diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index 5150890ec6..7271d3be1a 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -476,7 +476,7 @@ static ftdm_state_map_t isdn_state_map = { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, - {FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_RING, FTDM_END} + {FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_END} }, { ZSD_INBOUND, @@ -484,6 +484,12 @@ static ftdm_state_map_t isdn_state_map = { {FTDM_CHANNEL_STATE_DIALTONE, FTDM_END}, {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_COLLECT, FTDM_END}, + {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + }, { ZSD_INBOUND, ZSM_UNACCEPTABLE, @@ -656,6 +662,29 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan) } break; + case FTDM_CHANNEL_STATE_COLLECT: /* Overlap receive */ + { + if (!ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) { + if (!call) { + ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "No call handle\n"); + ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART); + } + else if (pri_need_more_info(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0)) { + ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan); + + ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "Failed to send INFORMATION request\n"); + + /* hangup call */ + caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER; + ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP); + } + } else { + ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "Overlap receiving on outbound call?\n"); + ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART); + } + } + break; + case FTDM_CHANNEL_STATE_RING: { /* @@ -837,11 +866,45 @@ static __inline__ void check_state(ftdm_span_t *span) */ static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent) { - ftdm_log(FTDM_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum); + ftdm_span_t *span = spri->span; + ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ring.channel); + ftdm_caller_data_t *caller_data = NULL; - if (strlen(pevent->ring.callednum) > 3) { - ftdm_log(FTDM_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum); - pri_answer(spri->pri, pevent->ring.call, 0, 1); + if (!chan) { + ftdm_log(FTDM_LOG_CRIT, "-- Info on channel %d:%d %s but it's not in use?\n", ftdm_span_get_id(span), pevent->ring.channel); + return 0; + } + + caller_data = ftdm_channel_get_caller_data(chan); + + switch (ftdm_channel_get_state(chan)) { + case FTDM_CHANNEL_STATE_COLLECT: /* TE-mode overlap receiving */ + ftdm_log_chan(chan, FTDM_LOG_DEBUG, "-- Incoming INFORMATION indication, current called number: '%s', number complete: %s\n", + pevent->ring.callednum, pevent->ring.complete ? "yes" : "no"); + + if (pevent->ring.complete) { + ftdm_log_chan_msg(chan, FTDM_LOG_DEBUG, "Number complete indicated, moving channel to RING state\n"); + /* copy final value */ + ftdm_set_string(caller_data->dnis.digits, (char *)pevent->ring.callednum); + /* notify switch */ + ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING); + } + break; + case FTDM_CHANNEL_STATE_DIALTONE: /* NT-mode overlap receiving */ + ftdm_log_chan(chan, FTDM_LOG_DEBUG, "-- Incoming INFORMATION indication, current called number: '%s'\n", + pevent->ring.callednum); + + /* Need to add proper support for overlap receiving in NT-mode (requires FreeSWITCH + FreeTDM core support) */ + if (strlen(pevent->ring.callednum) > 3) { + ftdm_log(FTDM_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum); + pri_answer(spri->pri, pevent->ring.call, 0, 1); + } + break; + default: + ftdm_log_chan(chan, FTDM_LOG_ERROR, "-- INFORMATION indication on channel %d:%d in invalid state '%s'\n", + ftdm_channel_get_span_id(chan), + ftdm_channel_get_id(chan), + ftdm_channel_get_state_str(chan)); } return 0; } @@ -878,7 +941,15 @@ static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_even pri_hangup(spri->pri, pevent->hangup.call, pevent->hangup.cause); chan->caller_data.hangup_cause = pevent->hangup.cause; - ftdm_set_state(chan, FTDM_CHANNEL_STATE_TERMINATING); + + switch (ftdm_channel_get_state(chan)) { + case FTDM_CHANNEL_STATE_DIALTONE: + case FTDM_CHANNEL_STATE_COLLECT: + ftdm_set_state(chan, FTDM_CHANNEL_STATE_HANGUP); + break; + default: + ftdm_set_state(chan, FTDM_CHANNEL_STATE_TERMINATING); + } break; case LPWRAP_PRI_EVENT_HANGUP_ACK: /* */ @@ -1112,6 +1183,7 @@ out: static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent) { ftdm_span_t *span = spri->span; + ftdm_libpri_data_t *isdn_data = span->signal_data; ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ring.channel); ftdm_caller_data_t *caller_data = NULL; int ret = 0; @@ -1187,8 +1259,14 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event /* hurr, this is valid as along as nobody releases the call */ chan->call_data = pevent->ring.call; - ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING); - + /* only go to RING state if we have the complete called number (indicated via pevent->complete flag) */ + if (!pevent->ring.complete && (isdn_data->overlap & FTMOD_LIBPRI_OVERLAP_RECEIVE)) { + ftdm_log(FTDM_LOG_DEBUG, "RING event without complete indicator, waiting for more digits\n"); + ftdm_set_state(chan, FTDM_CHANNEL_STATE_COLLECT); + } else { + ftdm_log(FTDM_LOG_DEBUG, "RING event with complete indicator (or overlap receive disabled)\n"); + ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING); + } done: ftdm_channel_unlock(chan); return ret; @@ -1878,6 +1956,25 @@ static int parse_ton(const char *ton) return PRI_UNKNOWN; } +/** + * \brief Parse overlap string to value + * \param val String to parse + * \return Overlap flags + */ +static int parse_overlap_dial(const char *val) +{ + if (!strcasecmp(val, "yes") || !strcasecmp(val, "both")) + return FTMOD_LIBPRI_OVERLAP_BOTH; + if (!strcasecmp(val, "incoming") || !strcasecmp(val, "receive")) + return FTMOD_LIBPRI_OVERLAP_RECEIVE; + if (!strcasecmp(val, "outgoing") || !strcasecmp(val, "send")) + return FTMOD_LIBPRI_OVERLAP_SEND; + if (!strcasecmp(val, "no")) + return FTMOD_LIBPRI_OVERLAP_NONE; + + return -1; +} + /** * \brief Parses an option string to flags * \param in String to parse for configuration options @@ -2034,6 +2131,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span) else if (!strcasecmp(var, "l1") || !strcasecmp(var, "layer1")) { isdn_data->layer1 = parse_layer1(val); } + else if (!strcasecmp(var, "overlapdial")) { + if ((isdn_data->overlap = parse_overlap_dial(val)) == -1) { + ftdm_log(FTDM_LOG_ERROR, "Invalid overlap flag, ignoring parameter\n"); + isdn_data->overlap = FTMOD_LIBPRI_OVERLAP_NONE; + } + } else if (!strcasecmp(var, "debug")) { if (parse_debug(val, &isdn_data->debug_mask) == -1) { ftdm_log(FTDM_LOG_ERROR, "Invalid debug flag, ignoring parameter\n"); diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h index 3f47cd2888..4ec15c7b69 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.h @@ -51,6 +51,12 @@ typedef enum { FTMOD_LIBPRI_RUNNING = (1 << 0) } ftdm_isdn_flag_t; +typedef enum { + FTMOD_LIBPRI_OVERLAP_NONE = 0, + FTMOD_LIBPRI_OVERLAP_RECEIVE = (1 << 0), + FTMOD_LIBPRI_OVERLAP_SEND = (1 << 1) +#define FTMOD_LIBPRI_OVERLAP_BOTH (FTMOD_LIBPRI_OVERLAP_RECEIVE | FTMOD_LIBPRI_OVERLAP_SEND) +} ftdm_isdn_overlap_t; struct ftdm_libpri_data { ftdm_channel_t *dchan; @@ -60,6 +66,7 @@ struct ftdm_libpri_data { int mode; int dialect; + int overlap; /*!< Overlap dial flags */ unsigned int layer1; unsigned int ton;