diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index a6007272e3..246ebc07ba 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -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; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 30de78857a..7c5f4a46af 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -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++) { diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index c13455dd21..ae46852300 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -35,6 +35,7 @@ * Moises Silva * David Yat Sin * Nenad Corbic + * Arnaldo Pereira * */ @@ -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; diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 87da5d1dd0..f862ae184b 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -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 */ }; diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 06f899c8c9..7d3ee68176 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -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 *