tech_pvt = switch_core_session_get_private(session);
assert(tech_pvt != NULL);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+ assert(tech_pvt->ftdmchan != NULL);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
+
+ ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED);
return SWITCH_STATUS_SUCCESS;
}
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_RINGING:
{
- ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROGRESS);
+ ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_RINGING);
}
break;
case SWITCH_MESSAGE_INDICATE_PROGRESS:
!switch_channel_test_flag(channel, CF_EARLY_MEDIA) &&
!switch_channel_test_flag(channel, CF_RING_READY)
) {
- ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_RING);
+ ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_RINGING);
switch_channel_mark_ring_ready(channel);
}
break;
spanid, chanid, (uuid) ? uuid : "N/A");
}
}
- break;
+ break;
case FTDM_SIGEVENT_SIGSTATUS_CHANGED:
{
ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->sigstatus;
spanid, chanid, ftdm_signaling_status2str(sigstatus));
}
break;
+ case FTDM_SIGEVENT_PROCEED:
+ case FTDM_SIGEVENT_MSG:
+ /* FS does not have handlers for these messages, so ignore them for now */
+ break;
default:
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
goto done;
}
-
if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
}
switch (indication) {
/* FIXME: ring and busy cannot be used with all signaling stacks
* (particularly isdn stacks I think, we should emulate or just move to hangup with busy cause) */
- case FTDM_CHANNEL_INDICATE_RING:
- ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RING, 1);
+ case FTDM_CHANNEL_INDICATE_RINGING:
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RINGING, 1);
break;
-
case FTDM_CHANNEL_INDICATE_BUSY:
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_BUSY, 1);
break;
-
+ case FTDM_CHANNEL_INDICATE_PROCEED:
+ if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_PROCEED_STATE)) {
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_RING) {
+ ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROCEED, 1);
+ }
+ }
+ break;
case FTDM_CHANNEL_INDICATE_PROGRESS:
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
}
break;
-
case FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA:
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS);
ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
}
break;
-
default:
ftdm_log(file, func, line, FTDM_LOG_LEVEL_WARNING, "Do not know how to indicate %d\n", indication);
status = FTDM_FAIL;
{
if (state_counter > 5000 || !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT)) {
ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_CALLERID_DETECT, NULL);
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
}
}
break;
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
- (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
- || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
+ (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
+ || ftdmchan->last_state >= FTDM_CHANNEL_STATE_RING)) {
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
} else {
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
}
}
case FTDM_CHANNEL_STATE_UP:
- case FTDM_CHANNEL_STATE_IDLE:
+ case FTDM_CHANNEL_STATE_RING:
{
ftdm_sleep(interval);
continue;
ftdm_channel_use(ftdmchan);
}
break;
- case FTDM_CHANNEL_STATE_IDLE:
+ case FTDM_CHANNEL_STATE_RING:
{
ftdm_channel_use(ftdmchan);
sig.event_id = FTDM_SIGEVENT_START;
continue;
}
break;
- case FTDM_CHANNEL_STATE_RING:
+ case FTDM_CHANNEL_STATE_RINGING:
{
ftdm_buffer_zero(dt_buffer);
teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) >= analog_data->max_dialstr))) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
last_digit = 0;
collecting = 0;
}
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
} else {
- ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_IDLE);
+ ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING);
}
event->channel->ring_count = 1;
ftdm_mutex_unlock(event->channel->mutex);
ZSD_INBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_RING, FTDM_END},
- {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RINGING, FTDM_END},
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
},
{
ZSD_INBOUND,
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
{FTDM_CHANNEL_STATE_DIALING, FTDM_END},
- {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS,
- FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
+ FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
+ FTDM_CHANNEL_STATE_DOWN, FTDM_END}
},
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
+ FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
{
ZSD_OUTBOUND,
ZSM_UNACCEPTABLE,
break;
case FTDM_CHANNEL_STATE_GET_CALLERID:
{
- sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
- sngisdn_snd_proceed(ftdmchan);
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
+ sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
+ sngisdn_snd_proceed(ftdmchan);
+ }
/* Wait in this state until we get FACILITY msg */
}
break;
case FTDM_CHANNEL_STATE_RING: /* incoming call request */
- {
+ {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending incoming call from %s to %s to FTDM core\n", ftdmchan->caller_data.ani.digits, ftdmchan->caller_data.dnis.digits);
/* we have enough information to inform FTDM of the call*/
}
}
break;
+ case FTDM_CHANNEL_STATE_PROCEED:
+ {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
+ /*OUTBOUND...so we were told by the line of this so noifiy the user*/
+ sigev.event_id = FTDM_SIGEVENT_PROCEED;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+ } else {
+ if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
+ sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
+ sngisdn_snd_proceed(ftdmchan);
+ }
+ }
+ }
+ break;
+ case FTDM_CHANNEL_STATE_RINGING:
+ {
+ sngisdn_snd_alert(ftdmchan, SNGISDN_PROGIND_NETE_ISDN);
+ }
+ break;
case FTDM_CHANNEL_STATE_PROGRESS:
{
/*check if the channel is inbound or outbound*/
/*OUTBOUND...so we were told by the line of this so noifiy the user*/
sigev.event_id = FTDM_SIGEVENT_PROGRESS;
ftdm_span_send_signal(ftdmchan->span, &sigev);
- } else if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
- sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
- sngisdn_snd_proceed(ftdmchan);
+ } else {
+ /* If we already sent a PROCEED before, do not send a PROGRESS as there is nothing to indicate to the remote switch */
+ if (ftdmchan->last_state != FTDM_CHANNEL_STATE_PROCEED) {
+ /* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */
+ sngisdn_snd_progress(ftdmchan, SNGISDN_PROGIND_NETE_ISDN);
+ }
}
}
break;
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
ftdm_span_send_signal(ftdmchan->span, &sigev);
} else {
- sngisdn_snd_progress(ftdmchan);
+ /* Send a progress message, indicating: In-band information/pattern available */
+ sngisdn_snd_progress(ftdmchan, SNGISDN_PROGIND_IB_AVAIL);
}
}
break;
span->state_map = &sangoma_isdn_state_map;
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
+ ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
span->trunk_type == FTDM_TRUNK_BRI) {
FLAG_DELAYED_REL = (1 << 7),
FLAG_SENT_PROCEED = (1 << 8),
FLAG_SEND_DISC = (1 << 9),
- FLAG_ACTIVATING = (1 << 10), /* Used for BRI only, flag is set after we request line CONNECTED */
+ /* Used for BRI only, flag is set after we request line CONNECTED */
+ FLAG_ACTIVATING = (1 << 10),
} sngisdn_flag_t;
SNGISDN_EVENT_RST_IND,
} ftdm_sngisdn_event_id_t;
+typedef enum {
+ /* Call is not end-to-end ISDN */
+ SNGISDN_PROGIND_NETE_ISDN = 1,
+ /* Destination address is non-ISDN */
+ SNGISDN_PROGIND_DEST_NISDN,
+ /* Origination address is non-ISDN */
+ SNGISDN_PROGIND_ORIG_NISDN,
+ /* Call has returned to the ISDN */
+ SNGISDN_PROGIND_RET_ISDN,
+ /* Interworking as occured and has resulted in a telecommunication service change */
+ SNGISDN_PROGIND_SERV_CHANGE,
+ /* In-band information or an appropriate pattern is now available */
+ SNGISDN_PROGIND_IB_AVAIL,
+} ftdm_sngisdn_progind_t;
+
/* Only timers that can be cancelled are listed here */
#define SNGISDN_NUM_TIMERS 1
/* Increase NUM_TIMERS as number of ftdm_sngisdn_timer_t increases */
uint8_t trace_flags; /* TODO: change to flags, so we can use ftdm_test_flag etc.. */
uint8_t overlap_dial;
uint8_t setup_arb;
+ uint8_t facility_ie_decode;
uint8_t facility;
int8_t facility_timeout;
uint8_t num_local_numbers;
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan);
void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
-void sngisdn_snd_progress(ftdm_channel_t *ftdmchan);
-void sngisdn_snd_alert(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
+void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan);
void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare);
void sngisdn_snd_reset(ftdm_channel_t *ftdmchan);
void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan);
void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan);
void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan);
void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len);
ftdm_status_t cpy_called_num_from_stack(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPtyNmb);
ftdm_status_t cpy_redir_num_from_stack(ftdm_caller_data_t *ftdm, RedirNmb *redirNmb);
ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Display *display);
+ftdm_status_t cpy_facility_ie_from_stack(ftdm_caller_data_t *ftdm, uint8_t *data, uint32_t data_len);
+
ftdm_status_t cpy_calling_num_from_user(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm);
ftdm_status_t cpy_called_num_from_user(CdPtyNmb *cdPtyNmb, ftdm_caller_data_t *ftdm);
ftdm_status_t cpy_redir_num_from_user(RedirNmb *redirNmb, ftdm_caller_data_t *ftdm);
signal_data->min_digits = 8;
signal_data->overlap_dial = SNGISDN_OPT_DEFAULT;
signal_data->setup_arb = SNGISDN_OPT_DEFAULT;
+ signal_data->facility_ie_decode = SNGISDN_OPT_TRUE;
signal_data->timer_t3 = 8;
signal_data->link_id = span->span_id;
if (signal_data->facility_timeout < 0) {
signal_data->facility_timeout = 0;
}
+ } else if (!strcasecmp(var, "facility-ie-decode")) {
+ if (!strcasecmp(val, "yes")) {
+ signal_data->facility_ie_decode = SNGISDN_OPT_TRUE;
+ } else if (!strcasecmp(val, "no")) {
+ signal_data->facility_ie_decode = SNGISDN_OPT_FALSE;
+ } else {
+ ftdm_log(FTDM_LOG_ERROR, "Invalid value for parameter:%s:%s\n", var, val);
+ }
} else {
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var);
}
snprintf(ftdmchan->caller_data.aniII, 5, "%.2d", conEvnt->ni2OctStr.str.val[3]);
}
}
-
- if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) {
- /* Verify whether the Caller Name will come in a subsequent FACILITY message */
- uint16_t ret_val;
- char retrieved_str[255];
-
- ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
- /*
- return values for "sng_isdn_retrieve_facility_information_following":
- If there will be no information following, or fails to decode IE, returns -1
- If there will be no information following, but current FACILITY IE contains a caller name, returns 0
- If there will be information following, returns 1
- */
-
- if (ret_val == 1) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID);
- /* Launch timer in case we never get a FACILITY msg */
- if (signal_data->facility_timeout) {
- ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout,
- sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]);
+
+ if (conEvnt->facilityStr.eh.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ cpy_facility_ie_from_stack(&ftdmchan->caller_data, conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len);
+ } else if (signal_data->facility == SNGISDN_OPT_TRUE) {
+ /* Verify whether the Caller Name will come in a subsequent FACILITY message */
+ uint16_t ret_val;
+ char retrieved_str[255];
+
+ ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
+ /*
+ return values for "sng_isdn_retrieve_facility_information_following":
+ If there will be no information following, or fails to decode IE, returns -1
+ If there will be no information following, but current FACILITY IE contains a caller name, returns 0
+ If there will be information following, returns 1
+ */
+
+ if (ret_val == 1) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID);
+ /* Launch timer in case we never get a FACILITY msg */
+ if (signal_data->facility_timeout) {
+ ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout,
+ sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]);
+ }
+ break;
+ } else if (ret_val == 0) {
+ strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
}
- break;
- } else if (ret_val == 0) {
- strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
}
}
}
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
switch(ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_DIALING:
case MI_CALLPROC:
switch(ftdmchan->state) {
- case FTDM_CHANNEL_STATE_DIALING:
- if (evntType == MI_PROGRESS ||
+ case FTDM_CHANNEL_STATE_DIALING:
+ if (evntType == MI_CALLPROC) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED);
+ } else if (evntType == MI_PROGRESS ||
(cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL)) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
} else {
}
break;
case FTDM_CHANNEL_STATE_RING:
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_UP:
uint32_t spInstId = sngisdn_event->spInstId;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
DiscEvnt *discEvnt = &sngisdn_event->event.discEvnt;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId);
ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n");
- switch (ftdmchan->state) {
+ switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_RING:
case FTDM_CHANNEL_STATE_DIALING:
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
- case FTDM_CHANNEL_STATE_UP:
+ case FTDM_CHANNEL_STATE_UP:
+ if (discEvnt->facilityStr.eh.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ cpy_facility_ie_from_stack(&ftdmchan->caller_data, discEvnt->facilityStr.facilityStr.val, discEvnt->facilityStr.facilityStr.len);
+ } else {
+ /* Call libsng_isdn facility decode function and copy variables here */
+ }
+ }
if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val;
} else {
uint32_t spInstId = sngisdn_event->spInstId;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
RelEvnt *relEvnt = &sngisdn_event->event.relEvnt;
sngisdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN);
}
/* fall-through */
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_UP:
not changed while we were waiting for ftdmchan->mutex by comparing suInstId's */
if (((sngisdn_chan_data_t*)ftdmchan->call_data)->suInstId == suInstId ||
((sngisdn_chan_data_t*)ftdmchan->call_data)->spInstId == spInstId) {
+
+ if (relEvnt->facilityStr.eh.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ cpy_facility_ie_from_stack(&ftdmchan->caller_data, relEvnt->facilityStr.facilityStr.val, relEvnt->facilityStr.facilityStr.len);
+ } else {
+ /* Call libsng_isdn facility decode function and copy variables here */
+ }
+ }
+
if (relEvnt->causeDgn[0].eh.pres && relEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = relEvnt->causeDgn[0].causeVal.val;
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "cause:%d\n", ftdmchan->caller_data.hangup_cause);
switch (ftdmchan->state) {
case FTDM_CHANNEL_STATE_GET_CALLERID:
/* Update the caller ID Name */
+
if (facEvnt->facElmt.facStr.pres) {
char retrieved_str[255];
-
+
/* return values for "sng_isdn_retrieve_facility_information_following":
If there will be no information following, or fails to decode IE, returns -1
If there will be no information following, but current FACILITY IE contains a caller name, returns 0
If there will be information following, returns 1
*/
-
+
if (sng_isdn_retrieve_facility_caller_name(&facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len, retrieved_str) == 0) {
strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
} else {
/* We received the caller ID Name in FACILITY, but its too late, facility-timeout already occurred */
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "FACILITY received, but we already proceeded with call\n");
break;
+ case FTDM_CHANNEL_STATE_UP:
+ {
+ ftdm_sigmsg_t sigev;
+ if (facEvnt->facElmt.facStr.pres) {
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ cpy_facility_ie_from_stack(&ftdmchan->caller_data, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len);
+ } else {
+ /* Call libsng_isdn facility decode function and copy variables here */
+ }
+ }
+ memset(&sigev, 0, sizeof(sigev));
+ sigev.chan_id = ftdmchan->chan_id;
+ sigev.span_id = ftdmchan->span_id;
+ sigev.channel = ftdmchan;
+
+ sigev.event_id = FTDM_SIGEVENT_MSG;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+ }
+ break;
default:
/* We do not support other FACILITY types for now, so do nothing */
break;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T302 Timer expired, proceeding with call\n");
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
break;
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Remote switch expecting OVERLAP receive, but we are already PROCEEDING\n");
break;
case 3:
switch (ftdmchan->state) {
+ case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
/* T310 timer has expired */
ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
#include "ftmod_sangoma_isdn.h"
+static void sngisdn_set_prog_desc(ProgInd *progInd, ftdm_sngisdn_progind_t prod_ind);
+static void sngisdn_set_facilityStr(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
+
void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
{
ConEvnt conEvnt;
cpy_redir_num_from_user(&conEvnt.redirNmb, &ftdmchan->caller_data);
cpy_calling_name_from_user(&conEvnt, ftdmchan);
+ sngisdn_set_facilityStr(ftdmchan, &conEvnt.facilityStr);
+
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
if (sng_isdn_con_request(signal_data->cc_id, sngisdn_info->suInstId, &conEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
return;
}
-void sngisdn_snd_progress(ftdm_channel_t *ftdmchan)
+void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending PROGRESS, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
- cnStEvnt.progInd.progDesc.val = IN_PD_IBAVAIL;
+
+ sngisdn_set_prog_desc(&cnStEvnt.progInd, prog_ind);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) {
return;
}
-void sngisdn_snd_alert(ftdm_channel_t *ftdmchan)
+void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind)
{
CnStEvnt cnStEvnt;
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending ALERT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
cnStEvnt.progInd.codeStand0.pres = PRSNT_NODEF;
cnStEvnt.progInd.codeStand0.val = IN_CSTD_CCITT;
cnStEvnt.progInd.progDesc.pres = PRSNT_NODEF;
- cnStEvnt.progInd.progDesc.val = IN_PD_NOTETEISDN;
+ sngisdn_set_prog_desc(&cnStEvnt.progInd, prog_ind);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
return;
}
+void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan)
+{
+ FacEvnt facEvnt;
+
+ sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending FACILITY, but no call data, ignoring (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
+ return;
+ }
+
+ memset(&facEvnt, 0, sizeof(facEvnt));
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
+
+ if (sng_isdn_facility_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &facEvnt, MI_FACIL, signal_data->dchan_id, sngisdn_info->ces)) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused FACILITY request\n");
+ }
+ return;
+}
void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan)
{
sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
+ if (!sngisdn_info->suInstId || !sngisdn_info->spInstId) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Sending DISCONNECT, but no call data, aborting (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
discEvnt.causeDgn[0].recommend.pres = NOTPRSNT;
discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
+ sngisdn_set_facilityStr(ftdmchan, &discEvnt.facilityStr);
+
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused DISCONNECT request\n");
spInstId = sngisdn_info->spInstId;
}
+ sngisdn_set_facilityStr(ftdmchan, &relEvnt.facilityStr);
+
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, suInstId, spInstId);
if (glare) {
return;
}
+static void sngisdn_set_prog_desc(ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind)
+{
+ switch(prog_ind) {
+ case SNGISDN_PROGIND_NETE_ISDN:
+ progInd->progDesc.val = IN_PD_NOTETEISDN;
+ break;
+ case SNGISDN_PROGIND_DEST_NISDN:
+ progInd->progDesc.val = IN_PD_DSTNOTISDN;
+ break;
+ case SNGISDN_PROGIND_ORIG_NISDN:
+ progInd->progDesc.val = IN_PD_ORGNOTISDN;
+ break;
+ case SNGISDN_PROGIND_RET_ISDN:
+ progInd->progDesc.val = IN_PD_CALLRET;
+ break;
+ case SNGISDN_PROGIND_SERV_CHANGE:
+ /* Trillium defines do not match ITU-T Q931 Progress descriptions,
+ indicate a delayed response for now */
+ progInd->progDesc.val = IN_PD_DELRESP;
+ break;
+ case SNGISDN_PROGIND_IB_AVAIL:
+ progInd->progDesc.val = IN_PD_IBAVAIL;
+ break;
+ }
+ return;
+}
+
+static void sngisdn_set_facilityStr(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr)
+{
+ const char *facility_str = NULL;
+
+ facility_str = ftdm_channel_get_var(ftdmchan, "isdn.facility.val");
+ if (facility_str) {
+ facilityStr->eh.pres = PRSNT_NODEF;
+ facilityStr->facilityStr.len = strlen(facility_str);
+ memcpy(facilityStr->facilityStr.val, facility_str, facilityStr->facilityStr.len);
+ }
+ return;
+}
+
/* We received an incoming frame on the d-channel, send data to the stack */
void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len)
{
return FTDM_SUCCESS;
}
+ftdm_status_t cpy_facility_ie_from_stack(ftdm_caller_data_t *caller_data, uint8_t *data, uint32_t data_len)
+{
+ if (data_len > sizeof(caller_data->raw_data)-2) {
+ ftdm_log(FTDM_LOG_CRIT, "Length of Facility IE exceeds maximum length\n");
+ return FTDM_FAIL;
+ }
+
+ memset(caller_data->raw_data, 0, sizeof(caller_data->raw_data));
+ /* Always include Facility IE identifier + len so this can be used as a sanity check by the user */
+ caller_data->raw_data[0] = 0x1C;
+ caller_data->raw_data[1] = data_len;
+
+ memcpy(&caller_data->raw_data[2], data, data_len);
+ caller_data->raw_data_len = data_len+2;
+
+ return FTDM_SUCCESS;
+}
+
ftdm_status_t cpy_calling_num_from_user(CgPtyNmb *cgPtyNmb, ftdm_caller_data_t *ftdm)
{
uint8_t len = strlen(ftdm->cid_num.digits);
FTDM_SIGEVENT_STOP, /*!< Hangup */
FTDM_SIGEVENT_RELEASED, /*!< Channel is completely released and available */
FTDM_SIGEVENT_UP, /*!< Outgoing call has been answered */
- FTDM_SIGEVENT_FLASH, /*< Flash event (typically on-hook/off-hook for analog devices) */
+ FTDM_SIGEVENT_FLASH, /*!< Flash event (typically on-hook/off-hook for analog devices) */
+ FTDM_SIGEVENT_PROCEED, /*!< Outgoing call got a response */
FTDM_SIGEVENT_PROGRESS, /*!< Outgoing call is making progress */
FTDM_SIGEVENT_PROGRESS_MEDIA, /*!< Outgoing call is making progress and there is media available */
FTDM_SIGEVENT_ALARM_TRAP, /*!< Hardware alarm ON */
FTDM_SIGEVENT_RESTART, /*!< Restart has been requested. Typically you hangup your call resources here */
FTDM_SIGEVENT_SIGSTATUS_CHANGED, /*!< Signaling protocol status changed (ie: D-chan up), see new status in raw_data ftdm_sigmsg_t member */
FTDM_SIGEVENT_COLLISION, /*!< Outgoing call was dropped because an incoming call arrived at the same time */
+ FTDM_SIGEVENT_MSG, /* !< We received an in-call msg */
FTDM_SIGEVENT_INVALID
} ftdm_signal_event_t;
-#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROGRESS", \
+#define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "PROGRESS", \
"PROGRESS_MEDIA", "ALARM_TRAP", "ALARM_CLEAR", \
"COLLECTED_DIGIT", "ADD_CALL", "RESTART", "SIGSTATUS_CHANGED", "COLLISION", "INVALID"
* This is used during incoming calls when you want to request the signaling stack
* to notify about indications occurring locally */
typedef enum {
- FTDM_CHANNEL_INDICATE_RING,
+ FTDM_CHANNEL_INDICATE_RINGING,
FTDM_CHANNEL_INDICATE_PROCEED,
FTDM_CHANNEL_INDICATE_PROGRESS,
FTDM_CHANNEL_INDICATE_PROGRESS_MEDIA,
* after having called ftdm_send_span_signal(), which with this flag it will just enqueue the signal
* for later delivery */
FTDM_SPAN_USE_SIGNALS_QUEUE = (1 << 10),
+ /* If this flag is set, channel will be moved to proceed state when calls goes to routing */
+ FTDM_SPAN_USE_PROCEED_STATE = (1 << 11),
} ftdm_span_flag_t;
/*! \brief Channel supported features */
FTDM_CHANNEL_STATE_DIALTONE,
FTDM_CHANNEL_STATE_COLLECT,
FTDM_CHANNEL_STATE_RING,
+ FTDM_CHANNEL_STATE_RINGING,
FTDM_CHANNEL_STATE_BUSY,
FTDM_CHANNEL_STATE_ATTN,
FTDM_CHANNEL_STATE_GENRING,
FTDM_CHANNEL_STATE_GET_CALLERID,
FTDM_CHANNEL_STATE_CALLWAITING,
FTDM_CHANNEL_STATE_RESTART,
+ FTDM_CHANNEL_STATE_PROCEED,
FTDM_CHANNEL_STATE_PROGRESS,
FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
FTDM_CHANNEL_STATE_UP,
FTDM_CHANNEL_STATE_INVALID
} ftdm_channel_state_t;
#define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \
- "RING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
- "RESTART", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
+ "RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \
+ "RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \
"HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "INVALID"
FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t)
switch(sigmsg->event_id) {
case FTDM_SIGEVENT_START:
- ftdm_channel_call_indicate(sigmsg->channel, FTDM_CHANNEL_INDICATE_RING);
+ ftdm_channel_call_indicate(sigmsg->channel, FTDM_CHANNEL_INDICATE_RINGING);
ftdm_log(FTDM_LOG_DEBUG, "launching thread and indicating ring\n");
ftdm_thread_create_detached(test_call, sigmsg->channel);
break;