(OPENZAP-7) inital checkin of E&M support from John Wehle
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@561 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
parent
b46ce732b2
commit
3479ce917e
|
@ -181,7 +181,7 @@ PIKA_LIB=$(shell ls /usr/lib/libpikahmpapi.so 2>/dev/null)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
all: $(MYLIB) analogmod isdnmod boostmod ztmod wpmod
|
||||
all: $(MYLIB) analogmod analog_emmod isdnmod boostmod ztmod wpmod
|
||||
|
||||
$(MYLIB): $(OBJS) $(HEADERS) $(SOURCES)
|
||||
$(LINK) $(SOLINK) -o $(MYLIB) $(OBJS) $(ADD_OBJS) $(LIBS)
|
||||
|
@ -274,6 +274,10 @@ $(SRC)/ozmod/ozmod_analog/ozmod_analog.$(DYNAMIC_LIB_EXTEN): $(MYLIB) $(SRC)/ozm
|
|||
$(LINK) $(SOLINK) $(SRC)/ozmod/ozmod_analog/ozmod_analog.o $(MYLIB) -rpath $(libdir)
|
||||
analogmod: $(SRC)/ozmod/ozmod_analog/ozmod_analog.$(DYNAMIC_LIB_EXTEN)
|
||||
|
||||
$(SRC)/ozmod/ozmod_analog_em/ozmod_analog_em.$(DYNAMIC_LIB_EXTEN): $(MYLIB) $(ANALOG_EM_OBJS) $(SRC)/ozmod/ozmod_analog_em/ozmod_analog_em.o
|
||||
$(LINK) $(SOLINK) $(SRC)/ozmod/ozmod_analog_em/ozmod_analog_em.o $(MYLIB) -rpath $(libdir)
|
||||
analog_emmod: $(SRC)/ozmod/ozmod_analog_em/ozmod_analog_em.$(DYNAMIC_LIB_EXTEN)
|
||||
|
||||
$(SRC)/ozmod/ozmod_ss7_boost/ozmod_ss7_boost.$(DYNAMIC_LIB_EXTEN): $(MYLIB) $(BOOST_OBJS)
|
||||
$(LINK) $(SOLINK) $(BOOST_OBJS) $(MYLIB) -rpath $(libdir)
|
||||
boostmod: $(SRC)/ozmod/ozmod_ss7_boost/ozmod_ss7_boost.$(DYNAMIC_LIB_EXTEN)
|
||||
|
|
|
@ -417,6 +417,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
|
|||
|
||||
switch (tech_pvt->zchan->type) {
|
||||
case ZAP_CHAN_TYPE_FXO:
|
||||
case ZAP_CHAN_TYPE_EM:
|
||||
{
|
||||
|
||||
zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
|
||||
|
@ -806,6 +807,7 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
|
|||
|
||||
switch (tech_pvt->zchan->type) {
|
||||
case ZAP_CHAN_TYPE_FXS:
|
||||
case ZAP_CHAN_TYPE_EM:
|
||||
status = channel_receive_message_fxs(session, msg);
|
||||
break;
|
||||
case ZAP_CHAN_TYPE_FXO:
|
||||
|
@ -1445,6 +1447,7 @@ static ZIO_SIGNAL_CB_FUNCTION(on_analog_signal)
|
|||
|
||||
switch (sigmsg->channel->type) {
|
||||
case ZAP_CHAN_TYPE_FXO:
|
||||
case ZAP_CHAN_TYPE_EM:
|
||||
{
|
||||
status = on_fxo_signal(sigmsg);
|
||||
}
|
||||
|
@ -1616,6 +1619,100 @@ static switch_status_t load_config(void)
|
|||
}
|
||||
}
|
||||
|
||||
if ((spans = switch_xml_child(cfg, "analog_em_spans"))) {
|
||||
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
|
||||
char *id = (char *) switch_xml_attr_soft(myspan, "id");
|
||||
char *context = "default";
|
||||
char *dialplan = "XML";
|
||||
char *tonegroup = NULL;
|
||||
char *digit_timeout = NULL;
|
||||
char *max_digits = NULL;
|
||||
char *dial_regex = NULL;
|
||||
char *hold_music = NULL;
|
||||
char *fail_dial_regex = NULL;
|
||||
uint32_t span_id = 0, to = 0, max = 0;
|
||||
zap_span_t *span = NULL;
|
||||
analog_option_t analog_options = ANALOG_OPTION_NONE;
|
||||
|
||||
for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
|
||||
char *var = (char *) switch_xml_attr_soft(param, "name");
|
||||
char *val = (char *) switch_xml_attr_soft(param, "value");
|
||||
|
||||
if (!strcasecmp(var, "tonegroup")) {
|
||||
tonegroup = val;
|
||||
} else if (!strcasecmp(var, "digit_timeout") || !strcasecmp(var, "digit-timeout")) {
|
||||
digit_timeout = val;
|
||||
} else if (!strcasecmp(var, "context")) {
|
||||
context = val;
|
||||
} else if (!strcasecmp(var, "dialplan")) {
|
||||
dialplan = val;
|
||||
} else if (!strcasecmp(var, "dial-regex")) {
|
||||
dial_regex = val;
|
||||
} else if (!strcasecmp(var, "fail-dial-regex")) {
|
||||
fail_dial_regex = val;
|
||||
} else if (!strcasecmp(var, "hold-music")) {
|
||||
hold_music = val;
|
||||
} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
|
||||
max_digits = val;
|
||||
} else if (!strcasecmp(var, "enable-analog-option")) {
|
||||
analog_options = enable_analog_option(val, analog_options);
|
||||
}
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
span_id = atoi(id);
|
||||
|
||||
if (!tonegroup) {
|
||||
tonegroup = "us";
|
||||
}
|
||||
|
||||
if (digit_timeout) {
|
||||
to = atoi(digit_timeout);
|
||||
}
|
||||
|
||||
if (max_digits) {
|
||||
max = atoi(max_digits);
|
||||
}
|
||||
|
||||
if (zap_span_find(span_id, &span) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span %d\n", span_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zap_configure_span("analog_em", span, on_analog_signal,
|
||||
"tonemap", tonegroup,
|
||||
"digit_timeout", &to,
|
||||
"max_dialstr", &max,
|
||||
TAG_END) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d\n", span_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
SPAN_CONFIG[span->span_id].span = span;
|
||||
switch_set_string(SPAN_CONFIG[span->span_id].context, context);
|
||||
switch_set_string(SPAN_CONFIG[span->span_id].dialplan, dialplan);
|
||||
SPAN_CONFIG[span->span_id].analog_options = analog_options | globals.analog_options;
|
||||
|
||||
if (dial_regex) {
|
||||
switch_set_string(SPAN_CONFIG[span->span_id].dial_regex, dial_regex);
|
||||
}
|
||||
|
||||
if (fail_dial_regex) {
|
||||
switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
|
||||
}
|
||||
|
||||
if (hold_music) {
|
||||
switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
|
||||
}
|
||||
switch_copy_string(SPAN_CONFIG[span->span_id].type, "analog_em", sizeof(SPAN_CONFIG[span->span_id].type));
|
||||
zap_span_start(span);
|
||||
}
|
||||
}
|
||||
|
||||
if ((spans = switch_xml_child(cfg, "pri_spans"))) {
|
||||
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
|
||||
char *id = (char *) switch_xml_attr_soft(myspan, "id");
|
||||
|
|
|
@ -123,18 +123,20 @@ typedef enum {
|
|||
ZAP_TRUNK_BRI_PTMP,
|
||||
ZAP_TRUNK_FXO,
|
||||
ZAP_TRUNK_FXS,
|
||||
ZAP_TRUNK_EM,
|
||||
ZAP_TRUNK_NONE
|
||||
} zap_trunk_type_t;
|
||||
#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "NONE"
|
||||
#define TRUNK_STRINGS "E1", "T1", "J1", "BRI", "BRI_PTMP", "FXO", "FXS", "EM", "NONE"
|
||||
ZAP_STR2ENUM_P(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t)
|
||||
|
||||
typedef enum {
|
||||
ZAP_ANALOG_START_KEWL,
|
||||
ZAP_ANALOG_START_LOOP,
|
||||
ZAP_ANALOG_START_GROUND,
|
||||
ZAP_ANALOG_START_WINK,
|
||||
ZAP_ANALOG_START_NA
|
||||
} zap_analog_start_type_t;
|
||||
#define START_TYPE_STRINGS "KEWL", "LOOP", "GROUND", "NA"
|
||||
#define START_TYPE_STRINGS "KEWL", "LOOP", "GROUND", "WINK", "NA"
|
||||
ZAP_STR2ENUM_P(zap_str2zap_analog_start_type, zap_analog_start_type2str, zap_analog_start_type_t)
|
||||
|
||||
typedef enum {
|
||||
|
@ -284,10 +286,11 @@ typedef enum {
|
|||
ZAP_CHAN_TYPE_DQ931,
|
||||
ZAP_CHAN_TYPE_FXS,
|
||||
ZAP_CHAN_TYPE_FXO,
|
||||
ZAP_CHAN_TYPE_EM,
|
||||
ZAP_CHAN_TYPE_COUNT
|
||||
} zap_chan_type_t;
|
||||
|
||||
#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "INVALID"
|
||||
#define CHAN_TYPE_STRINGS "B", "DQ921", "DQ931", "FXS", "FXO", "EM", "INVALID"
|
||||
ZAP_STR2ENUM_P(zap_str2zap_chan_type, zap_chan_type2str, zap_chan_type_t)
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -0,0 +1,663 @@
|
|||
/*
|
||||
* Copyright (c) 2008, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* John Wehle (john@feith.com)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "openzap.h"
|
||||
#include "zap_analog_em.h"
|
||||
|
||||
#ifndef localtime_r
|
||||
struct tm * localtime_r(const time_t *clock, struct tm *result);
|
||||
#endif
|
||||
|
||||
static void *zap_analog_em_channel_run(zap_thread_t *me, void *obj);
|
||||
|
||||
static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
|
||||
{
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
|
||||
zap_channel_clear_needed_tones(zchan);
|
||||
zap_channel_clear_detected_tones(zchan);
|
||||
|
||||
zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
|
||||
|
||||
zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
|
||||
zap_channel_command(zchan, ZAP_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
|
||||
zap_thread_create_detached(zap_analog_em_channel_run, zchan);
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
static zap_status_t zap_analog_em_start(zap_span_t *span)
|
||||
{
|
||||
zap_analog_em_data_t *analog_data = span->signal_data;
|
||||
zap_set_flag(analog_data, ZAP_ANALOG_EM_RUNNING);
|
||||
return zap_thread_create_detached(zap_analog_em_run, span);
|
||||
}
|
||||
|
||||
static ZIO_SIG_CONFIGURE_FUNCTION(zap_analog_em_configure_span)
|
||||
//zap_status_t zap_analog_em_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb)
|
||||
{
|
||||
zap_analog_em_data_t *analog_data;
|
||||
const char *tonemap = "us";
|
||||
uint32_t digit_timeout = 10;
|
||||
uint32_t max_dialstr = 11;
|
||||
const char *var, *val;
|
||||
int *intval;
|
||||
|
||||
assert(sig_cb != NULL);
|
||||
|
||||
if (span->signal_type) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
analog_data = malloc(sizeof(*analog_data));
|
||||
assert(analog_data != NULL);
|
||||
memset(analog_data, 0, sizeof(*analog_data));
|
||||
|
||||
while((var = va_arg(ap, char *))) {
|
||||
if (!strcasecmp(var, "tonemap")) {
|
||||
if (!(val = va_arg(ap, char *))) {
|
||||
break;
|
||||
}
|
||||
tonemap = val;
|
||||
} else if (!strcasecmp(var, "digit_timeout")) {
|
||||
if (!(intval = va_arg(ap, int *))) {
|
||||
break;
|
||||
}
|
||||
digit_timeout = *intval;
|
||||
} else if (!strcasecmp(var, "max_dialstr")) {
|
||||
if (!(intval = va_arg(ap, int *))) {
|
||||
break;
|
||||
}
|
||||
max_dialstr = *intval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (digit_timeout < 2000 || digit_timeout > 10000) {
|
||||
digit_timeout = 2000;
|
||||
}
|
||||
|
||||
if (max_dialstr < 2 || max_dialstr > 20) {
|
||||
max_dialstr = 11;
|
||||
}
|
||||
|
||||
span->start = zap_analog_em_start;
|
||||
analog_data->digit_timeout = digit_timeout;
|
||||
analog_data->max_dialstr = max_dialstr;
|
||||
analog_data->sig_cb = sig_cb;
|
||||
span->signal_type = ZAP_SIGTYPE_ANALOG;
|
||||
span->signal_data = analog_data;
|
||||
span->outgoing_call = analog_em_outgoing_call;
|
||||
zap_span_load_tones(span, tonemap);
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
|
||||
{
|
||||
zap_buffer_t *dt_buffer = ts->user_data;
|
||||
int wrote;
|
||||
|
||||
if (!dt_buffer) {
|
||||
return -1;
|
||||
}
|
||||
wrote = teletone_mux_tones(ts, map);
|
||||
zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *zap_analog_em_channel_run(zap_thread_t *me, void *obj)
|
||||
{
|
||||
zap_channel_t *zchan = (zap_channel_t *) obj;
|
||||
zap_buffer_t *dt_buffer = NULL;
|
||||
teletone_generation_session_t ts;
|
||||
uint8_t frame[1024];
|
||||
zap_size_t len, rlen;
|
||||
zap_tone_type_t tt = ZAP_TONE_DTMF;
|
||||
char dtmf[128] = "";
|
||||
zap_size_t dtmf_offset = 0;
|
||||
zap_analog_em_data_t *analog_data = zchan->span->signal_data;
|
||||
zap_channel_t *closed_chan;
|
||||
uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
|
||||
zap_sigmsg_t sig;
|
||||
zap_status_t status;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
|
||||
|
||||
ts.buffer = NULL;
|
||||
|
||||
if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "OPEN ERROR [%s]\n", zchan->last_error);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "memory error!");
|
||||
zap_log(ZAP_LOG_ERROR, "MEM ERROR\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zap_channel_command(zchan, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "error initilizing tone detector!");
|
||||
zap_log(ZAP_LOG_ERROR, "TONE ERROR\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
zap_set_flag_locked(zchan, ZAP_CHANNEL_INTHREAD);
|
||||
teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
|
||||
ts.rate = 8000;
|
||||
#if 0
|
||||
ts.debug = 1;
|
||||
ts.debug_stream = stdout;
|
||||
#endif
|
||||
zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval);
|
||||
zap_buffer_set_loops(dt_buffer, -1);
|
||||
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sig.chan_id = zchan->chan_id;
|
||||
sig.span_id = zchan->span_id;
|
||||
sig.channel = zchan;
|
||||
|
||||
assert(interval != 0);
|
||||
|
||||
while (zap_running() && zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
|
||||
zap_wait_flag_t flags = ZAP_READ;
|
||||
zap_size_t dlen = 0;
|
||||
|
||||
len = sizeof(frame);
|
||||
|
||||
elapsed += interval;
|
||||
state_counter += interval;
|
||||
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_STATE_CHANGE)) {
|
||||
switch(zchan->state) {
|
||||
case ZAP_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
if (! zchan->needed_tones[ZAP_TONEMAP_RING]
|
||||
&& zap_test_flag(zchan, ZAP_CHANNEL_WINK)) {
|
||||
if (zap_strlen_zero(zchan->caller_data.ani.digits)) {
|
||||
zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani.digits) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
state_counter = 0;
|
||||
zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
|
||||
zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
|
||||
dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani.digits)) + 2000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (state_counter > dial_timeout) {
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_WINK)) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALTONE:
|
||||
{
|
||||
if (state_counter > 10000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_BUSY:
|
||||
{
|
||||
if (state_counter > 20000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_ATTN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_ATTN:
|
||||
{
|
||||
if (state_counter > 20000) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_HANGUP:
|
||||
{
|
||||
if (state_counter > 500) {
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) &&
|
||||
(zchan->last_state == ZAP_CHANNEL_STATE_RING || zchan->last_state == ZAP_CHANNEL_STATE_DIALTONE
|
||||
|| zchan->last_state >= ZAP_CHANNEL_STATE_IDLE)) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else {
|
||||
zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_UP:
|
||||
case ZAP_CHANNEL_STATE_IDLE:
|
||||
{
|
||||
zap_sleep(interval);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
zap_clear_flag_locked(zchan, ZAP_CHANNEL_STATE_CHANGE);
|
||||
zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
|
||||
zap_channel_complete_state(zchan);
|
||||
indicate = 0;
|
||||
state_counter = 0;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
|
||||
zchan->span_id, zchan->chan_id,
|
||||
zap_channel_state2str(zchan->state));
|
||||
switch(zchan->state) {
|
||||
case ZAP_CHANNEL_STATE_UP:
|
||||
{
|
||||
zap_channel_use(zchan);
|
||||
zap_channel_clear_needed_tones(zchan);
|
||||
zap_channel_flush_dtmf(zchan);
|
||||
|
||||
if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK)) {
|
||||
zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
|
||||
}
|
||||
|
||||
sig.event_id = ZAP_SIGEVENT_UP;
|
||||
|
||||
analog_data->sig_cb(&sig);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALING:
|
||||
{
|
||||
zap_channel_use(zchan);
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_IDLE:
|
||||
{
|
||||
zap_channel_use(zchan);
|
||||
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
|
||||
zap_set_string(zchan->caller_data.dnis.digits, zchan->chan_number);
|
||||
} else {
|
||||
zap_set_string(zchan->caller_data.dnis.digits, dtmf);
|
||||
}
|
||||
|
||||
sig.event_id = ZAP_SIGEVENT_START;
|
||||
|
||||
analog_data->sig_cb(&sig);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DOWN:
|
||||
{
|
||||
sig.event_id = ZAP_SIGEVENT_STOP;
|
||||
analog_data->sig_cb(&sig);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_DIALTONE:
|
||||
{
|
||||
memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
|
||||
*dtmf = '\0';
|
||||
dtmf_offset = 0;
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_DIAL]);
|
||||
indicate = 1;
|
||||
|
||||
zap_sleep(25);
|
||||
zap_channel_command(zchan, ZAP_COMMAND_OFFHOOK, NULL);
|
||||
zap_sleep(200);
|
||||
zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
|
||||
zap_sleep(50);
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_RING:
|
||||
{
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_RING]);
|
||||
indicate = 1;
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_BUSY:
|
||||
{
|
||||
zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
|
||||
indicate = 1;
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_CHANNEL_STATE_ATTN:
|
||||
{
|
||||
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
|
||||
zap_buffer_zero(dt_buffer);
|
||||
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
|
||||
indicate = 1;
|
||||
} else {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE || zchan->state == ZAP_CHANNEL_STATE_COLLECT) {
|
||||
if ((dlen = zap_channel_dequeue_dtmf(zchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
|
||||
|
||||
if (zchan->state == ZAP_CHANNEL_STATE_DIALTONE) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_COLLECT);
|
||||
collecting = 1;
|
||||
}
|
||||
dtmf_offset = strlen(dtmf);
|
||||
last_digit = elapsed;
|
||||
sig.event_id = ZAP_SIGEVENT_COLLECTED_DIGIT;
|
||||
sig.raw_data = dtmf;
|
||||
if (analog_data->sig_cb(&sig) == ZAP_BREAK) {
|
||||
collecting = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_IDLE);
|
||||
last_digit = 0;
|
||||
collecting = 0;
|
||||
}
|
||||
|
||||
if (zap_channel_wait(zchan, &flags, interval * 2) != ZAP_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(flags & ZAP_READ)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zap_channel_read(zchan, frame, &len) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "READ ERROR [%s]\n", zchan->last_error);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (zchan->detected_tones[0]) {
|
||||
zap_sigmsg_t sig;
|
||||
int i;
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sig.chan_id = zchan->chan_id;
|
||||
sig.span_id = zchan->span_id;
|
||||
sig.channel = zchan;
|
||||
sig.event_id = ZAP_SIGEVENT_TONE_DETECTED;
|
||||
|
||||
for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
|
||||
if (zchan->detected_tones[i]) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
|
||||
sig.raw_data = &i;
|
||||
if (analog_data->sig_cb) {
|
||||
analog_data->sig_cb(&sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zchan->detected_tones[ZAP_TONEMAP_BUSY] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
|
||||
zchan->detected_tones[ZAP_TONEMAP_ATTN]
|
||||
) {
|
||||
zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
|
||||
} else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
|
||||
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
|
||||
}
|
||||
|
||||
zap_channel_clear_detected_tones(zchan);
|
||||
}
|
||||
|
||||
if ((zchan->dtmf_buffer && zap_buffer_inuse(zchan->dtmf_buffer))) {
|
||||
rlen = len;
|
||||
memset(frame, 0, len);
|
||||
zap_channel_write(zchan, frame, sizeof(frame), &rlen);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!indicate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (zchan->effective_codec != ZAP_CODEC_SLIN) {
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
rlen = zap_buffer_read_loop(dt_buffer, frame, len);
|
||||
|
||||
if (zchan->effective_codec != ZAP_CODEC_SLIN) {
|
||||
zio_codec_t codec_func = NULL;
|
||||
|
||||
if (zchan->native_codec == ZAP_CODEC_ULAW) {
|
||||
codec_func = zio_slin2ulaw;
|
||||
} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
|
||||
codec_func = zio_slin2alaw;
|
||||
}
|
||||
|
||||
if (codec_func) {
|
||||
status = codec_func(frame, sizeof(frame), &rlen);
|
||||
} else {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
zap_channel_write(zchan, frame, sizeof(frame), &rlen);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
zap_channel_command(zchan, ZAP_COMMAND_ONHOOK, NULL);
|
||||
|
||||
closed_chan = zchan;
|
||||
zap_channel_close(&zchan);
|
||||
|
||||
zap_channel_command(closed_chan, ZAP_COMMAND_SET_NATIVE_CODEC, NULL);
|
||||
|
||||
if (ts.buffer) {
|
||||
teletone_destroy_session(&ts);
|
||||
}
|
||||
|
||||
if (dt_buffer) {
|
||||
zap_buffer_destroy(&dt_buffer);
|
||||
}
|
||||
|
||||
zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD);
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *event)
|
||||
{
|
||||
zap_sigmsg_t sig;
|
||||
int locked = 0;
|
||||
|
||||
memset(&sig, 0, sizeof(sig));
|
||||
sig.chan_id = event->channel->chan_id;
|
||||
sig.span_id = event->channel->span_id;
|
||||
sig.channel = event->channel;
|
||||
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n",
|
||||
zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, zap_channel_state2str(event->channel->state));
|
||||
|
||||
zap_mutex_lock(event->channel->mutex);
|
||||
locked++;
|
||||
|
||||
switch(event->enum_id) {
|
||||
case ZAP_OOB_ONHOOK:
|
||||
{
|
||||
if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case ZAP_OOB_OFFHOOK:
|
||||
{
|
||||
if (zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP);
|
||||
} else {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
|
||||
zap_mutex_unlock(event->channel->mutex);
|
||||
locked = 0;
|
||||
zap_thread_create_detached(zap_analog_em_channel_run, event->channel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZAP_OOB_WINK:
|
||||
{
|
||||
if (event->channel->state != ZAP_CHANNEL_STATE_DIALING) {
|
||||
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
|
||||
} else {
|
||||
zap_set_flag_locked(event->channel, ZAP_CHANNEL_WINK);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (locked) {
|
||||
zap_mutex_unlock(event->channel->mutex);
|
||||
}
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static void *zap_analog_em_run(zap_thread_t *me, void *obj)
|
||||
{
|
||||
zap_span_t *span = (zap_span_t *) obj;
|
||||
zap_analog_em_data_t *analog_data = span->signal_data;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG EM thread starting.\n");
|
||||
|
||||
while(zap_running() && zap_test_flag(analog_data, ZAP_ANALOG_EM_RUNNING)) {
|
||||
int waitms = 10;
|
||||
zap_status_t status;
|
||||
|
||||
status = zap_span_poll_event(span, waitms);
|
||||
|
||||
switch(status) {
|
||||
case ZAP_SUCCESS:
|
||||
{
|
||||
zap_event_t *event;
|
||||
while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
|
||||
if (event->enum_id == ZAP_OOB_NOOP) {
|
||||
continue;
|
||||
}
|
||||
if (process_event(span, event) != ZAP_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_FAIL:
|
||||
{
|
||||
zap_log(ZAP_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
zap_clear_flag(analog_data, ZAP_ANALOG_EM_RUNNING);
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "ANALOG EM thread ending.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static ZIO_SIG_LOAD_FUNCTION(zap_analog_em_init)
|
||||
{
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
zap_module_t zap_module = {
|
||||
"analog_em",
|
||||
NULL,
|
||||
NULL,
|
||||
zap_analog_em_init,
|
||||
zap_analog_em_configure_span,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2008, Anthony Minessale II
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* John Wehle (john@feith.com)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ZAP_ANALOG_EM_H
|
||||
#define ZAP_ANALOG_EM_H
|
||||
#include "openzap.h"
|
||||
|
||||
typedef enum {
|
||||
ZAP_ANALOG_EM_RUNNING = (1 << 0)
|
||||
} zap_analog_em_flag_t;
|
||||
|
||||
static void *zap_analog_em_run(zap_thread_t *me, void *obj);
|
||||
typedef struct zap_analog_data zap_analog_em_data_t;
|
||||
|
||||
#endif
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
|
||||
*/
|
|
@ -173,7 +173,7 @@ static unsigned zt_open_range(zap_span_t *span, unsigned start, unsigned end, za
|
|||
zchan->physical_span_id = ztp.span_no;
|
||||
zchan->physical_chan_id = ztp.chan_no;
|
||||
|
||||
if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_B) {
|
||||
if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO || type == ZAP_CHAN_TYPE_EM || type == ZAP_CHAN_TYPE_B) {
|
||||
if (ztp.g711_type == ZT_G711_ALAW) {
|
||||
zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ALAW;
|
||||
} else if (ztp.g711_type == ZT_G711_MULAW) {
|
||||
|
@ -343,7 +343,7 @@ static ZIO_OPEN_FUNCTION(zt_open)
|
|||
zap_log(ZAP_LOG_ERROR, "%s\n", zchan->last_error);
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
} else if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO) {
|
||||
} else if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO || zchan->type == ZAP_CHAN_TYPE_EM) {
|
||||
int len = zt_globals.eclevel;
|
||||
if (ioctl(zchan->sockfd, ZT_ECHOCANCEL, &len)) {
|
||||
zap_log(ZAP_LOG_WARNING, "Echo cancel not available for %d:%d\n", zchan->span_id, zchan->chan_id);
|
||||
|
@ -636,7 +636,7 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
|||
break;
|
||||
case ZT_EVENT_WINKFLASH:
|
||||
{
|
||||
if (span->channels[i]->state == ZAP_CHANNEL_STATE_DOWN) {
|
||||
if (span->channels[i]->state == ZAP_CHANNEL_STATE_DOWN || span->channels[i]->state == ZAP_CHANNEL_STATE_DIALING) {
|
||||
event_id = ZAP_OOB_WINK;
|
||||
} else {
|
||||
event_id = ZAP_OOB_FLASH;
|
||||
|
@ -645,7 +645,7 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
|||
break;
|
||||
case ZT_EVENT_RINGOFFHOOK:
|
||||
{
|
||||
if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS) {
|
||||
if (span->channels[i]->type == ZAP_CHAN_TYPE_FXS || (span->channels[i]->type == ZAP_CHAN_TYPE_EM && span->channels[i]->state != ZAP_CHANNEL_STATE_UP)) {
|
||||
zap_set_flag_locked(span->channels[i], ZAP_CHANNEL_OFFHOOK);
|
||||
event_id = ZAP_OOB_OFFHOOK;
|
||||
} else if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
|
||||
|
|
|
@ -2032,7 +2032,7 @@ static zap_status_t load_config(void)
|
|||
zap_copy_string(number, val, sizeof(number));
|
||||
}
|
||||
} else if (!strcasecmp(var, "analog-start-type")) {
|
||||
if (span->trunk_type == ZAP_TRUNK_FXS || span->trunk_type == ZAP_TRUNK_FXO) {
|
||||
if (span->trunk_type == ZAP_TRUNK_FXS || span->trunk_type == ZAP_TRUNK_FXO || span->trunk_type == ZAP_TRUNK_EM) {
|
||||
if ((tmp = zap_str2zap_analog_start_type(val)) != ZAP_ANALOG_START_NA) {
|
||||
span->start_type = tmp;
|
||||
zap_log(ZAP_LOG_DEBUG, "changing start type to '%s'\n", zap_analog_start_type2str(span->start_type));
|
||||
|
@ -2062,6 +2062,17 @@ static zap_status_t load_config(void)
|
|||
} else {
|
||||
zap_log(ZAP_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n");
|
||||
}
|
||||
} else if (!strcasecmp(var, "em-channel")) {
|
||||
if (span->trunk_type == ZAP_TRUNK_NONE) {
|
||||
span->trunk_type = ZAP_TRUNK_EM;
|
||||
zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s' start(%s)\n", zap_trunk_type2str(span->trunk_type),
|
||||
zap_analog_start_type2str(span->start_type));
|
||||
}
|
||||
if (span->trunk_type == ZAP_TRUNK_EM) {
|
||||
configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_EM, name, number);
|
||||
} else {
|
||||
zap_log(ZAP_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n");
|
||||
}
|
||||
} else if (!strcasecmp(var, "b-channel")) {
|
||||
configured += zio->configure_span(span, val, ZAP_CHAN_TYPE_B, name, number);
|
||||
} else if (!strcasecmp(var, "d-channel")) {
|
||||
|
|
Loading…
Reference in New Issue