From 7256232af27e737a44f1dc1c3ba677ddcdbc0cd6 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Tue, 25 May 2010 12:48:10 -0400 Subject: [PATCH] freetdm: add call waiting disable/enable feature --- libs/freetdm/mod_freetdm/mod_freetdm.c | 9 ++-- libs/freetdm/src/ftdm_io.c | 8 ++-- .../src/ftmod/ftmod_analog/ftmod_analog.c | 48 ++++++++++++------- libs/freetdm/src/include/freetdm.h | 3 +- libs/freetdm/src/include/private/ftdm_core.h | 2 + libs/freetdm/src/include/private/ftdm_types.h | 14 +++--- 6 files changed, 54 insertions(+), 30 deletions(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 85944f60ad..baf0677753 100644 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2294,6 +2294,7 @@ static switch_status_t load_config(void) char *hold_music = NULL; char *fail_dial_regex = NULL; const char *enable_callerid = "true"; + int callwaiting = 1; uint32_t span_id = 0, to = 0, max = 0; ftdm_span_t *span = NULL; @@ -2303,6 +2304,7 @@ static switch_status_t load_config(void) char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "analog_spans var = %s\n", var); if (!strcasecmp(var, "tonegroup")) { tonegroup = val; } else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) { @@ -2323,6 +2325,8 @@ static switch_status_t load_config(void) max_digits = val; } else if (!strcasecmp(var, "hotline")) { hotline = val; + } else if (!strcasecmp(var, "callwaiting")) { + callwaiting = switch_true(val) ? 1 : 0; } else if (!strcasecmp(var, "enable-analog-option")) { analog_options = enable_analog_option(val, analog_options); } @@ -2332,8 +2336,6 @@ static switch_status_t load_config(void) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n"); continue; } - - if (!tonegroup) { tonegroup = "us"; @@ -2373,8 +2375,9 @@ static switch_status_t load_config(void) "tonemap", tonegroup, "digit_timeout", &to, "max_dialstr", &max, - "hotline", hotline, + "hotline", hotline ? hotline : "", "enable_callerid", enable_callerid, + "callwaiting", &callwaiting, FTDM_TAG_END) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM analog span %s\n", ftdm_span_get_name(span)); continue; diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 910b260646..5371946993 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1677,8 +1677,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, status = FTDM_FAIL; - if (ftdm_test_flag(check, FTDM_CHANNEL_READY) && (!ftdm_test_flag(check, FTDM_CHANNEL_INUSE) || - (check->type == FTDM_CHAN_TYPE_FXS && check->token_count == 1))) { + /* the channel is only allowed to be open if not in use, or, for FXS devices with a call with call waiting enabled */ + if ((!ftdm_test_flag(check, FTDM_CHANNEL_INUSE)) + || ((check->type == FTDM_CHAN_TYPE_FXS && check->token_count == 1) && (ftdm_channel_test_feature(check, FTDM_CHANNEL_FEATURE_CALLWAITING)))) + { if (!ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { status = check->fio->open(check); if (status == FTDM_SUCCESS) { @@ -1692,7 +1694,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, } ftdm_mutex_unlock(check->mutex); - done: +done: ftdm_mutex_unlock(globals.mutex); return status; diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c index dd54a88d72..b3af374725 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c @@ -161,6 +161,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) const char *var, *val; int *intval; uint32_t flags = FTDM_ANALOG_CALLERID; + int callwaiting = 1; + int i = 0; assert(sig_cb != NULL); ftdm_log(FTDM_LOG_DEBUG, "Configuring span %s for analog signaling ...\n", span->name); @@ -172,10 +174,13 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) } analog_data = ftdm_malloc(sizeof(*analog_data)); - assert(analog_data != NULL); + + ftdm_assert_return(analog_data != NULL, FTDM_FAIL, "malloc failure\n"); + memset(analog_data, 0, sizeof(*analog_data)); while ((var = va_arg(ap, char *))) { + ftdm_log(FTDM_LOG_DEBUG, "Analog config var = %s\n", var); if (!strcasecmp(var, "tonemap")) { if (!(val = va_arg(ap, char *))) { break; @@ -196,6 +201,11 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) } else { flags &= ~FTDM_ANALOG_CALLERID; } + } else if (!strcasecmp(var, "callwaiting")) { + if (!(intval = va_arg(ap, int *))) { + break; + } + callwaiting = *intval; } else if (!strcasecmp(var, "max_dialstr")) { if (!(intval = va_arg(ap, int *))) { break; @@ -219,6 +229,12 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span) if ((max_dialstr < 1 && !strlen(hotline)) || max_dialstr > MAX_DTMF) { max_dialstr = MAX_DTMF; } + + if (callwaiting) { + for (i = 1; i <= span->chan_count; i++) { + ftdm_channel_set_feature(span->channels[i], FTDM_CHANNEL_FEATURE_CALLWAITING); + } + } span->start = ftdm_analog_start; span->stop = ftdm_analog_stop; @@ -329,24 +345,24 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) ftdm_sigmsg_t sig; ftdm_status_t status; - ftdm_log(FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n"); ts.buffer = NULL; if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error); goto done; } if (ftdm_buffer_create(&dt_buffer, 1024, 3192, 0) != FTDM_SUCCESS) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "memory error!"); - ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "MEM ERROR\n"); goto done; } if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) { snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "error initilizing tone detector!"); - ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "TONE ERROR\n"); goto done; } @@ -500,7 +516,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) indicate = 0; state_counter = 0; - ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state)); switch(ftdmchan->state) { @@ -515,7 +531,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } if (ftdmchan->fsk_buffer && ftdm_buffer_inuse(ftdmchan->fsk_buffer)) { - ftdm_log(FTDM_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancel FSK transmit due to early answer.\n"); ftdm_buffer_zero(ftdmchan->fsk_buffer); } @@ -676,7 +692,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) { - ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE); last_digit = 0; collecting = 0; @@ -691,7 +707,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) } if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_WARNING, "read error [%s]\n", ftdmchan->last_error); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "read error [%s]\n", ftdmchan->last_error); continue; } @@ -706,7 +722,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) for (i = 1; i < FTDM_TONEMAP_INVALID; i++) { if (ftdmchan->detected_tones[i]) { - ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id); sig.raw_data = &i; ftdm_span_send_signal(ftdmchan->span, &sig); } @@ -718,15 +734,15 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] || ftdmchan->detected_tones[FTDM_TONEMAP_ATTN] ) { - ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failure indication detected!\n"); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else if (ftdmchan->detected_tones[FTDM_TONEMAP_DIAL]) { if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) { - ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "No Digits to send!\n"); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error); ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { state_counter = 0; @@ -815,7 +831,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) ftdm_set_state_locked(closed_chan, FTDM_CHANNEL_STATE_DOWN); } - ftdm_log(FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id); + ftdm_log_chan(closed_chan, FTDM_LOG_DEBUG, "ANALOG CHANNEL %d:%d thread ended.\n", closed_chan->span_id, closed_chan->chan_id); ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD); return NULL; @@ -839,7 +855,7 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e sig.channel = event->channel; - ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", + ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state)); ftdm_mutex_lock(event->channel->mutex); @@ -849,7 +865,7 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e case FTDM_OOB_RING_START: { if (event->channel->type != FTDM_CHAN_TYPE_FXO) { - ftdm_log(FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n"); + ftdm_log_chan_msg(event->channel, FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n"); ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); goto end; } diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index d0358265ba..beefd8d06e 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -440,7 +440,6 @@ struct ftdm_memory_handler { ftdm_free_func_t free; }; - /*! \brief FreeTDM I/O layer interface argument macros * You don't need these unless your implementing an I/O interface module (most users don't) */ #define FIO_CHANNEL_REQUEST_ARGS (ftdm_span_t *span, uint32_t chan_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan) @@ -985,7 +984,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan); /*! - * \brief Execute a command in a channel + * \brief Execute a command in a channel (same semantics as the ioctl() unix system call) * * \param ftdmchan The channel to execute the command * \param command The command to execute diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 93f197f0ed..86a35ccea6 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -561,6 +561,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); #define ftdm_channel_lock(chan) ftdm_mutex_lock(chan->mutex) #define ftdm_channel_unlock(chan) ftdm_mutex_unlock(chan->mutex) +#define ftdm_log_chan(fchan, level, format, ...) ftdm_log(level, "%d:%d " format, fchan->span_id, fchan->chan_id, __VA_ARGS__) +#define ftdm_log_chan_msg(fchan, level, msg) ftdm_log(level, "%d:%d " msg, fchan->span_id, fchan->chan_id) static __inline__ void ftdm_abort(void) { diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index 50f3280d61..6f77859f6c 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -158,13 +158,15 @@ typedef enum { FTDM_SPAN_SUGGEST_CHAN_ID = (1 << 7), } ftdm_span_flag_t; +/*! \brief Channel supported features */ typedef enum { - FTDM_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0), - FTDM_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1), - FTDM_CHANNEL_FEATURE_CODECS = (1 << 2), - FTDM_CHANNEL_FEATURE_INTERVAL = (1 << 3), - FTDM_CHANNEL_FEATURE_CALLERID = (1 << 4), - FTDM_CHANNEL_FEATURE_PROGRESS = (1 << 5) + FTDM_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0), /*!< Channel can detect DTMF (read-only) */ + FTDM_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1), /*!< Channel can generate DTMF (read-only) */ + FTDM_CHANNEL_FEATURE_CODECS = (1 << 2), /*!< Channel can do transcoding (read-only) */ + FTDM_CHANNEL_FEATURE_INTERVAL = (1 << 3), /*!< Channel support i/o interval configuration (read-only) */ + FTDM_CHANNEL_FEATURE_CALLERID = (1 << 4), /*!< Channel can detect caller id (read-only) */ + FTDM_CHANNEL_FEATURE_PROGRESS = (1 << 5), /*!< Channel can detect inband progress (read-only) */ + FTDM_CHANNEL_FEATURE_CALLWAITING = (1 << 6), /*!< Channel will allow call waiting (ie: FXS devices) (read/write) */ } ftdm_channel_feature_t; typedef enum {