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;
} 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 */
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;
}
/* 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;
}
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 */
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");
if (!R2CALL(ftdmchan)->ftdm_started) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
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)
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 = {
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;
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);
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;
-
- 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
- }
- }
-
- /* 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);
- }
+ /* 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);
- if (ftdm_r2_state_advance(ftdmchan)) {
- ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
- ftdm_mutex_unlock(ftdmchan->mutex);
- continue;
+ 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;
}
+ }
- 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++) {
* Moises Silva <moy@sangoma.com>
* David Yat Sin <davidy@sangoma.com>
* Nenad Corbic <ncorbic@sangoma.com>
+ * Arnaldo Pereira <arnaldo@sangoma.com>
*
*/
/* 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
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;
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;
#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)
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 ;
#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
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 */
};
*/
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
*