freetdm: ftdm_channel_read_event() to retrieve events from a channel, removed from ftmod_r2: ftdm_r2_sig_read(), FTDM_R2_PROCESSING flag and locks for ftdmchan

This commit is contained in:
Arnaldo Pereira 2010-11-24 21:25:24 -02:00
parent 5eb172d9f3
commit c842466a68
5 changed files with 311 additions and 84 deletions

View File

@ -988,6 +988,51 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t *
return status;
}
FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event)
{
ftdm_status_t status = FTDM_FAIL;
ftdm_sigmsg_t sigmsg;
ftdm_span_t *span = ftdmchan->span;
ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n");
if (!span->fio->channel_next_event) {
ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!", span->fio->name);
return FTDM_NOTIMPL;
}
status = span->fio->channel_next_event(ftdmchan, event);
if (status != FTDM_SUCCESS) {
return status;
}
/* before returning the event to the user we do some core operations with certain OOB events */
memset(&sigmsg, 0, sizeof(sigmsg));
sigmsg.span_id = span->span_id;
sigmsg.chan_id = (*event)->channel->chan_id;
sigmsg.channel = (*event)->channel;
switch ((*event)->enum_id) {
case FTDM_OOB_ALARM_CLEAR:
{
sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
ftdm_span_send_signal(span, &sigmsg);
}
break;
case FTDM_OOB_ALARM_TRAP:
{
sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
ftdm_span_send_signal(span, &sigmsg);
}
break;
default:
/* NOOP */
break;
}
return status;
}
static ftdm_status_t ftdmchan_fsk_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data)
{
ftdm_channel_t *ftdmchan = (ftdm_channel_t *) user_data;

View File

@ -57,8 +57,7 @@ typedef enum {
} ftdm_r2_flag_t;
typedef enum {
FTDM_R2_PROCESSING = (1 << 0),
FTDM_R2_WAITING_ACK = (1 << 1),
FTDM_R2_WAITING_ACK = (1 << 0),
} ftdm_r2_call_flag_t;
/* private call information stored in ftdmchan->call_data void* ptr */
@ -398,44 +397,26 @@ static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
return FTDM_SUCCESS;
}
static ftdm_status_t ftdm_r2_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size)
{
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
if (!openr2_chan_get_read_enabled(r2chan)) {
ftdm_mutex_lock(ftdmchan->mutex);
//openr2_chan_process_input(r2chan, data, size);
ftdm_mutex_unlock(ftdmchan->mutex);
}
return FTDM_SUCCESS;
}
/* always called from the monitor thread */
static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
{
//ftdm_status_t status;
ftdm_r2_call_t *r2call;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
//ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n");
ftdm_mutex_lock(ftdmchan->mutex);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot handle request to start call in state %s\n", ftdm_channel_state2str(ftdmchan->state));
ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open channel during incoming call! [%s]\n", ftdmchan->last_error);
ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
@ -448,7 +429,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
/* clean the call data structure but keep the R2 processing flag on! */
ft_r2_clean_call(ftdmchan->call_data);
r2call = R2CALL(ftdmchan);
ftdm_set_flag(r2call, FTDM_R2_PROCESSING);
if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
@ -457,7 +437,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
}
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
ftdm_mutex_unlock(ftdmchan->mutex);
}
/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
@ -574,11 +553,8 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
ftdm_r2_data_t *r2data;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_mutex_lock(ftdmchan->mutex);
if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Got protocol error when we're already down!\n");
ftdm_mutex_unlock(ftdmchan->mutex);
}
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n");
@ -587,7 +563,6 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
if (!R2CALL(ftdmchan)->ftdm_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
@ -602,8 +577,6 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err
r2data = ftdmchan->span->signal_data;
ftdm_span_send_signal(ftdmchan->span, &sigev);
ftdm_mutex_unlock(ftdmchan->mutex);
}
static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
@ -867,9 +840,37 @@ static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
{
*event = 0;
ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O get oob event)!!\n");
return 0;
ftdm_status_t status;
ftdm_event_t *fevent = NULL;
ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
*event = OR2_OOB_EVENT_NONE;
status = ftdm_channel_read_event(ftdmchan, &fevent);
if (status != FTDM_SUCCESS) {
//ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n");
return -1;
}
if (fevent->e_type != FTDM_EVENT_OOB)
return 0;
switch (fevent->enum_id) {
case FTDM_OOB_CAS_BITS_CHANGE:
{
*event = OR2_OOB_EVENT_CAS_CHANGE;
}
break;
case FTDM_OOB_ALARM_TRAP:
{
*event = OR2_OOB_EVENT_ALARM_ON;
}
break;
case FTDM_OOB_ALARM_CLEAR:
{
*event = OR2_OOB_EVENT_ALARM_OFF;
}
break;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "returning event: %s\n", ftdm_signal_event2str(*event));
return 0;
}
static openr2_io_interface_t ftdm_r2_io_iface = {
@ -1137,7 +1138,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
span->start = ftdm_r2_start;
span->stop = ftdm_r2_stop;
span->sig_read = ftdm_r2_sig_read;
span->sig_read = NULL;
span->signal_cb = sig_cb;
span->signal_type = FTDM_SIGTYPE_R2;
@ -1350,6 +1351,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
int ms;
struct timeval start, end;
short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count);
ftdm_event_t *event = NULL;
#ifdef __linux__
r2data->monitor_thread_id = syscall(SYS_gettid);
@ -1401,63 +1403,44 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
continue;
}
if (FTDM_SUCCESS == status) {
ftdm_event_t *event;
while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
if (event->enum_id == FTDM_OOB_CAS_BITS_CHANGE) {
r2call = R2CALL(event->channel);
r2chan = r2call->r2chan;
/* XXX
* when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span.
* is it possible to know on which channels those events are pending, without traversing the span?
* XXX */
for (i = 1; i <= span->chan_count; i++) {
r2chan = R2CALL(span->channels[i])->r2chan;
r2call = R2CALL(ftdmchan);
ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
// we only expect CAS and other OOB events on this thread/loop, once a call is started
// the MF events (in-band signaling) are handled in the call thread
openr2_chan_process_cas_signaling(r2chan);
} else {
ftdm_log(FTDM_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
// XXX TODO: handle alarms here XXX
status = ftdm_channel_read_event(ftdmchan, &event);
ftdm_mutex_lock(ftdmchan->mutex);
if (status == FTDM_SUCCESS) {
switch (event->enum_id) {
case FTDM_OOB_CAS_BITS_CHANGE:
{
ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", i);
openr2_chan_process_cas_signaling(r2chan);
}
break;
case FTDM_OOB_ALARM_TRAP:
case FTDM_OOB_ALARM_CLEAR:
{
ftdm_log(FTDM_LOG_DEBUG, "OOB EVENT: %s\n", ftdm_signal_event2str(event->enum_id));
openr2_chan_process_oob_events(r2chan);
}
break;
}
}
/* XXX
* when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span.
* is it possible to know on which channels those events are pending, without traversing the span?
* XXX */
for (i = 1; i <= span->chan_count; i++) {
r2chan = R2CALL(span->channels[i])->r2chan;
ftdmchan = openr2_chan_get_client_data(r2chan);
r2call = R2CALL(ftdmchan);
ftdm_mutex_lock(ftdmchan->mutex);
ftdm_set_flag(r2call, FTDM_R2_PROCESSING);
if (ftdm_r2_state_advance(ftdmchan)) {
ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
ftdm_mutex_unlock(ftdmchan->mutex);
continue;
}
/* handle timeout events first if any */
openr2_chan_run_schedule(r2chan);
/* process mf tones, if any */
if (openr2_chan_get_read_enabled(r2chan)) {
openr2_chan_process_mf_signaling(r2chan);
}
if (ftdm_r2_state_advance(ftdmchan)) {
ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
ftdm_mutex_unlock(ftdmchan->mutex);
continue;
}
ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
if (!ftdm_r2_state_advance(ftdmchan)) {
ftdm_mutex_unlock(ftdmchan->mutex);
}
openr2_chan_process_signaling(r2chan);
if (!ftdm_r2_state_advance(ftdmchan)) {
ftdm_mutex_unlock(ftdmchan->mutex);
}
} else if (status != FTDM_TIMEOUT) {
ftdm_log(FTDM_LOG_ERROR, "ftdm_span_poll_event returned %d.\n", status);
}
ftdm_span_trigger_signals(span);
ftdm_sleep(20);
}
for (i = 1; i <= span->chan_count; i++) {

View File

@ -35,6 +35,7 @@
* Moises Silva <moy@sangoma.com>
* David Yat Sin <davidy@sangoma.com>
* Nenad Corbic <ncorbic@sangoma.com>
* Arnaldo Pereira <arnaldo@sangoma.com>
*
*/
@ -99,7 +100,8 @@ static struct {
/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event);
FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event);
/**
* \brief Poll for event on a wanpipe socket
@ -1110,13 +1112,188 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a wanpipe channel
* \param channel Channel to retrieve event from
* \param event FreeTDM event to return
* \return Success or failure
*/
FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
{
ftdm_status_t status;
ftdm_oob_event_t event_id;
wanpipe_tdm_api_t tdm_api;
ftdm_span_t *span = ftdmchan->span;
if (ftdmchan->last_event_time && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - ftdmchan->last_event_time);
/* XX printf("%u %u %u\n", diff, (unsigned)ftdm_current_time_in_ms(), (unsigned)ftdmchan->last_event_time); */
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
if (diff > wp_globals.wink_ms) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
event_id = FTDM_OOB_OFFHOOK;
goto event;
}
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
if (diff > wp_globals.flash_ms) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
event_id = FTDM_OOB_ONHOOK;
if (ftdmchan->type == FTDM_CHAN_TYPE_FXO) {
wanpipe_tdm_api_t tdm_api;
memset(&tdm_api, 0, sizeof(tdm_api));
sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
}
goto event;
}
}
}
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT))
return FTDM_FAIL;
memset(&tdm_api, 0, sizeof(tdm_api));
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
if (status != FTDM_SUCCESS) {
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno));
return FTDM_FAIL;
}
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
case WP_TDMAPI_EVENT_LINK_STATUS:
{
switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
event_id = FTDM_OOB_ALARM_CLEAR;
break;
default:
event_id = FTDM_OOB_ALARM_TRAP;
break;
};
}
break;
case WP_TDMAPI_EVENT_RXHOOK:
{
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) {
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
if (event_id == FTDM_OOB_OFFHOOK) {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
event_id = FTDM_OOB_FLASH;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
}
} else {
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
event_id = FTDM_OOB_WINK;
goto event;
} else {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
}
}
break;
} else {
wanpipe_tdm_api_t onhook_tdm_api;
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api);
if (status) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
return FTDM_FAIL;
}
event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
}
}
break;
case WP_TDMAPI_EVENT_RING_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
}
break;
/*
disabled this ones when configuring, we don't need them, do we?
case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
{
event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
}
break;
*/
case WP_TDMAPI_EVENT_RBS:
{
event_id = FTDM_OOB_CAS_BITS_CHANGE;
ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
}
break;
case WP_TDMAPI_EVENT_DTMF:
{
char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
event_id = FTDM_OOB_NOOP;
if (tmp_dtmf[0] == 'f') {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
break;
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
}
if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
}
}
}
break;
case WP_TDMAPI_EVENT_ALARM:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
event_id = FTDM_OOB_ALARM_TRAP;
}
break;
default:
{
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
event_id = FTDM_OOB_INVALID;
}
break;
}
event:
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
ftdmchan->last_event_time = 0;
span->event_header.e_type = FTDM_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = ftdmchan;
*event = &span->event_header;
return FTDM_SUCCESS;
}
/**
* \brief Retrieves an event from a wanpipe span
* \param span Span to retrieve event from
* \param event FreeTDM event to return
* \return Success or failure
*/
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
{
uint32_t i,err;
ftdm_oob_event_t event_id;
@ -1348,7 +1525,8 @@ static FIO_IO_LOAD_FUNCTION(wanpipe_init)
wanpipe_interface.read = wanpipe_read;
wanpipe_interface.write = wanpipe_write;
wanpipe_interface.poll_event = wanpipe_poll_event;
wanpipe_interface.next_event = wanpipe_next_event;
wanpipe_interface.next_event = wanpipe_span_next_event;
wanpipe_interface.channel_next_event = wanpipe_channel_next_event;
wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
wanpipe_interface.get_alarms = wanpipe_get_alarms;
*fio = &wanpipe_interface;

View File

@ -467,6 +467,7 @@ struct ftdm_memory_handler {
#define FIO_SPAN_GET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
#define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms, short *poll_events)
#define FIO_SPAN_NEXT_EVENT_ARGS (ftdm_span_t *span, ftdm_event_t **event)
#define FIO_CHANNEL_NEXT_EVENT_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t **event)
#define FIO_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg)
#define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event)
#define FIO_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, const char *str, ftdm_chan_type_t type, char *name, char *number)
@ -498,6 +499,7 @@ typedef ftdm_status_t (*fio_span_set_sig_status_t) FIO_SPAN_SET_SIG_STATUS_ARGS;
typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS;
typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ;
typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ;
typedef ftdm_status_t (*fio_channel_next_event_t) FIO_CHANNEL_NEXT_EVENT_ARGS ;
typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ;
typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ;
typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ;
@ -530,6 +532,7 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ;
#define FIO_SPAN_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_GET_SIG_STATUS_ARGS
#define FIO_SPAN_POLL_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_POLL_EVENT_ARGS
#define FIO_SPAN_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_NEXT_EVENT_ARGS
#define FIO_CHANNEL_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_NEXT_EVENT_ARGS
#define FIO_SIGNAL_CB_FUNCTION(name) ftdm_status_t name FIO_SIGNAL_CB_ARGS
#define FIO_EVENT_CB_FUNCTION(name) ftdm_status_t name FIO_EVENT_CB_ARGS
#define FIO_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_ARGS
@ -568,6 +571,7 @@ struct ftdm_io_interface {
fio_write_t write; /*!< Write data to the channel */
fio_span_poll_event_t poll_event; /*!< Poll for events on the whole span */
fio_span_next_event_t next_event; /*!< Retrieve an event from the span */
fio_channel_next_event_t channel_next_event; /*!< Retrieve an event from channel */
fio_api_t api; /*!< Execute a text command */
};

View File

@ -615,6 +615,23 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan);
*/
FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event);
/*!
* \brief Retrieves an event from the span
*
* \note
* This function is non-reentrant and not thread-safe.
* The event returned may be modified if the function is called again
* from a different thread or even the same. It is recommended to
* handle events from the same span in a single thread.
*
* \param span The channel to retrieve the event from
* \param event Pointer to store the pointer to the event
*
* \retval FTDM_SUCCESS success (at least one event available)
* \retval FTDM_FAIL failure
*/
FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event);
/*!
* \brief Enqueue a DTMF string into the channel
*