mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-23 19:54:17 +00:00
Merge branch 'master' into netborder
Conflicts: libs/freetdm/src/ftdm_io.c libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c libs/freetdm/src/include/freetdm.h
This commit is contained in:
commit
eb84fc772f
224 files changed
+13786
-6134
No files matched your search
@@ -37,7 +37,9 @@
|
||||
|
||||
typedef enum {
|
||||
FTDM_ANALOG_RUNNING = (1 << 0),
|
||||
FTDM_ANALOG_CALLERID = (1 << 1)
|
||||
FTDM_ANALOG_CALLERID = (1 << 1),
|
||||
FTDM_ANALOG_ANSWER_POLARITY_REVERSE = (1 << 2),
|
||||
FTDM_ANALOG_HANGUP_POLARITY_REVERSE = (1 << 3)
|
||||
} ftdm_analog_flag_t;
|
||||
|
||||
#define FTDM_MAX_HOTLINE_STR 20
|
||||
@@ -47,11 +49,13 @@ struct ftdm_analog_data {
|
||||
uint32_t flags;
|
||||
uint32_t max_dialstr;
|
||||
uint32_t wait_dialtone_timeout;
|
||||
uint32_t polarity_delay;
|
||||
uint32_t digit_timeout;
|
||||
char hotline[FTDM_MAX_HOTLINE_STR];
|
||||
};
|
||||
|
||||
|
||||
/* Analog flags to be set in the sflags (signaling flags) channel memeber */
|
||||
#define AF_POLARITY_REVERSE (1 << 0)
|
||||
|
||||
static void *ftdm_analog_run(ftdm_thread_t *me, void *obj);
|
||||
typedef struct ftdm_analog_data ftdm_analog_data_t;
|
||||
|
||||
@@ -96,6 +96,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call)
|
||||
|
||||
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
|
||||
{
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) {
|
||||
*status = FTDM_SIG_STATE_DOWN;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
*status = FTDM_SIG_STATE_UP;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
@@ -109,7 +113,25 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status)
|
||||
|
||||
static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_get_span_sig_status)
|
||||
{
|
||||
*status = FTDM_SIG_STATE_UP;
|
||||
ftdm_iterator_t *citer = NULL;
|
||||
ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL);
|
||||
if (!chaniter) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
/* if ALL channels are in alarm, report DOWN, UP otherwise. */
|
||||
*status = FTDM_SIG_STATE_DOWN;
|
||||
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
|
||||
ftdm_channel_lock(fchan);
|
||||
if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) {
|
||||
*status = FTDM_SIG_STATE_UP;
|
||||
ftdm_channel_unlock(fchan);
|
||||
break;
|
||||
}
|
||||
ftdm_channel_unlock(fchan);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -162,6 +184,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
|
||||
uint32_t digit_timeout = 10;
|
||||
uint32_t wait_dialtone_timeout = 30000;
|
||||
uint32_t max_dialstr = MAX_DTMF;
|
||||
uint32_t polarity_delay = 600;
|
||||
const char *var, *val;
|
||||
int *intval;
|
||||
uint32_t flags = FTDM_ANALOG_CALLERID;
|
||||
@@ -214,6 +237,29 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
|
||||
} else {
|
||||
flags &= ~FTDM_ANALOG_CALLERID;
|
||||
}
|
||||
} else if (!strcasecmp(var, "answer_polarity_reverse")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
if (ftdm_true(val)) {
|
||||
flags |= FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
|
||||
} else {
|
||||
flags &= ~FTDM_ANALOG_ANSWER_POLARITY_REVERSE;
|
||||
}
|
||||
} else if (!strcasecmp(var, "hangup_polarity_reverse")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
if (ftdm_true(val)) {
|
||||
flags |= FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
|
||||
} else {
|
||||
flags &= ~FTDM_ANALOG_HANGUP_POLARITY_REVERSE;
|
||||
}
|
||||
} else if (!strcasecmp(var, "polarity_delay")) {
|
||||
if (!(intval = va_arg(ap, int *))) {
|
||||
break;
|
||||
}
|
||||
polarity_delay = *intval;
|
||||
} else if (!strcasecmp(var, "callwaiting")) {
|
||||
if (!(intval = va_arg(ap, int *))) {
|
||||
break;
|
||||
@@ -254,6 +300,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_configure_span)
|
||||
analog_data->flags = flags;
|
||||
analog_data->digit_timeout = digit_timeout;
|
||||
analog_data->wait_dialtone_timeout = wait_dialtone_timeout;
|
||||
analog_data->polarity_delay = polarity_delay;
|
||||
analog_data->max_dialstr = max_dialstr;
|
||||
span->signal_cb = sig_cb;
|
||||
strncpy(analog_data->hotline, hotline, sizeof(analog_data->hotline));
|
||||
@@ -377,6 +424,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
ftdm_analog_data_t *analog_data = ftdmchan->span->signal_data;
|
||||
ftdm_channel_t *closed_chan;
|
||||
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = analog_data->wait_dialtone_timeout;
|
||||
uint32_t answer_on_polarity_counter = 0;
|
||||
ftdm_sigmsg_t sig;
|
||||
ftdm_status_t status;
|
||||
|
||||
@@ -448,7 +496,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
if (ftdmchan->needed_tones[FTDM_TONEMAP_DIAL]) {
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
/* do not go up if we're waiting for polarity reversal */
|
||||
if (ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
|
||||
} else {
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -493,8 +546,10 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
|
||||
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
|
||||
ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) &&
|
||||
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|
||||
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) {
|
||||
(ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING
|
||||
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE
|
||||
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_RING
|
||||
|| ftdmchan->last_state == FTDM_CHANNEL_STATE_UP)) {
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
|
||||
@@ -530,15 +585,37 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
|
||||
if (done) {
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
ftdmchan->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
|
||||
}
|
||||
}
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
case FTDM_CHANNEL_STATE_RING:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
{
|
||||
ftdm_sleep(interval);
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
|
||||
ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA &&
|
||||
ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Answering on polarity reverse\n");
|
||||
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
|
||||
answer_on_polarity_counter = state_counter;
|
||||
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_UP
|
||||
&& ftdm_test_sflag(ftdmchan, AF_POLARITY_REVERSE)){
|
||||
/* if this polarity reverse is close to the answer polarity reverse, ignore it */
|
||||
if (answer_on_polarity_counter
|
||||
&& (state_counter - answer_on_polarity_counter) > analog_data->polarity_delay) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Hanging up on polarity reverse\n");
|
||||
ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING,
|
||||
"Not hanging up on polarity reverse, too close to Answer reverse\n");
|
||||
}
|
||||
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
|
||||
} else {
|
||||
ftdm_sleep(interval);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -551,7 +628,6 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
indicate = 0;
|
||||
@@ -591,6 +667,19 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
sig.event_id = FTDM_SIGEVENT_UP;
|
||||
}
|
||||
|
||||
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
|
||||
!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) &&
|
||||
ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)) {
|
||||
ftdm_polarity_t polarity = FTDM_POLARITY_REVERSE;
|
||||
if (ftdmchan->polarity == FTDM_POLARITY_FORWARD) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on answer\n");
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
|
||||
} else {
|
||||
/* the polarity may be already reversed if this is the second time we
|
||||
* answer (ie, due to 2 calls being on the same line) */
|
||||
}
|
||||
}
|
||||
|
||||
ftdm_span_send_signal(ftdmchan->span, &sig);
|
||||
continue;
|
||||
}
|
||||
@@ -615,6 +704,22 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
/* this state is only used when the user hangup, if the device hang up (onhook) we currently
|
||||
* go straight to DOWN. If we ever change this (as other signaling modules do) by using this
|
||||
* state for both user and device hangup, we should check here for the type of hangup since
|
||||
* some actions (polarity reverse) do not make sense if the device hung up */
|
||||
if (ftdmchan->type == FTDM_CHAN_TYPE_FXS &&
|
||||
ftdmchan->last_state == FTDM_CHANNEL_STATE_UP &&
|
||||
ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
|
||||
ftdm_polarity_t polarity = ftdmchan->polarity == FTDM_POLARITY_REVERSE
|
||||
? FTDM_POLARITY_FORWARD : FTDM_POLARITY_REVERSE;
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Reversing polarity on hangup\n");
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_POLARITY, &polarity);
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
sig.event_id = FTDM_SIGEVENT_STOP;
|
||||
@@ -717,7 +822,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
dtmf_offset = strlen(dtmf);
|
||||
last_digit = elapsed;
|
||||
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
|
||||
sig.raw_data = dtmf;
|
||||
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
|
||||
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
|
||||
collecting = 0;
|
||||
}
|
||||
@@ -823,6 +928,9 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
|
||||
done:
|
||||
|
||||
closed_chan = ftdmchan;
|
||||
|
||||
ftdm_channel_lock(closed_chan);
|
||||
|
||||
if (ftdmchan->type == FTDM_CHAN_TYPE_FXO && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
|
||||
@@ -833,7 +941,8 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
}
|
||||
|
||||
|
||||
closed_chan = ftdmchan;
|
||||
ftdm_clear_sflag(ftdmchan, AF_POLARITY_REVERSE);
|
||||
|
||||
ftdm_channel_close(&ftdmchan);
|
||||
|
||||
ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
|
||||
@@ -851,8 +960,11 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ftdm_channel_unlock(closed_chan);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -879,19 +991,32 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
||||
ftdm_mutex_lock(event->channel->mutex);
|
||||
locked++;
|
||||
|
||||
/* MAINTENANCE WARNING:
|
||||
* 1. Be aware you are working on the locked channel
|
||||
* 2. We should not be calling ftdm_span_send_signal or ftdm_set_state when there is already a channel thread running
|
||||
* however, since this is old code I am not changing it now, but new code should adhere to that convention
|
||||
* otherwise, we have possible races where we compete with the user for state changes, ie, the user requests
|
||||
* a state change and then we process an event, the state change from the user is pending so our ftdm_set_state
|
||||
* operation will fail. In cases where we win the race, our state change will be accepted but if a user requests
|
||||
* a state change before the state change we requested here is processed by the channel thread, we'll end up
|
||||
* rejecting the user request.
|
||||
*
|
||||
* See docs/locking.txt for further information about what guarantees should signaling modules provide when
|
||||
* locking/unlocking a channel
|
||||
* */
|
||||
switch(event->enum_id) {
|
||||
case FTDM_OOB_RING_START:
|
||||
{
|
||||
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
|
||||
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);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
|
||||
goto end;
|
||||
}
|
||||
if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) {
|
||||
if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID);
|
||||
} else {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_RING);
|
||||
}
|
||||
event->channel->ring_count = 1;
|
||||
ftdm_mutex_unlock(event->channel->mutex);
|
||||
@@ -909,24 +1034,33 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
||||
}
|
||||
|
||||
if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
|
||||
if (event->channel->state == FTDM_CHANNEL_STATE_HANGUP &&
|
||||
ftdm_test_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
/* we do not need to process HANGUP since the device also hangup already */
|
||||
ftdm_channel_complete_state(event->channel);
|
||||
}
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
if (event->channel->type == FTDM_CHAN_TYPE_FXS) {
|
||||
/* we always return to forward when the device goes onhook */
|
||||
ftdm_polarity_t forward_polarity = FTDM_POLARITY_FORWARD;
|
||||
ftdm_channel_command(event->channel, FTDM_COMMAND_SET_POLARITY, &forward_polarity);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_FLASH:
|
||||
{
|
||||
if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_clear_flag(event->channel->span, FTDM_SPAN_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(event->channel);
|
||||
event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0;
|
||||
}
|
||||
|
||||
ftdm_channel_rotate_tokens(event->channel);
|
||||
|
||||
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||
} else {
|
||||
sig.event_id = FTDM_SIGEVENT_FLASH;
|
||||
ftdm_span_send_signal(span, &sig);
|
||||
@@ -940,12 +1074,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
||||
if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) {
|
||||
ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL);
|
||||
}
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP);
|
||||
} else {
|
||||
if(!analog_data->max_dialstr) {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_COLLECT);
|
||||
} else {
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
|
||||
}
|
||||
ftdm_mutex_unlock(event->channel->mutex);
|
||||
locked = 0;
|
||||
@@ -957,9 +1091,53 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e
|
||||
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
|
||||
}
|
||||
}
|
||||
ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
|
||||
ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_ALARM_TRAP:
|
||||
{
|
||||
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
||||
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN;
|
||||
ftdm_span_send_signal(span, &sig);
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_ALARM_CLEAR:
|
||||
{
|
||||
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
||||
sig.ev_data.sigstatus.status = FTDM_SIG_STATE_UP;
|
||||
ftdm_span_send_signal(span, &sig);
|
||||
}
|
||||
break;
|
||||
case FTDM_OOB_POLARITY_REVERSE:
|
||||
{
|
||||
if (event->channel->type != FTDM_CHAN_TYPE_FXO) {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
|
||||
"Ignoring polarity reversal, this should not happen in non-FXO channels!\n");
|
||||
break;
|
||||
}
|
||||
if (!ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD) &&
|
||||
ftdm_test_flag(event->channel, FTDM_CHANNEL_OFFHOOK)) {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_WARNING,
|
||||
"Forcing onhook in channel not in thread after polarity reversal\n");
|
||||
ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL);
|
||||
break;
|
||||
}
|
||||
if (!ftdm_test_flag(analog_data, FTDM_ANALOG_ANSWER_POLARITY_REVERSE)
|
||||
&& !ftdm_test_flag(analog_data, FTDM_ANALOG_HANGUP_POLARITY_REVERSE)) {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
|
||||
"Ignoring polarity reversal because this channel is not configured for it\n");
|
||||
break;
|
||||
}
|
||||
if (event->channel->state == FTDM_CHANNEL_STATE_DOWN) {
|
||||
ftdm_log_chan_msg(event->channel, FTDM_LOG_DEBUG,
|
||||
"Ignoring polarity reversal because this channel is down\n");
|
||||
break;
|
||||
}
|
||||
/* we have a good channel, set the polarity flag and let the channel thread deal with it */
|
||||
ftdm_set_sflag(event->channel, AF_POLARITY_REVERSE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state));
|
||||
|
||||
@@ -355,7 +355,6 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
indicate = 0;
|
||||
@@ -467,7 +466,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
|
||||
dtmf_offset = strlen(dtmf);
|
||||
last_digit = elapsed;
|
||||
sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
|
||||
sig.raw_data = dtmf;
|
||||
ftdm_set_string(sig.ev_data.collected.digits, dtmf);
|
||||
if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
|
||||
collecting = 0;
|
||||
}
|
||||
|
||||
@@ -497,7 +497,7 @@ static ftdm_state_map_t isdn_state_map = {
|
||||
* \param ftdmchan Channel to handle
|
||||
* \note This function MUST be called with the channel locked
|
||||
*/
|
||||
static __inline__ void state_advance(ftdm_channel_t *chan)
|
||||
static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
||||
{
|
||||
ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
|
||||
q931_call *call = (q931_call *)chan->call_data;
|
||||
@@ -511,27 +511,23 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
|
||||
sig.chan_id = ftdm_channel_get_id(chan);
|
||||
sig.span_id = ftdm_channel_get_span_id(chan);
|
||||
sig.channel = chan;
|
||||
|
||||
ftdm_channel_complete_state(chan);
|
||||
|
||||
switch (ftdm_channel_get_state(chan)) {
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
ftdm_channel_t *chtmp = chan;
|
||||
chan->call_data = NULL;
|
||||
ftdm_channel_done(chan);
|
||||
|
||||
/*
|
||||
* Close channel completely, BRI PTMP will thank us
|
||||
*/
|
||||
if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
|
||||
ftdm_channel_t *chtmp = chan;
|
||||
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan));
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan));
|
||||
}
|
||||
if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan));
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
|
||||
ftdm_channel_get_span_id(chan),
|
||||
ftdm_channel_get_id(chan));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -631,7 +627,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
|
||||
ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
|
||||
/* TODO: set hangup cause? */
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
|
||||
return;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
ton = caller_data->dnis.type;
|
||||
@@ -714,6 +710,7 @@ static __inline__ void state_advance(ftdm_channel_t *chan)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -729,13 +726,8 @@ static __inline__ void check_state(ftdm_span_t *span)
|
||||
|
||||
for (j = 1; j <= ftdm_span_get_chan_count(span); j++) {
|
||||
ftdm_channel_t *chan = ftdm_span_get_channel(span, j);
|
||||
|
||||
ftdm_channel_lock(chan);
|
||||
while (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_clear_flag(chan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
state_advance(chan);
|
||||
ftdm_channel_complete_state(chan);
|
||||
}
|
||||
ftdm_channel_advance_states(chan);
|
||||
ftdm_channel_unlock(chan);
|
||||
}
|
||||
}
|
||||
@@ -1403,8 +1395,7 @@ static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev
|
||||
sig.chan_id = ftdm_channel_get_id(chan);
|
||||
sig.channel = chan;
|
||||
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
||||
sig.raw_data = &status;
|
||||
|
||||
sig.ev_data.sigstatus.status = status;
|
||||
ftdm_span_send_signal(span, &sig);
|
||||
}
|
||||
}
|
||||
@@ -1440,7 +1431,7 @@ static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_
|
||||
sig.chan_id = ftdm_channel_get_id(chan);
|
||||
sig.channel = chan;
|
||||
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
||||
sig.raw_data = &status;
|
||||
sig.ev_data.sigstatus.status = status;
|
||||
|
||||
ftdm_span_send_signal(span, &sig);
|
||||
}
|
||||
@@ -1917,6 +1908,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
|
||||
span->outgoing_call = isdn_outgoing_call;
|
||||
|
||||
span->state_map = &isdn_state_map;
|
||||
span->state_processor = state_advance;
|
||||
|
||||
span->get_channel_sig_status = isdn_get_channel_sig_status;
|
||||
span->get_span_sig_status = isdn_get_span_sig_status;
|
||||
|
||||
@@ -127,9 +127,8 @@ static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id);
|
||||
}
|
||||
|
||||
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
|
||||
return -1;
|
||||
/* we cannot return -1, libpri seems to expect values >= 0 */
|
||||
return 0;
|
||||
}
|
||||
spri->errs = 0;
|
||||
res = (int)len;
|
||||
@@ -156,8 +155,8 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
|
||||
|
||||
if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error);
|
||||
ftdm_clear_flag(spri, LPWRAP_PRI_READY);
|
||||
return -1;
|
||||
/* we cannot return -1, libpri seems to expect values >= 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IODEBUG
|
||||
|
||||
@@ -265,7 +265,7 @@ static ftdm_state_map_t pritap_state_map = {
|
||||
}
|
||||
};
|
||||
|
||||
static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
|
||||
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_status_t status;
|
||||
ftdm_sigmsg_t sig;
|
||||
@@ -278,6 +278,8 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
|
||||
sig.span_id = ftdmchan->span_id;
|
||||
sig.channel = ftdmchan;
|
||||
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
switch (ftdmchan->state) {
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
@@ -321,24 +323,20 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan)
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static __inline__ void pritap_check_state(ftdm_span_t *span)
|
||||
{
|
||||
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
|
||||
uint32_t j;
|
||||
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
|
||||
for(j = 1; j <= span->chan_count; j++) {
|
||||
if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_mutex_lock(span->channels[j]->mutex);
|
||||
ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE);
|
||||
state_advance(span->channels[j]);
|
||||
ftdm_channel_complete_state(span->channels[j]);
|
||||
ftdm_mutex_unlock(span->channels[j]->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
|
||||
uint32_t j;
|
||||
ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
|
||||
for(j = 1; j <= span->chan_count; j++) {
|
||||
ftdm_mutex_lock(span->channels[j]->mutex);
|
||||
ftdm_channel_advance_states(span->channels[j]);
|
||||
ftdm_mutex_unlock(span->channels[j]->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int pri_io_read(struct pri *pri, void *buf, int buflen)
|
||||
@@ -896,6 +894,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_pritap_configure_span)
|
||||
span->get_span_sig_status = pritap_get_span_sig_status;
|
||||
|
||||
span->state_map = &pritap_state_map;
|
||||
span->state_processor = state_advance;
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* Contributors:
|
||||
*
|
||||
* Arnaldo Pereira <arnaldo@sangoma.com>
|
||||
* Ricardo Barroetaveña <rbarroetavena@anura.com.ar>
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -49,10 +50,6 @@
|
||||
#include "freetdm.h"
|
||||
#include "private/ftdm_core.h"
|
||||
|
||||
/* debug thread count for r2 legs */
|
||||
static ftdm_mutex_t* g_thread_count_mutex;
|
||||
static int32_t g_thread_count = 0;
|
||||
|
||||
typedef int openr2_call_status_t;
|
||||
|
||||
/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread
|
||||
@@ -76,7 +73,6 @@ typedef struct ftdm_r2_call_t {
|
||||
int disconnect_rcvd:1;
|
||||
int ftdm_call_started:1;
|
||||
int protocol_error:1;
|
||||
ftdm_channel_state_t chanstate;
|
||||
ftdm_size_t dnis_index;
|
||||
ftdm_size_t ani_index;
|
||||
char logname[255];
|
||||
@@ -171,8 +167,7 @@ static ftdm_hash_t *g_mod_data_hash;
|
||||
/* IO interface for the command API */
|
||||
static ftdm_io_interface_t g_ftdm_r2_interface;
|
||||
|
||||
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
|
||||
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan);
|
||||
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
|
||||
|
||||
/* whether R2 call accept process is pending */
|
||||
#define IS_ACCEPTING_PENDING(ftdmchan) \
|
||||
@@ -352,7 +347,6 @@ static void ft_r2_clean_call(ftdm_r2_call_t *call)
|
||||
call->disconnect_rcvd = 0;
|
||||
call->ftdm_call_started = 0;
|
||||
call->protocol_error = 0;
|
||||
call->chanstate = FTDM_CHANNEL_STATE_DOWN;
|
||||
call->dnis_index = 0;
|
||||
call->ani_index = 0;
|
||||
call->name[0] = 0;
|
||||
@@ -380,11 +374,72 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan)
|
||||
R2CALL(ftdmchan)->answer_pending = 0;
|
||||
}
|
||||
|
||||
static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc)
|
||||
{
|
||||
switch (cpc) {
|
||||
case OR2_CALLING_PARTY_CATEGORY_UNKNOWN:
|
||||
return FTDM_CPC_UNKNOWN;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER:
|
||||
return FTDM_CPC_ORDINARY;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER:
|
||||
return FTDM_CPC_PRIORITY;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER:
|
||||
return FTDM_CPC_UNKNOWN;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER:
|
||||
return FTDM_CPC_UNKNOWN;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT:
|
||||
return FTDM_CPC_TEST;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE:
|
||||
return FTDM_CPC_PAYPHONE;
|
||||
|
||||
case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL:
|
||||
return FTDM_CPC_OPERATOR;
|
||||
}
|
||||
return FTDM_CPC_INVALID;
|
||||
}
|
||||
|
||||
static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc)
|
||||
{
|
||||
switch (cpc) {
|
||||
case FTDM_CPC_UNKNOWN:
|
||||
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
|
||||
|
||||
case FTDM_CPC_OPERATOR:
|
||||
return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL;
|
||||
|
||||
case FTDM_CPC_ORDINARY:
|
||||
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
|
||||
|
||||
case FTDM_CPC_PRIORITY:
|
||||
return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER;
|
||||
|
||||
case FTDM_CPC_DATA:
|
||||
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
|
||||
|
||||
case FTDM_CPC_TEST:
|
||||
return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT;
|
||||
|
||||
case FTDM_CPC_PAYPHONE:
|
||||
return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE;
|
||||
|
||||
case FTDM_CPC_INVALID:
|
||||
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
|
||||
}
|
||||
return OR2_CALLING_PARTY_CATEGORY_UNKNOWN;
|
||||
}
|
||||
|
||||
/* this function must be called with the chan mutex held! */
|
||||
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
|
||||
{
|
||||
openr2_call_status_t callstatus;
|
||||
ftdm_r2_data_t *r2data;
|
||||
openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
|
||||
|
||||
r2data = ftdmchan->span->signal_data;
|
||||
|
||||
@@ -397,6 +452,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
|
||||
|
||||
ft_r2_clean_call(ftdmchan->call_data);
|
||||
|
||||
if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) {
|
||||
category = r2data->category;
|
||||
} else {
|
||||
category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc);
|
||||
}
|
||||
|
||||
/* start io dump */
|
||||
if (r2data->mf_dump_size) {
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
|
||||
@@ -404,9 +465,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
|
||||
}
|
||||
|
||||
callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan,
|
||||
ftdmchan->caller_data.cid_num.digits,
|
||||
ftdmchan->caller_data.cid_num.digits,
|
||||
ftdmchan->caller_data.dnis.digits,
|
||||
r2data->category);
|
||||
category,
|
||||
ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? 0 : 1);
|
||||
|
||||
if (callstatus) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
|
||||
@@ -414,7 +476,6 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
|
||||
}
|
||||
|
||||
R2CALL(ftdmchan)->ftdm_call_started = 1;
|
||||
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
|
||||
|
||||
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
|
||||
@@ -456,19 +517,40 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
|
||||
static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status)
|
||||
{
|
||||
openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
|
||||
openr2_cas_signal_t rxcas, txcas;
|
||||
|
||||
/* get the current rx and tx cas bits */
|
||||
openr2_chan_get_cas(r2chan, &rxcas, &txcas);
|
||||
|
||||
/* if we're already in the state the user asks us to be, we have nothing to do */
|
||||
if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n");
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n");
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable.
|
||||
* see docs/sigstatus.txt for details */
|
||||
switch(status) {
|
||||
case FTDM_SIG_STATE_DOWN:
|
||||
case FTDM_SIG_STATE_SUSPENDED:
|
||||
openr2_chan_set_blocked(r2chan);
|
||||
if (rxcas == OR2_CAS_IDLE) {
|
||||
ftdm_r2_set_chan_sig_status(ftdmchan, status);
|
||||
}
|
||||
break;
|
||||
case FTDM_SIG_STATE_UP:
|
||||
openr2_chan_set_idle(r2chan);
|
||||
if (rxcas == OR2_CAS_IDLE) {
|
||||
ftdm_r2_set_chan_sig_status(ftdmchan, status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_r2_set_chan_sig_status(ftdmchan, status);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -484,10 +566,13 @@ static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status)
|
||||
*status = FTDM_SIG_STATE_SUSPENDED;
|
||||
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
|
||||
ftdm_channel_lock(fchan);
|
||||
if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) {
|
||||
*status = FTDM_SIG_STATE_UP;
|
||||
ftdm_channel_unlock(fchan);
|
||||
break;
|
||||
}
|
||||
ftdm_channel_unlock(fchan);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
return FTDM_SUCCESS;
|
||||
@@ -497,21 +582,6 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
|
||||
{
|
||||
ftdm_iterator_t *chaniter = NULL;
|
||||
ftdm_iterator_t *citer = NULL;
|
||||
uint32_t span_opr = -1;
|
||||
|
||||
/* we either set the channels to BLOCK or IDLE */
|
||||
switch(status) {
|
||||
case FTDM_SIG_STATE_DOWN:
|
||||
case FTDM_SIG_STATE_SUSPENDED:
|
||||
span_opr = 0;
|
||||
break;
|
||||
case FTDM_SIG_STATE_UP:
|
||||
span_opr = 1;
|
||||
break;
|
||||
default:
|
||||
ftdm_log(FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
chaniter = ftdm_span_get_chan_iterator(span, NULL);
|
||||
if (!chaniter) {
|
||||
@@ -521,15 +591,13 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status)
|
||||
/* iterate over all channels, setting them to the requested state */
|
||||
for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdm_channel_t *fchan = ftdm_iterator_current(citer);
|
||||
openr2_chan_t *r2chan = R2CALL(fchan)->r2chan;
|
||||
if (span_opr == 0) {
|
||||
openr2_chan_set_blocked(r2chan);
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel blocked\n");
|
||||
} else {
|
||||
openr2_chan_set_idle(r2chan);
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_NOTICE, "Channel idle\n");
|
||||
/* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes
|
||||
* care of notifying the user when appropriate */
|
||||
ftdm_channel_lock(fchan);
|
||||
if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status));
|
||||
}
|
||||
ftdm_r2_set_chan_sig_status(fchan, status);
|
||||
ftdm_channel_unlock(fchan);
|
||||
}
|
||||
ftdm_iterator_free(chaniter);
|
||||
return FTDM_SUCCESS;
|
||||
@@ -552,7 +620,7 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
|
||||
ftdm_sched_cancel_timer(r2data->sched, r2call->protocol_error_recovery_timer);
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Cancelled protocol error recovery timer\n");
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,7 +654,6 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
|
||||
}
|
||||
|
||||
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
|
||||
ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS);
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_FLUSH_TX_BUFFERS, NULL);
|
||||
@@ -595,12 +662,14 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
|
||||
|
||||
static void dump_mf(openr2_chan_t *r2chan);
|
||||
/* 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 */
|
||||
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
|
||||
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis,
|
||||
openr2_calling_party_category_t category, int ani_restricted)
|
||||
{
|
||||
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
|
||||
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = %d, ANI restricted = %s\n",
|
||||
ani, dnis, category, ani_restricted ? "Yes" : "No");
|
||||
|
||||
/* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
|
||||
if (r2data->mf_dump_size) {
|
||||
@@ -615,6 +684,8 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
|
||||
} else {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
|
||||
}
|
||||
ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category);
|
||||
ftdmchan->caller_data.pres = ani_restricted ? FTDM_PRES_RESTRICTED : FTDM_PRES_ALLOWED;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -632,12 +703,10 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons
|
||||
static void clear_accept_pending(ftdm_channel_t *fchan)
|
||||
{
|
||||
if (IS_ACCEPTING_PENDING(fchan)) {
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(fchan);
|
||||
} else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n",
|
||||
ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(fchan);
|
||||
}
|
||||
}
|
||||
@@ -745,7 +814,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
|
||||
/* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
}
|
||||
|
||||
static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
|
||||
@@ -777,7 +846,7 @@ static void ftdm_r2_recover_from_protocol_error(void *data)
|
||||
goto done;
|
||||
}
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
done:
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
@@ -1158,6 +1227,18 @@ static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level)
|
||||
|
||||
static ftdm_state_map_t r2_state_map = {
|
||||
{
|
||||
{
|
||||
ZSD_INBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_ANY_STATE, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
|
||||
},
|
||||
{
|
||||
ZSD_INBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
|
||||
},
|
||||
{
|
||||
ZSD_INBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
@@ -1209,6 +1290,20 @@ static ftdm_state_map_t r2_state_map = {
|
||||
|
||||
/* Outbound states */
|
||||
|
||||
{
|
||||
ZSD_OUTBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_ANY_STATE, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_RESET, FTDM_END}
|
||||
},
|
||||
|
||||
{
|
||||
ZSD_OUTBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
{FTDM_CHANNEL_STATE_RESET, FTDM_END},
|
||||
{FTDM_CHANNEL_STATE_DOWN, FTDM_END}
|
||||
},
|
||||
|
||||
{
|
||||
ZSD_OUTBOUND,
|
||||
ZSM_UNACCEPTABLE,
|
||||
@@ -1515,10 +1610,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
|
||||
span->set_channel_sig_status = ftdm_r2_set_channel_sig_status;
|
||||
|
||||
span->state_map = &r2_state_map;
|
||||
span->state_processor = ftdm_r2_state_advance;
|
||||
|
||||
/* use signals queue */
|
||||
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
|
||||
|
||||
/* we can skip states (going straight from RING to UP) */
|
||||
ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
|
||||
|
||||
/* setup the scheduler */
|
||||
snprintf(schedname, sizeof(schedname), "ftmod_r2_%s", span->name);
|
||||
ftdm_assert(ftdm_sched_create(&r2data->sched, schedname) == FTDM_SUCCESS, "Failed to create schedule!\n");
|
||||
@@ -1541,10 +1640,10 @@ fail:
|
||||
}
|
||||
|
||||
/* the channel must be locked when calling this function */
|
||||
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||
static ftdm_status_t ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_sigmsg_t sigev;
|
||||
int ret;
|
||||
ftdm_status_t ret;
|
||||
ftdm_r2_call_t *r2call = R2CALL(ftdmchan);
|
||||
openr2_chan_t *r2chan = r2call->r2chan;
|
||||
ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
|
||||
@@ -1554,172 +1653,173 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||
sigev.span_id = ftdmchan->span_id;
|
||||
sigev.channel = ftdmchan;
|
||||
|
||||
ret = 0;
|
||||
ret = FTDM_SUCCESS;
|
||||
|
||||
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
|
||||
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
|
||||
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
|
||||
* to complete (the processing is media-bound)
|
||||
* */
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
|
||||
&& (r2call->chanstate != ftdmchan->state)) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
r2call->chanstate = ftdmchan->state;
|
||||
|
||||
if (IS_ACCEPTING_PENDING(ftdmchan)) {
|
||||
/*
|
||||
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
|
||||
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
|
||||
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
|
||||
which means during that time the user should not try to perform any operations like answer, hangup or anything
|
||||
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
|
||||
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
|
||||
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
|
||||
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
}
|
||||
|
||||
switch (ftdmchan->state) {
|
||||
|
||||
/* starting an incoming call */
|
||||
case FTDM_CHANNEL_STATE_COLLECT:
|
||||
{
|
||||
uint32_t interval = 0;
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
|
||||
ftdm_assert(interval != 0, "Invalid interval!");
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
|
||||
openr2_chan_enable_read(r2chan);
|
||||
}
|
||||
break;
|
||||
|
||||
/* starting an outgoing call */
|
||||
case FTDM_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
uint32_t interval = 0;
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
|
||||
ftdm_assert(interval != 0, "Invalid interval!");
|
||||
ftdm_log_chan(ftdmchan,
|
||||
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
|
||||
openr2_chan_enable_read(r2chan);
|
||||
}
|
||||
break;
|
||||
|
||||
/* incoming call was offered */
|
||||
case FTDM_CHANNEL_STATE_RING:
|
||||
|
||||
/* notify the user about the new call */
|
||||
sigev.event_id = FTDM_SIGEVENT_START;
|
||||
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
r2call->ftdm_call_started = 1;
|
||||
|
||||
break;
|
||||
|
||||
/* the call is making progress */
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
{
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
if (!r2call->accepted) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
|
||||
ft_r2_accept_call(ftdmchan);
|
||||
}
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
|
||||
sigev.event_id = FTDM_SIGEVENT_PROCEED;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
|
||||
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* the call was answered */
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
if (!r2call->accepted) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
|
||||
// the answering will be done in the on_call_accepted handler
|
||||
ft_r2_accept_call(ftdmchan);
|
||||
r2call->answer_pending = 1;
|
||||
} else {
|
||||
ft_r2_answer_call(ftdmchan);
|
||||
}
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
|
||||
sigev.event_id = FTDM_SIGEVENT_UP;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* just got hangup */
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
if (!r2call->disconnect_rcvd) {
|
||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
|
||||
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
|
||||
openr2_chan_disconnect_call(r2chan, disconnect_cause);
|
||||
} else if (!r2call->protocol_error) {
|
||||
/* just ack the hangup, on_call_end will be called by openr2 right after */
|
||||
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
|
||||
/* do not set to down yet, give some time for recovery */
|
||||
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
|
||||
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||
{
|
||||
/* if the call has not been started yet we must go to HANGUP right here */
|
||||
if (!r2call->ftdm_call_started) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
|
||||
} else {
|
||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
|
||||
/* notify the user of the call terminating and we wait for the user to move us to hangup */
|
||||
sigev.event_id = FTDM_SIGEVENT_STOP;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* finished call for good */
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
if (IS_ACCEPTING_PENDING(ftdmchan)) {
|
||||
/*
|
||||
Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
|
||||
the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
|
||||
since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
|
||||
which means during that time the user should not try to perform any operations like answer, hangup or anything
|
||||
else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
|
||||
the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
|
||||
otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
|
||||
if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
switch (ftdmchan->state) {
|
||||
|
||||
/* starting an incoming call */
|
||||
case FTDM_CHANNEL_STATE_COLLECT:
|
||||
{
|
||||
uint32_t interval = 0;
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
|
||||
ftdm_assert(interval != 0, "Invalid interval!");
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
|
||||
openr2_chan_enable_read(r2chan);
|
||||
}
|
||||
break;
|
||||
|
||||
/* starting an outgoing call */
|
||||
case FTDM_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
uint32_t interval = 0;
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
|
||||
ftdm_assert(interval != 0, "Invalid interval!");
|
||||
ftdm_log_chan(ftdmchan,
|
||||
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
|
||||
openr2_chan_enable_read(r2chan);
|
||||
}
|
||||
break;
|
||||
|
||||
/* incoming call was offered */
|
||||
case FTDM_CHANNEL_STATE_RING:
|
||||
|
||||
/* notify the user about the new call */
|
||||
sigev.event_id = FTDM_SIGEVENT_START;
|
||||
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
r2call->ftdm_call_started = 1;
|
||||
|
||||
break;
|
||||
|
||||
/* the call is making progress */
|
||||
case FTDM_CHANNEL_STATE_PROGRESS:
|
||||
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
|
||||
{
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
if (!r2call->accepted) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n");
|
||||
ft_r2_accept_call(ftdmchan);
|
||||
}
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
|
||||
sigev.event_id = FTDM_SIGEVENT_PROCEED;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
|
||||
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* the call was answered */
|
||||
case FTDM_CHANNEL_STATE_UP:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n");
|
||||
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
if (!r2call->accepted) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n");
|
||||
// the answering will be done in the on_call_accepted handler
|
||||
ft_r2_accept_call(ftdmchan);
|
||||
r2call->answer_pending = 1;
|
||||
} else {
|
||||
ft_r2_answer_call(ftdmchan);
|
||||
}
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
|
||||
sigev.event_id = FTDM_SIGEVENT_UP;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* just got hangup */
|
||||
case FTDM_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
if (!r2call->disconnect_rcvd) {
|
||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
|
||||
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
|
||||
openr2_chan_disconnect_call(r2chan, disconnect_cause);
|
||||
} else if (!r2call->protocol_error) {
|
||||
/* just ack the hangup, on_call_end will be called by openr2 right after */
|
||||
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
|
||||
/* do not set to down yet, give some time for recovery */
|
||||
ftdm_sched_timer(r2data->sched, "protocolerr_recover", 100,
|
||||
ftdm_r2_recover_from_protocol_error, r2chan, &r2call->protocol_error_recovery_timer);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FTDM_CHANNEL_STATE_TERMINATING:
|
||||
{
|
||||
/* if the call has not been started yet we must go to HANGUP right here */
|
||||
if (!r2call->ftdm_call_started) {
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
|
||||
} else {
|
||||
openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
|
||||
/* notify the user of the call terminating and we wait for the user to move us to hangup */
|
||||
sigev.event_id = FTDM_SIGEVENT_STOP;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sigev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* finished call for good */
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
if (ftdmchan->last_state != FTDM_CHANNEL_STATE_RESET) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Call is down\n");
|
||||
} else {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 Reset Complete\n");
|
||||
}
|
||||
ret = FTDM_BREAK;
|
||||
}
|
||||
break;
|
||||
|
||||
/* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */
|
||||
case FTDM_CHANNEL_STATE_RINGING:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n");
|
||||
}
|
||||
break;
|
||||
|
||||
/* put the r2 channel back to IDLE, close ftdmchan and set it's state as DOWN */
|
||||
case FTDM_CHANNEL_STATE_RESET:
|
||||
{
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RESET indicated, putting the R2 channel back to IDLE\n");
|
||||
openr2_chan_set_idle(r2chan);
|
||||
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == FTDM_BREAK) {
|
||||
ftdm_channel_t *closed_chan;
|
||||
closed_chan = ftdmchan;
|
||||
ftdm_channel_close(&closed_chan);
|
||||
@@ -1728,20 +1828,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* the channel must be locked when calling this function */
|
||||
static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
/* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
|
||||
* procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
|
||||
* function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
|
||||
* to complete (the processing is media-bound)
|
||||
* */
|
||||
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
|
||||
&& (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
|
||||
ftdm_r2_state_advance(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
||||
{
|
||||
openr2_chan_t *r2chan = NULL;
|
||||
@@ -1776,10 +1862,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
||||
}
|
||||
for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) {
|
||||
ftdmchan = ftdm_iterator_current(citer);
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
r2chan = R2CALL(ftdmchan)->r2chan;
|
||||
openr2_chan_set_span_id(r2chan, span->span_id);
|
||||
openr2_chan_set_idle(r2chan);
|
||||
openr2_chan_process_cas_signaling(r2chan);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &txqueue_size);
|
||||
}
|
||||
|
||||
@@ -1861,7 +1949,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
||||
for ( ; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdmchan = ftdm_iterator_current(citer);
|
||||
|
||||
ftdm_mutex_lock(ftdmchan->mutex);
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
|
||||
call = R2CALL(ftdmchan);
|
||||
|
||||
@@ -1870,12 +1958,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_RX_DISABLED);
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
|
||||
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
r2chan = call->r2chan;
|
||||
openr2_chan_process_signaling(r2chan);
|
||||
|
||||
ftdm_r2_state_advance_all(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
if (!call->accepted) {
|
||||
/* if the call is not accepted we do not want users reading */
|
||||
@@ -1883,7 +1971,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
|
||||
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_TX_DISABLED);
|
||||
}
|
||||
|
||||
ftdm_mutex_unlock(ftdmchan->mutex);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1891,8 +1979,10 @@ done:
|
||||
citer = ftdm_span_get_chan_iterator(span, chaniter);
|
||||
for ( ; citer; citer = ftdm_iterator_next(citer)) {
|
||||
ftdmchan = ftdm_iterator_current(citer);
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
r2chan = R2CALL(ftdmchan)->r2chan;
|
||||
openr2_chan_set_blocked(r2chan);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
|
||||
ftdm_iterator_free(chaniter);
|
||||
@@ -1947,6 +2037,14 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle
|
||||
ftdm_mutex_unlock(fchan->mutex);
|
||||
}
|
||||
|
||||
#define FT_SYNTAX "USAGE:\n" \
|
||||
"--------------------------------------------------------------------------------\n" \
|
||||
"ftdm r2 status <span_id|span_name>\n" \
|
||||
"ftdm r2 loopstats <span_id|span_name>\n" \
|
||||
"ftdm r2 block|unblock <span_id|span_name> [<chan_id>]\n" \
|
||||
"ftdm r2 version\n" \
|
||||
"ftdm r2 variants\n" \
|
||||
"--------------------------------------------------------------------------------\n"
|
||||
static FIO_API_FUNCTION(ftdm_r2_api)
|
||||
{
|
||||
ftdm_span_t *span = NULL;
|
||||
@@ -2130,14 +2228,6 @@ static FIO_API_FUNCTION(ftdm_r2_api)
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
if (!strcasecmp(argv[0], "threads")) {
|
||||
ftdm_mutex_lock(g_thread_count_mutex);
|
||||
stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count);
|
||||
ftdm_mutex_unlock(g_thread_count_mutex);
|
||||
stream->write_function(stream, "+OK.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[0], "version")) {
|
||||
stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
|
||||
stream->write_function(stream, "+OK.\n");
|
||||
@@ -2163,7 +2253,7 @@ static FIO_API_FUNCTION(ftdm_r2_api)
|
||||
}
|
||||
}
|
||||
|
||||
stream->write_function(stream, "-ERR invalid command.\n");
|
||||
stream->write_function(stream, "%s", FT_SYNTAX);
|
||||
|
||||
done:
|
||||
|
||||
@@ -2192,7 +2282,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init)
|
||||
if (!g_mod_data_hash) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_mutex_create(&g_thread_count_mutex);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2212,7 +2301,6 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
|
||||
}
|
||||
}
|
||||
hashtable_destroy(g_mod_data_hash);
|
||||
ftdm_mutex_destroy(&g_thread_count_mutex);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -951,7 +951,6 @@ static void handle_call_answer(ftdm_span_t *span, sangomabc_connection_t *mcon,
|
||||
}
|
||||
}
|
||||
|
||||
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
|
||||
static __inline__ void stop_loop(ftdm_channel_t *ftdmchan);
|
||||
|
||||
/**
|
||||
@@ -1002,7 +1001,7 @@ tryagain:
|
||||
} else if (ftdmchan->state == FTDM_CHANNEL_STATE_IN_LOOP && retry) {
|
||||
retry = 0;
|
||||
stop_loop(ftdmchan);
|
||||
advance_chan_states(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
goto tryagain;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_ERROR, "s%dc%d: rejecting incoming call in channel state %s\n",
|
||||
@@ -1267,7 +1266,7 @@ static ftdm_channel_t* event_process_states(ftdm_span_t *span, sangomabc_short_e
|
||||
}
|
||||
|
||||
ftdm_mutex_lock(ftdmchan->mutex);
|
||||
advance_chan_states(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
return ftdmchan;
|
||||
}
|
||||
|
||||
@@ -1354,11 +1353,11 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
|
||||
}
|
||||
|
||||
if(ftdmchan != NULL) {
|
||||
advance_chan_states(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
ftdm_mutex_unlock(ftdmchan->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -1366,7 +1365,7 @@ static int parse_sangoma_event(ftdm_span_t *span, sangomabc_connection_t *mcon,
|
||||
* \brief Handler for channel state change
|
||||
* \param ftdmchan Channel to handle
|
||||
*/
|
||||
static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
|
||||
static ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_sangoma_boost_data_t *sangoma_boost_data = ftdmchan->span->signal_data;
|
||||
sangomabc_connection_t *mcon = &sangoma_boost_data->mcon;
|
||||
@@ -1374,12 +1373,6 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
|
||||
ftdm_status_t status;
|
||||
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
} else {
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
ftdm_assert_return(ftdmchan->last_state != ftdmchan->state, FTDM_FAIL, "Channel state already processed\n");
|
||||
|
||||
ftdm_log(FTDM_LOG_DEBUG, "%d:%d PROCESSING STATE [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state));
|
||||
@@ -1389,6 +1382,8 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
|
||||
sig.span_id = ftdmchan->span_id;
|
||||
sig.channel = ftdmchan;
|
||||
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
switch (ftdmchan->state) {
|
||||
case FTDM_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
@@ -1640,24 +1635,15 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
state_advance(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialises outgoing requests array
|
||||
*/
|
||||
static __inline__ void init_outgoing_array(void)
|
||||
{
|
||||
memset(&OUTBOUND_REQUESTS, 0, sizeof(OUTBOUND_REQUESTS));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1685,7 +1671,7 @@ static __inline__ void check_state(ftdm_span_t *span)
|
||||
if (susp && span->channels[j]->state != FTDM_CHANNEL_STATE_DOWN) {
|
||||
ftdm_set_state(span->channels[j], FTDM_CHANNEL_STATE_RESTART);
|
||||
}
|
||||
state_advance(span->channels[j]);
|
||||
ftdm_channel_advance_states(span->channels[j]);
|
||||
ftdm_mutex_unlock(span->channels[j]->mutex);
|
||||
}
|
||||
}
|
||||
@@ -1695,7 +1681,7 @@ static __inline__ void check_state(ftdm_span_t *span)
|
||||
* but without taking the chan out of the queue, so check th
|
||||
* flag before advancing the state */
|
||||
ftdm_mutex_lock(ftdmchan->mutex);
|
||||
state_advance(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
ftdm_mutex_unlock(ftdmchan->mutex);
|
||||
}
|
||||
}
|
||||
@@ -2478,7 +2464,7 @@ static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change)
|
||||
sig.span_id = ftdmchan->span_id;
|
||||
sig.channel = ftdmchan;
|
||||
sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
|
||||
sig.raw_data = &status;
|
||||
sig.ev_data.sigstatus.status = status;
|
||||
ftdm_span_send_signal(ftdmchan->span, &sig);
|
||||
return;
|
||||
}
|
||||
@@ -2687,6 +2673,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
|
||||
span->get_span_sig_status = sangoma_boost_get_span_sig_status;
|
||||
span->set_span_sig_status = sangoma_boost_set_span_sig_status;
|
||||
span->state_map = &boost_state_map;
|
||||
span->state_processor = state_advance;
|
||||
sangoma_boost_data->mcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
|
||||
sangoma_boost_data->pcon.debuglevel = FTDM_LOG_LEVEL_DEBUG;
|
||||
ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#if HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
@@ -40,11 +40,12 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""C:\Program Files\libsng_isdn\include";"C:\Program Files\libsng_isdn\include\sng_isdn";../../include;"C:\Program Files\Sangoma\include""
|
||||
AdditionalIncludeDirectories=""C:\Program Files\sangoma\sng_isdn\include";../../include;"C:\Program Files\Sangoma\include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
|
||||
MinimalRebuild="true"
|
||||
ExceptionHandling="0"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
@@ -63,7 +64,7 @@
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories=""$(OutDir)";"C:\Program Files\libsng_isdn\lib";"C:\Program Files\Sangoma\api\lib\x86""
|
||||
AdditionalLibraryDirectories=""$(OutDir)";"C:\Program Files\sangoma\sng_isdn\lib";"C:\Program Files\Sangoma\api\lib\x86""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
RandomizedBaseAddress="1"
|
||||
@@ -116,10 +117,11 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""C:\Program Files\sangoma\sng_isdn\include";../../include;"C:\Program Files\Sangoma\include""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
@@ -136,7 +138,9 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="freetdm.lib libsng_isdn.lib"
|
||||
LinkIncremental="2"
|
||||
AdditionalLibraryDirectories=""$(OutDir)";"C:\Program Files\sangoma\sng_isdn\lib";"C:\Program Files\Sangoma\api\lib\x86""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<ExceptionHandling>
|
||||
@@ -95,10 +95,11 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
@@ -110,7 +111,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ExceptionHandling>
|
||||
</ExceptionHandling>
|
||||
@@ -119,6 +120,7 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
@@ -135,11 +137,13 @@
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<Optimization>Disabled</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -147,23 +151,27 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\sangoma\sng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\sangoma\sng_isdn\include;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<AdditionalDependencies>freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -46,10 +46,9 @@ static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
|
||||
static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
|
||||
|
||||
ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
|
||||
static void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan);
|
||||
static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span);
|
||||
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event);
|
||||
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
|
||||
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
|
||||
static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
|
||||
static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
|
||||
static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
|
||||
@@ -270,13 +269,6 @@ ftdm_state_map_t sangoma_isdn_state_map = {
|
||||
}
|
||||
};
|
||||
|
||||
static __inline__ void ftdm_sangoma_isdn_advance_chan_states(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_sangoma_isdn_process_state_change(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
|
||||
{
|
||||
sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
|
||||
@@ -457,7 +449,7 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
|
||||
while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
|
||||
/* double check that this channel has a state change pending */
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
|
||||
@@ -470,11 +462,11 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
|
||||
/* twiddle */
|
||||
break;
|
||||
case FTDM_FAIL:
|
||||
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name);
|
||||
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name);
|
||||
ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -536,7 +528,7 @@ ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisd
|
||||
break;
|
||||
}
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
return ftdmchan;
|
||||
}
|
||||
|
||||
@@ -600,13 +592,14 @@ static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_ev
|
||||
sngisdn_process_rst_ind(sngisdn_event);
|
||||
break;
|
||||
}
|
||||
if(ftdmchan != NULL) {
|
||||
ftdm_sangoma_isdn_advance_chan_states(ftdmchan);
|
||||
if (ftdmchan != NULL) {
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
}
|
||||
}
|
||||
|
||||
static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
|
||||
/* this function is called with the channel already locked by the core */
|
||||
static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
|
||||
{
|
||||
ftdm_sigmsg_t sigev;
|
||||
ftdm_channel_state_t initial_state;
|
||||
@@ -618,13 +611,12 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
|
||||
sigev.span_id = ftdmchan->span_id;
|
||||
sigev.channel = ftdmchan;
|
||||
|
||||
/*first lock the channel*/
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
/*clear the state change flag...since we might be setting a new state*/
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
/* Acknowledge the state change */
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
#ifdef FTDM_DEBUG_CHAN_MEMORY
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
|
||||
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ)==0, "Failed to mprotect");
|
||||
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ) == 0, "Failed to mprotect");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -879,11 +871,10 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
|
||||
}
|
||||
#ifdef FTDM_DEBUG_CHAN_MEMORY
|
||||
if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
|
||||
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE)==0, "Failed to mprotect");
|
||||
ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE) == 0, "Failed to mprotect");
|
||||
}
|
||||
#endif
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
return;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
|
||||
@@ -1098,6 +1089,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
|
||||
span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
|
||||
span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
|
||||
span->state_map = &sangoma_isdn_state_map;
|
||||
span->state_processor = ftdm_sangoma_isdn_process_state_change;
|
||||
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);
|
||||
|
||||
@@ -137,8 +137,9 @@ void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
|
||||
ftdm_assert(raw_data, "Failed to malloc");
|
||||
|
||||
memcpy(raw_data, data, data_len);
|
||||
sigev.raw_data = raw_data;
|
||||
sigev.raw_data_len = data_len;
|
||||
sigev.raw.data = raw_data;
|
||||
sigev.raw.len = data_len;
|
||||
sigev.raw.autofree = 1;
|
||||
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
|
||||
}
|
||||
|
||||
@@ -250,8 +251,9 @@ void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t d
|
||||
ftdm_assert(raw_data, "Failed to malloc");
|
||||
|
||||
memcpy(raw_data, data, data_len);
|
||||
sigev.raw_data = raw_data;
|
||||
sigev.raw_data_len = data_len;
|
||||
sigev.raw.data = raw_data;
|
||||
sigev.raw.len = data_len;
|
||||
sigev.raw.autofree = 1;
|
||||
ftdm_span_send_signal(signal_data->ftdm_span, &sigev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ ftdm_sngss7_data_t g_ftdm_sngss7_data;
|
||||
|
||||
/* PROTOTYPES *****************************************************************/
|
||||
static void *ftdm_sangoma_ss7_run (ftdm_thread_t * me, void *obj);
|
||||
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
|
||||
static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_event);
|
||||
|
||||
static ftdm_status_t ftdm_sangoma_ss7_stop (ftdm_span_t * span);
|
||||
@@ -308,9 +307,7 @@ static void *ftdm_sangoma_ss7_run(ftdm_thread_t * me, void *obj)
|
||||
ftdm_mutex_lock(ftdmchan->mutex);
|
||||
|
||||
/* process state changes for this channel until they are all done */
|
||||
while (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_sangoma_ss7_process_state_change (ftdmchan);
|
||||
}
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
/* unlock the channel */
|
||||
ftdm_mutex_unlock (ftdmchan->mutex);
|
||||
@@ -403,9 +400,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
||||
ftdm_mutex_lock(ftdmchan->mutex);
|
||||
|
||||
/* while there's a state change present on this channel process it */
|
||||
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_sangoma_ss7_process_state_change(ftdmchan);
|
||||
}
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
/* figure out the type of event and send it to the right handler */
|
||||
switch (sngss7_event->event_id) {
|
||||
@@ -468,9 +463,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
||||
} /* switch (sngss7_event->event_id) */
|
||||
|
||||
/* while there's a state change present on this channel process it */
|
||||
while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
|
||||
ftdm_sangoma_ss7_process_state_change(ftdmchan);
|
||||
}
|
||||
ftdm_channel_advance_states(ftdmchan);
|
||||
|
||||
/* unlock the channel */
|
||||
ftdm_mutex_unlock(ftdmchan->mutex);
|
||||
@@ -479,7 +472,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
|
||||
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
|
||||
{
|
||||
sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;
|
||||
sng_isup_inf_t *isup_intf = NULL;
|
||||
@@ -495,7 +488,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan)
|
||||
SS7_DEBUG_CHAN(ftdmchan, "ftmod_sangoma_ss7 processing state %s\n", ftdm_channel_state2str (ftdmchan->state));
|
||||
|
||||
/* clear the state change flag...since we might be setting a new state */
|
||||
ftdm_clear_flag (ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
|
||||
ftdm_channel_complete_state(ftdmchan);
|
||||
|
||||
/*check what state we are supposed to be in */
|
||||
switch (ftdmchan->state) {
|
||||
@@ -1212,7 +1205,7 @@ suspend_goto_restart:
|
||||
/**************************************************************************/
|
||||
}/*switch (ftdmchan->state) */
|
||||
|
||||
return;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -1476,6 +1469,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_ss7_span_config)
|
||||
span->get_channel_sig_status = ftdm_sangoma_ss7_get_sig_status;
|
||||
span->set_channel_sig_status = ftdm_sangoma_ss7_set_sig_status;
|
||||
span->state_map = &sangoma_ss7_state_map;
|
||||
span->state_processor = ftdm_sangoma_ss7_process_state_change;
|
||||
span->signal_data = ss7_span_info;
|
||||
|
||||
/* set the flag to indicate that this span uses channel state change queues */
|
||||
|
||||
@@ -452,7 +452,7 @@ extern int cmbLinkSetId;
|
||||
|
||||
/* PROTOTYPES *****************************************************************/
|
||||
/* in ftmod_sangoma_ss7_main.c */
|
||||
void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
|
||||
ftdm_status_t ftdm_sangoma_ss7_process_state_change (ftdm_channel_t *ftdmchan);
|
||||
|
||||
/* in ftmod_sangoma_ss7_logger.c */
|
||||
void handle_sng_log(uint8_t level, char *fmt,...);
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -127,7 +127,7 @@
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -148,7 +148,7 @@
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -174,7 +174,7 @@
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>freetdm.lib;libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>libsangoma.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
@@ -784,17 +784,27 @@ static FIO_COMMAND_FUNCTION(wanpipe_command)
|
||||
err = sangoma_set_tx_queue_sz(ftdmchan->sockfd, &tdm_api, queue_size);
|
||||
}
|
||||
break;
|
||||
case FTDM_COMMAND_SET_POLARITY:
|
||||
{
|
||||
ftdm_polarity_t polarity = FTDM_COMMAND_OBJ_INT;
|
||||
err = sangoma_tdm_set_polarity(ftdmchan->sockfd, &tdm_api, polarity);
|
||||
if (!err) {
|
||||
ftdmchan->polarity = polarity;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = FTDM_NOTIMPL;
|
||||
break;
|
||||
};
|
||||
|
||||
if (err) {
|
||||
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
|
||||
int myerrno = errno;
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Wanpipe failed to execute command %d: %s\n", command, strerror(myerrno));
|
||||
errno = myerrno;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1224,6 +1234,131 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Process an event in a channel and set it's OOB event id. The channel must be locked.
|
||||
* \param fchan Channel in which event occured
|
||||
* \param event_id Pointer where we save the OOB event id
|
||||
* \param tdm_api Wanpipe tdm struct that contain the event
|
||||
* \return FTDM_SUCCESS or FTDM_FAIL
|
||||
*/
|
||||
static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, wanpipe_tdm_api_t *tdm_api)
|
||||
{
|
||||
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_type) {
|
||||
case WP_API_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_API_EVENT_RXHOOK:
|
||||
{
|
||||
if (fchan->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(fchan, FTDM_CHANNEL_FLASH)) {
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
|
||||
*event_id = FTDM_OOB_FLASH;
|
||||
goto event;
|
||||
} else {
|
||||
ftdm_set_flag(fchan, FTDM_CHANNEL_WINK);
|
||||
}
|
||||
} else {
|
||||
if (ftdm_test_flag(fchan, FTDM_CHANNEL_WINK)) {
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_WINK);
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_FLASH);
|
||||
*event_id = FTDM_OOB_WINK;
|
||||
goto event;
|
||||
} else {
|
||||
ftdm_set_flag(fchan, FTDM_CHANNEL_FLASH);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
ftdm_status_t status;
|
||||
wanpipe_tdm_api_t onhook_tdm_api;
|
||||
memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
|
||||
status = sangoma_tdm_txsig_onhook(fchan->sockfd, &onhook_tdm_api);
|
||||
if (status) {
|
||||
snprintf(fchan->last_error, sizeof(fchan->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_API_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_API_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_API_EVENT_RBS:
|
||||
{
|
||||
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
|
||||
fchan->rx_cas_bits = wanpipe_swap_bits(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
|
||||
}
|
||||
break;
|
||||
case WP_API_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(fchan, 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(fchan, FTDM_CHANNEL_MUTE);
|
||||
}
|
||||
|
||||
if (tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_MUTE);
|
||||
if (ftdm_test_flag(fchan, FTDM_CHANNEL_INUSE)) {
|
||||
ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
|
||||
ftdm_channel_queue_dtmf(fchan, tmp_dtmf);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WP_API_EVENT_ALARM:
|
||||
{
|
||||
ftdm_log_chan(fchan, 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;
|
||||
case WP_API_EVENT_POLARITY_REVERSE:
|
||||
{
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Got polarity reverse\n");
|
||||
*event_id = FTDM_OOB_POLARITY_REVERSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(fchan, 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:
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves an event from a wanpipe channel
|
||||
* \param channel Channel to retrieve event from
|
||||
@@ -1237,8 +1372,9 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
ftdm_span_t *span = ftdmchan->span;
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT))
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
|
||||
}
|
||||
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
|
||||
@@ -1249,115 +1385,11 @@ FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
|
||||
}
|
||||
|
||||
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;
|
||||
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
event:
|
||||
|
||||
ftdmchan->last_event_time = 0;
|
||||
span->event_header.e_type = FTDM_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
@@ -1419,114 +1451,15 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
ftdm_log_chan(span->channels[i], 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 (span->channels[i]->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(span->channels[i], FTDM_CHANNEL_FLASH)) {
|
||||
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
|
||||
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
|
||||
event_id = FTDM_OOB_FLASH;
|
||||
goto event;
|
||||
} else {
|
||||
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
|
||||
}
|
||||
} else {
|
||||
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
|
||||
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
|
||||
ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
|
||||
event_id = FTDM_OOB_WINK;
|
||||
goto event;
|
||||
} else {
|
||||
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
int err;
|
||||
ftdm_channel_t *ftdmchan = span->channels[i];
|
||||
err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
|
||||
if (err) {
|
||||
snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
event_id = 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;
|
||||
span->channels[i]->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;
|
||||
ftdm_channel_lock(ftdmchan);
|
||||
if ((wanpipe_channel_process_event(ftdmchan, &event_id, &tdm_api)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process events from channel\n");
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_channel_unlock(ftdmchan);
|
||||
|
||||
event:
|
||||
|
||||
@@ -1538,9 +1471,7 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return FTDM_FAIL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,42 +52,48 @@ static struct {
|
||||
float txgain;
|
||||
} zt_globals;
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
typedef unsigned long ioctlcmd;
|
||||
#else
|
||||
typedef int ioctlcmd;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief General IOCTL codes
|
||||
*/
|
||||
struct ioctl_codes {
|
||||
int GET_BLOCKSIZE;
|
||||
int SET_BLOCKSIZE;
|
||||
int FLUSH;
|
||||
int SYNC;
|
||||
int GET_PARAMS;
|
||||
int SET_PARAMS;
|
||||
int HOOK;
|
||||
int GETEVENT;
|
||||
int IOMUX;
|
||||
int SPANSTAT;
|
||||
int MAINT;
|
||||
int GETCONF;
|
||||
int SETCONF;
|
||||
int CONFLINK;
|
||||
int CONFDIAG;
|
||||
int GETGAINS;
|
||||
int SETGAINS;
|
||||
int SPANCONFIG;
|
||||
int CHANCONFIG;
|
||||
int SET_BUFINFO;
|
||||
int GET_BUFINFO;
|
||||
int AUDIOMODE;
|
||||
int ECHOCANCEL;
|
||||
int HDLCRAWMODE;
|
||||
int HDLCFCSMODE;
|
||||
int SPECIFY;
|
||||
int SETLAW;
|
||||
int SETLINEAR;
|
||||
int GETCONFMUTE;
|
||||
int ECHOTRAIN;
|
||||
int SETTXBITS;
|
||||
int GETRXBITS;
|
||||
ioctlcmd GET_BLOCKSIZE;
|
||||
ioctlcmd SET_BLOCKSIZE;
|
||||
ioctlcmd FLUSH;
|
||||
ioctlcmd SYNC;
|
||||
ioctlcmd GET_PARAMS;
|
||||
ioctlcmd SET_PARAMS;
|
||||
ioctlcmd HOOK;
|
||||
ioctlcmd GETEVENT;
|
||||
ioctlcmd IOMUX;
|
||||
ioctlcmd SPANSTAT;
|
||||
ioctlcmd MAINT;
|
||||
ioctlcmd GETCONF;
|
||||
ioctlcmd SETCONF;
|
||||
ioctlcmd CONFLINK;
|
||||
ioctlcmd CONFDIAG;
|
||||
ioctlcmd GETGAINS;
|
||||
ioctlcmd SETGAINS;
|
||||
ioctlcmd SPANCONFIG;
|
||||
ioctlcmd CHANCONFIG;
|
||||
ioctlcmd SET_BUFINFO;
|
||||
ioctlcmd GET_BUFINFO;
|
||||
ioctlcmd AUDIOMODE;
|
||||
ioctlcmd ECHOCANCEL;
|
||||
ioctlcmd HDLCRAWMODE;
|
||||
ioctlcmd HDLCFCSMODE;
|
||||
ioctlcmd SPECIFY;
|
||||
ioctlcmd SETLAW;
|
||||
ioctlcmd SETLINEAR;
|
||||
ioctlcmd GETCONFMUTE;
|
||||
ioctlcmd ECHOTRAIN;
|
||||
ioctlcmd SETTXBITS;
|
||||
ioctlcmd GETRXBITS;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,6 +187,7 @@ static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
|
||||
|
||||
FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
|
||||
FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
|
||||
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event);
|
||||
|
||||
/**
|
||||
* \brief Initialises codec, and rx/tx gains
|
||||
@@ -985,6 +992,124 @@ FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
|
||||
return k ? FTDM_SUCCESS : FTDM_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked.
|
||||
* \param fchan Channel to retrieve event from
|
||||
* \param event_id Pointer to OOB event id
|
||||
* \param zt_event_id Zaptel event id
|
||||
* \return FTDM_SUCCESS or FTDM_FAIL
|
||||
*/
|
||||
static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
|
||||
{
|
||||
switch(zt_event_id) {
|
||||
case ZT_EVENT_RINGEROFF:
|
||||
{
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGERON:
|
||||
{
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGBEGIN:
|
||||
{
|
||||
*event_id = FTDM_OOB_RING_START;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_ONHOOK:
|
||||
{
|
||||
*event_id = FTDM_OOB_ONHOOK;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_WINKFLASH:
|
||||
{
|
||||
if (fchan->state == FTDM_CHANNEL_STATE_DOWN || fchan->state == FTDM_CHANNEL_STATE_DIALING) {
|
||||
*event_id = FTDM_OOB_WINK;
|
||||
} else {
|
||||
*event_id = FTDM_OOB_FLASH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGOFFHOOK:
|
||||
{
|
||||
if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
|
||||
ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
|
||||
*event_id = FTDM_OOB_OFFHOOK;
|
||||
} else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
|
||||
*event_id = FTDM_OOB_RING_START;
|
||||
} else {
|
||||
*event_id = FTDM_OOB_NOOP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_ALARM:
|
||||
{
|
||||
*event_id = FTDM_OOB_ALARM_TRAP;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_NOALARM:
|
||||
{
|
||||
*event_id = FTDM_OOB_ALARM_CLEAR;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_BITSCHANGED:
|
||||
{
|
||||
*event_id = FTDM_OOB_CAS_BITS_CHANGE;
|
||||
int bits = 0;
|
||||
int err = ioctl(fchan->sockfd, codes.GETRXBITS, &bits);
|
||||
if (err) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
fchan->rx_cas_bits = bits;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
|
||||
*event_id = FTDM_OOB_INVALID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves an event from a ftdm channel
|
||||
* \param ftdmchan Channel to retrieve event from
|
||||
* \param event FreeTDM event to return
|
||||
* \return Success or failure
|
||||
*/
|
||||
FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
|
||||
{
|
||||
uint32_t event_id = FTDM_OOB_INVALID;
|
||||
zt_event_t zt_event_id = 0;
|
||||
ftdm_span_t *span = ftdmchan->span;
|
||||
|
||||
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
|
||||
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
|
||||
}
|
||||
|
||||
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n",
|
||||
strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
/* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */
|
||||
if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
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 ftdmtel span
|
||||
* \param span Span to retrieve event from
|
||||
@@ -997,91 +1122,29 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
||||
zt_event_t zt_event_id = 0;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
|
||||
ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
|
||||
if (ioctl(span->channels[i]->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
switch(zt_event_id) {
|
||||
case ZT_EVENT_RINGEROFF:
|
||||
{
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGERON:
|
||||
{
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGBEGIN:
|
||||
{
|
||||
event_id = FTDM_OOB_RING_START;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_ONHOOK:
|
||||
{
|
||||
event_id = FTDM_OOB_ONHOOK;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_WINKFLASH:
|
||||
{
|
||||
if (span->channels[i]->state == FTDM_CHANNEL_STATE_DOWN || span->channels[i]->state == FTDM_CHANNEL_STATE_DIALING) {
|
||||
event_id = FTDM_OOB_WINK;
|
||||
} else {
|
||||
event_id = FTDM_OOB_FLASH;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_RINGOFFHOOK:
|
||||
{
|
||||
if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS || (span->channels[i]->type == FTDM_CHAN_TYPE_EM && span->channels[i]->state != FTDM_CHANNEL_STATE_UP)) {
|
||||
ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
|
||||
event_id = FTDM_OOB_OFFHOOK;
|
||||
} else if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
|
||||
event_id = FTDM_OOB_RING_START;
|
||||
} else {
|
||||
event_id = FTDM_OOB_NOOP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_ALARM:
|
||||
{
|
||||
event_id = FTDM_OOB_ALARM_TRAP;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_NOALARM:
|
||||
{
|
||||
event_id = FTDM_OOB_ALARM_CLEAR;
|
||||
}
|
||||
break;
|
||||
case ZT_EVENT_BITSCHANGED:
|
||||
{
|
||||
event_id = FTDM_OOB_CAS_BITS_CHANGE;
|
||||
int bits = 0;
|
||||
int err = ioctl(span->channels[i]->sockfd, codes.GETRXBITS, &bits);
|
||||
if (err) {
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
span->channels[i]->rx_cas_bits = bits;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ftdm_log(FTDM_LOG_WARNING, "Unhandled event %d for %d:%d\n", zt_event_id, span->span_id, i);
|
||||
event_id = FTDM_OOB_INVALID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
span->channels[i]->last_event_time = 0;
|
||||
span->event_header.e_type = FTDM_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
span->event_header.channel = span->channels[i];
|
||||
*event = &span->event_header;
|
||||
return FTDM_SUCCESS;
|
||||
ftdm_channel_t *fchan = span->channels[i];
|
||||
if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) {
|
||||
ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT);
|
||||
}
|
||||
if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
ftdm_channel_lock(fchan);
|
||||
if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
|
||||
ftdm_channel_unlock(fchan);
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
ftdm_channel_unlock(fchan);
|
||||
|
||||
fchan->last_event_time = 0;
|
||||
span->event_header.e_type = FTDM_EVENT_OOB;
|
||||
span->event_header.enum_id = event_id;
|
||||
span->event_header.channel = fchan;
|
||||
*event = &span->event_header;
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
return FTDM_FAIL;
|
||||
@@ -1146,6 +1209,7 @@ static FIO_WRITE_FUNCTION(zt_write)
|
||||
bytes += 2;
|
||||
}
|
||||
|
||||
tryagain:
|
||||
w = write(ftdmchan->sockfd, data, bytes);
|
||||
|
||||
if (w >= 0) {
|
||||
@@ -1153,6 +1217,17 @@ static FIO_WRITE_FUNCTION(zt_write)
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
if (errno == ELAST) {
|
||||
zt_event_t zt_event_id = 0;
|
||||
if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
/* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
|
||||
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
return FTDM_FAIL;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user