forked from Mirrors/freeswitch
added initial OpenR2 support
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@808 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
parent
b429cb1111
commit
f7cd254439
@ -101,7 +101,7 @@ core-install: install-libLTLIBRARIES
|
||||
#
|
||||
# tools & test programs
|
||||
#
|
||||
noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testboost testanalog testapp testcid
|
||||
noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testboost testanalog testapp testcid
|
||||
|
||||
testapp_SOURCES = $(SRC)/testapp.c
|
||||
testapp_LDADD = libopenzap.la
|
||||
@ -131,6 +131,10 @@ testpri_SOURCES = $(SRC)/testpri.c
|
||||
testpri_LDADD = libopenzap.la
|
||||
testpri_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
|
||||
|
||||
testr2_SOURCES = $(SRC)/testr2.c
|
||||
testr2_LDADD = libopenzap.la
|
||||
testr2_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
|
||||
|
||||
testboost_SOURCES = $(SRC)/testboost.c
|
||||
testboost_LDADD = libopenzap.la
|
||||
testboost_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
|
||||
@ -152,6 +156,10 @@ if LIBPRI
|
||||
mod_LTLIBRARIES += ozmod_libpri.la
|
||||
endif
|
||||
|
||||
if OPENR2
|
||||
mod_LTLIBRARIES += ozmod_r2.la
|
||||
endif
|
||||
|
||||
ozmod_zt_la_SOURCES = $(SRC)/ozmod/ozmod_zt/ozmod_zt.c
|
||||
ozmod_zt_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
|
||||
ozmod_zt_la_LDFLAGS = -module -avoid-version
|
||||
@ -218,6 +226,13 @@ ozmod_libpri_la_LDFLAGS = -module -avoid-version -lpri
|
||||
ozmod_libpri_la_LIBADD = $(MYLIB)
|
||||
endif
|
||||
|
||||
if OPENR2
|
||||
ozmod_r2_la_SOURCES = $(SRC)/ozmod/ozmod_r2/ozmod_r2.c
|
||||
ozmod_r2_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
|
||||
ozmod_r2_la_LDFLAGS = -module -avoid-version -lopenr2
|
||||
ozmod_r2_la_LIBADD = $(MYLIB)
|
||||
endif
|
||||
|
||||
|
||||
dox doxygen:
|
||||
cd docs && doxygen $(OZ_SRCDIR)/docs/Doxygen.conf
|
||||
|
@ -168,6 +168,9 @@ AM_CONDITIONAL([LIBSANGOMA],[test "${have_libsangoma}" = "yes"])
|
||||
|
||||
AM_CONDITIONAL([LIBPRI],[test "${enable_libpri}" = "yes"])
|
||||
|
||||
AC_CHECK_LIB([openr2], [openr2_context_set_io_type], [have_openr2="yes"])
|
||||
AM_CONDITIONAL([OPENR2],[test "${have_openr2}" = "yes"])
|
||||
|
||||
COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS"
|
||||
AC_SUBST(COMP_VENDOR_CFLAGS)
|
||||
AC_CONFIG_FILES([Makefile
|
||||
|
@ -24,6 +24,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
* Moises Silva <moy@sangoma.com>
|
||||
*
|
||||
*
|
||||
* mod_openzap.c -- OPENZAP Endpoint Module
|
||||
@ -446,6 +447,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:
|
||||
case ZAP_CHAN_TYPE_CAS:
|
||||
{
|
||||
|
||||
zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
|
||||
@ -723,6 +725,65 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t channel_receive_message_cas(switch_core_session_t *session, switch_core_session_message_t *msg)
|
||||
{
|
||||
switch_channel_t *channel;
|
||||
private_t *tech_pvt;
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
|
||||
tech_pvt = (private_t *) switch_core_session_get_private(session);
|
||||
assert(tech_pvt != NULL);
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", tech_pvt->zchan->physical_chan_id,
|
||||
msg->message_id);
|
||||
|
||||
switch (msg->message_id) {
|
||||
case SWITCH_MESSAGE_INDICATE_RINGING:
|
||||
{
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
|
||||
} else {
|
||||
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_PROGRESS:
|
||||
{
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS);
|
||||
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA);
|
||||
} else {
|
||||
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
|
||||
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_ANSWER:
|
||||
{
|
||||
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
|
||||
zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED);
|
||||
} else {
|
||||
/* lets make the ozmod_r2 module life easier by moving thru each
|
||||
* state waiting for completion, clumsy, but does the job
|
||||
*/
|
||||
if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS) {
|
||||
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS);
|
||||
}
|
||||
if (tech_pvt->zchan->state < ZAP_CHANNEL_STATE_PROGRESS_MEDIA) {
|
||||
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
|
||||
}
|
||||
zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch_core_session_message_t *msg)
|
||||
{
|
||||
@ -877,6 +938,9 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
|
||||
case ZAP_CHAN_TYPE_B:
|
||||
status = channel_receive_message_b(session, msg);
|
||||
break;
|
||||
case ZAP_CHAN_TYPE_CAS:
|
||||
status = channel_receive_message_cas(session, msg);
|
||||
break;
|
||||
default:
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
break;
|
||||
@ -1473,6 +1537,106 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
|
||||
return status;
|
||||
}
|
||||
|
||||
static ZIO_SIGNAL_CB_FUNCTION(on_r2_signal)
|
||||
{
|
||||
switch_core_session_t *session = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
zap_status_t status = ZAP_SUCCESS;
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "Got R2 channel sig [%s] in channel %d\n", zap_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
|
||||
|
||||
switch(sigmsg->event_id) {
|
||||
/* on_call_disconnect from the R2 side */
|
||||
case ZAP_SIGEVENT_STOP:
|
||||
{
|
||||
while((session = zap_channel_get_session(sigmsg->channel, 0))) {
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
|
||||
zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* on_call_offered from the R2 side */
|
||||
case ZAP_SIGEVENT_START:
|
||||
{
|
||||
status = zap_channel_from_event(sigmsg, &session);
|
||||
}
|
||||
break;
|
||||
|
||||
/* on DNIS received from the R2 forward side, return status == ZAP_BREAK to stop requesting DNIS */
|
||||
case ZAP_SIGEVENT_COLLECTED_DIGIT:
|
||||
{
|
||||
char *regex = SPAN_CONFIG[sigmsg->channel->span->span_id].dial_regex;
|
||||
char *fail_regex = SPAN_CONFIG[sigmsg->channel->span->span_id].fail_dial_regex;
|
||||
|
||||
if (switch_strlen_zero(regex)) {
|
||||
regex = NULL;
|
||||
}
|
||||
|
||||
if (switch_strlen_zero(fail_regex)) {
|
||||
fail_regex = NULL;
|
||||
}
|
||||
|
||||
zap_log(ZAP_LOG_DEBUG, "R2 DNIS so far [%s]\n", sigmsg->channel->caller_data.dnis.digits);
|
||||
|
||||
if ((regex || fail_regex) && !switch_strlen_zero(sigmsg->channel->caller_data.dnis.digits)) {
|
||||
switch_regex_t *re = NULL;
|
||||
int ovector[30];
|
||||
int match = 0;
|
||||
|
||||
if (fail_regex) {
|
||||
match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, fail_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
|
||||
status = match ? ZAP_SUCCESS : ZAP_BREAK;
|
||||
switch_regex_safe_free(re);
|
||||
}
|
||||
|
||||
if (status == ZAP_SUCCESS && regex) {
|
||||
match = switch_regex_perform(sigmsg->channel->caller_data.dnis.digits, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
|
||||
status = match ? ZAP_BREAK : ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
switch_regex_safe_free(re);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ZAP_SIGEVENT_PROGRESS:
|
||||
{
|
||||
if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_channel_mark_ring_ready(channel);
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ZAP_SIGEVENT_UP:
|
||||
{
|
||||
if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
|
||||
zap_tone_type_t tt = ZAP_TONE_DTMF;
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_channel_mark_answered(channel);
|
||||
if (zap_channel_command(sigmsg->channel, ZAP_COMMAND_ENABLE_DTMF_DETECT, &tt) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Failed to enable DTMF detection in R2 channel %d:%d\n", sigmsg->channel->span_id, sigmsg->channel->chan_id);
|
||||
}
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled event %d from R2 for channel %d:%d\n",
|
||||
sigmsg->event_id, sigmsg->channel->span_id, sigmsg->channel->chan_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ZIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
|
||||
{
|
||||
switch_core_session_t *session = NULL;
|
||||
@ -2154,7 +2318,170 @@ static switch_status_t load_config(void)
|
||||
}
|
||||
}
|
||||
|
||||
if ((spans = switch_xml_child(cfg, "r2_spans"))) {
|
||||
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
|
||||
char *id = (char *) switch_xml_attr(myspan, "id");
|
||||
char *name = (char *) switch_xml_attr(myspan, "name");
|
||||
zap_status_t zstatus = ZAP_FAIL;
|
||||
|
||||
/* strings */
|
||||
const char *variant = "itu";
|
||||
const char *category = "national_subscriber";
|
||||
const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */
|
||||
const char *logging = "notice,warning,error";
|
||||
const char *advanced_protocol_file = "";
|
||||
|
||||
/* booleans */
|
||||
int call_files = 0;
|
||||
int get_ani_first = -1;
|
||||
int immediate_accept = -1;
|
||||
int double_answer = -1;
|
||||
int skip_category = -1;
|
||||
int forced_release = -1;
|
||||
int charge_calls = -1;
|
||||
|
||||
/* integers */
|
||||
int mfback_timeout = -1;
|
||||
int metering_pulse_timeout = -1;
|
||||
int allow_collect_calls = -1;
|
||||
int max_ani = 10;
|
||||
int max_dnis = 4;
|
||||
|
||||
/* common non r2 stuff */
|
||||
const char *context = "default";
|
||||
const char *dialplan = "XML";
|
||||
char *dial_regex = NULL;
|
||||
char *fail_dial_regex = NULL;
|
||||
uint32_t span_id = 0;
|
||||
zap_span_t *span = NULL;
|
||||
|
||||
|
||||
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");
|
||||
|
||||
/* string parameters */
|
||||
if (!strcasecmp(var, "variant")) {
|
||||
variant = val;
|
||||
} else if (!strcasecmp(var, "category")) {
|
||||
category = val;
|
||||
} else if (!strcasecmp(var, "logdir")) {
|
||||
logdir = val;
|
||||
} else if (!strcasecmp(var, "logging")) {
|
||||
logging = val;
|
||||
} else if (!strcasecmp(var, "advanced_protocol_file")) {
|
||||
advanced_protocol_file = val;
|
||||
|
||||
/* booleans */
|
||||
} else if (!strcasecmp(var, "allow_collect_calls")) {
|
||||
allow_collect_calls = switch_true(val);
|
||||
} else if (!strcasecmp(var, "immediate_accept")) {
|
||||
immediate_accept = switch_true(val);
|
||||
} else if (!strcasecmp(var, "double_answer")) {
|
||||
double_answer = switch_true(val);
|
||||
} else if (!strcasecmp(var, "skip_category")) {
|
||||
skip_category = switch_true(var);
|
||||
} else if (!strcasecmp(var, "forced_release")) {
|
||||
forced_release = switch_true(val);
|
||||
} else if (!strcasecmp(var, "charge_calls")) {
|
||||
charge_calls = switch_true(val);
|
||||
} else if (!strcasecmp(var, "get_ani_first")) {
|
||||
get_ani_first = switch_true(val);
|
||||
} else if (!strcasecmp(var, "call_files")) {
|
||||
call_files = switch_true(val);
|
||||
|
||||
/* integers */
|
||||
} else if (!strcasecmp(var, "mfback_timeout")) {
|
||||
mfback_timeout = atoi(val);
|
||||
} else if (!strcasecmp(var, "metering_pulse_timeout")) {
|
||||
metering_pulse_timeout = atoi(val);
|
||||
} else if (!strcasecmp(var, "max_ani")) {
|
||||
max_ani = atoi(val);
|
||||
} else if (!strcasecmp(var, "max_dnis")) {
|
||||
max_dnis = atoi(val);
|
||||
|
||||
/* common non r2 stuff */
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id && !name) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
zstatus = zap_span_find_by_name(name, &span);
|
||||
} else {
|
||||
if (switch_is_number(id)) {
|
||||
span_id = atoi(id);
|
||||
zstatus = zap_span_find(span_id, &span);
|
||||
}
|
||||
|
||||
if (zstatus != ZAP_SUCCESS) {
|
||||
zstatus = zap_span_find_by_name(id, &span);
|
||||
}
|
||||
}
|
||||
|
||||
if (zstatus != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!span_id) {
|
||||
span_id = span->span_id;
|
||||
}
|
||||
|
||||
if (zap_configure_span("r2", span, on_r2_signal,
|
||||
"variant", variant,
|
||||
"max_ani", max_ani,
|
||||
"max_dnis", max_dnis,
|
||||
"category", category,
|
||||
"logdir", logdir,
|
||||
"logging", logging,
|
||||
"advanced_protocol_file", advanced_protocol_file,
|
||||
"allow_collect_calls", allow_collect_calls,
|
||||
"immediate_accept", immediate_accept,
|
||||
"double_answer", double_answer,
|
||||
"skip_category", skip_category,
|
||||
"forced_release", forced_release,
|
||||
"charge_calls", charge_calls,
|
||||
"get_ani_first", get_ani_first,
|
||||
"call_files", call_files,
|
||||
"mfback_timeout", mfback_timeout,
|
||||
"metering_pulse_timeout", metering_pulse_timeout,
|
||||
TAG_END) != ZAP_SUCCESS) {
|
||||
zap_log(ZAP_LOG_ERROR, "Error configuring R2 OpenZAP span %d, error: %s\n",
|
||||
span_id, span->last_error);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
SPAN_CONFIG[span->span_id].span = span;
|
||||
switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
|
||||
switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
|
||||
switch_copy_string(SPAN_CONFIG[span->span_id].type, "r2", sizeof(SPAN_CONFIG[span->span_id].type));
|
||||
|
||||
if (zap_span_start(span) == ZAP_FAIL) {
|
||||
zap_log(ZAP_LOG_ERROR, "Error starting R2 OpenZAP span %d, error: %s\n", span_id, span->last_error);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
|
||||
|
@ -280,6 +280,17 @@
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define zap_locked_wait_for_flag_cleared(obj, flag, time) \
|
||||
do { \
|
||||
int __safety = time; \
|
||||
while(__safety-- && zap_test_flag(obj, flag)) { \
|
||||
zap_sleep(10); \
|
||||
} \
|
||||
if(!__safety) { \
|
||||
zap_log(ZAP_LOG_CRIT, "flag %d was never cleared\n", flag); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
|
||||
typedef enum {
|
||||
ZAP_STATE_CHANGE_FAIL,
|
||||
@ -517,7 +528,7 @@ struct zap_channel {
|
||||
struct zap_span *span;
|
||||
struct zap_io_interface *zio;
|
||||
zap_hash_t *variable_hash;
|
||||
unsigned char cas_bits;
|
||||
unsigned char rx_cas_bits;
|
||||
};
|
||||
|
||||
|
||||
|
@ -175,7 +175,8 @@ typedef enum {
|
||||
ZAP_SIGTYPE_RBS,
|
||||
ZAP_SIGTYPE_ANALOG,
|
||||
ZAP_SIGTYPE_SS7BOOST,
|
||||
ZAP_SIGTYPE_M3UA
|
||||
ZAP_SIGTYPE_M3UA,
|
||||
ZAP_SIGTYPE_R2
|
||||
} zap_signal_type_t;
|
||||
|
||||
typedef enum {
|
||||
@ -279,6 +280,9 @@ typedef enum {
|
||||
ZAP_COMMAND_GET_RX_GAIN,
|
||||
ZAP_COMMAND_SET_TX_GAIN,
|
||||
ZAP_COMMAND_GET_TX_GAIN,
|
||||
ZAP_COMMAND_FLUSH_TX_BUFFERS,
|
||||
ZAP_COMMAND_FLUSH_RX_BUFFERS,
|
||||
ZAP_COMMAND_FLUSH_BUFFERS,
|
||||
ZAP_COMMAND_COUNT
|
||||
} zap_command_t;
|
||||
|
||||
|
1368
libs/freetdm/src/ozmod/ozmod_r2/ozmod_r2.c
Normal file
1368
libs/freetdm/src/ozmod/ozmod_r2/ozmod_r2.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -202,7 +202,7 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
|
||||
unsigned configured = 0, x;
|
||||
|
||||
if (type == ZAP_CHAN_TYPE_CAS) {
|
||||
zap_log(ZAP_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
|
||||
zap_log(ZAP_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
|
||||
}
|
||||
for(x = start; x < end; x++) {
|
||||
zap_channel_t *chan;
|
||||
@ -210,9 +210,14 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
|
||||
const char *dtmf = "none";
|
||||
|
||||
sockfd = tdmv_api_open_span_chan(spanno, x);
|
||||
if (sockfd == WP_INVALID_SOCKET) {
|
||||
zap_log(ZAP_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
|
||||
if (zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
|
||||
wanpipe_tdm_api_t tdm_api;
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
sangoma_status_t sangstatus;
|
||||
sangoma_wait_obj_t *sangoma_wait_obj;
|
||||
@ -225,8 +230,6 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
|
||||
chan->mod_data = sangoma_wait_obj;
|
||||
#endif
|
||||
|
||||
memset(&tdm_api,0,sizeof(tdm_api));
|
||||
|
||||
chan->physical_span_id = spanno;
|
||||
chan->physical_chan_id = x;
|
||||
chan->rate = 8000;
|
||||
@ -237,7 +240,7 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
|
||||
dtmf = "software";
|
||||
|
||||
/* FIXME: Handle Error Condition Check for return code */
|
||||
err= sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
|
||||
err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
|
||||
|
||||
if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
|
||||
chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
|
||||
@ -270,15 +273,26 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
|
||||
if (type == ZAP_CHAN_TYPE_CAS ||
|
||||
((span->trunk_type == ZAP_TRUNK_T1 || span->trunk_type == ZAP_TRUNK_E1) && type != ZAP_CHAN_TYPE_B)) {
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id,wanpipe_swap_bits(cas_bits));
|
||||
sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
|
||||
|
||||
/* this should probably be done for old libsangoma but I am not sure if the API is available and I'm lazy to check,
|
||||
The poll rate is hard coded to 100 per second (done in the driver, is the max rate of polling allowed by wanpipe)
|
||||
*/
|
||||
if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
|
||||
zap_log(ZAP_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
|
||||
continue;
|
||||
}
|
||||
/* probably done by the driver but lets write defensive code this time */
|
||||
sangoma_flush_bufs(chan->sockfd, &tdm_api);
|
||||
#else
|
||||
sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,wanpipe_swap_bits(cas_bits));
|
||||
sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!zap_strlen_zero(name)) {
|
||||
zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
|
||||
}
|
||||
|
||||
if (!zap_strlen_zero(number)) {
|
||||
zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
|
||||
}
|
||||
@ -288,7 +302,7 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
|
||||
spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
|
||||
|
||||
} else {
|
||||
zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
|
||||
zap_log(ZAP_LOG_ERROR, "zap_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,15 +385,13 @@ static ZIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
|
||||
}
|
||||
|
||||
if (!(sp && ch)) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid input\n");
|
||||
zap_log(ZAP_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
channo = atoi(ch);
|
||||
spanno = atoi(sp);
|
||||
|
||||
|
||||
if (channo < 0) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
|
||||
continue;
|
||||
@ -528,16 +540,24 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
|
||||
case ZAP_COMMAND_SET_CAS_BITS:
|
||||
{
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
err=sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api,zchan->physical_chan_id,wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
|
||||
err = sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api, zchan->physical_chan_id, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
|
||||
#else
|
||||
err=sangoma_tdm_write_rbs(zchan->sockfd,&tdm_api,wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
|
||||
err = sangoma_tdm_write_rbs(zchan->sockfd, &tdm_api, wanpipe_swap_bits(ZAP_COMMAND_OBJ_INT));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_GET_CAS_BITS:
|
||||
{
|
||||
/* wanpipe does not has a command to get the CAS bits so we emulate it */
|
||||
ZAP_COMMAND_OBJ_INT = zchan->cas_bits;
|
||||
#ifdef LIBSANGOMA_VERSION
|
||||
unsigned char rbsbits;
|
||||
err = sangoma_tdm_read_rbs(zchan->sockfd, &tdm_api, zchan->physical_chan_id, &rbsbits);
|
||||
if (!err) {
|
||||
ZAP_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
|
||||
}
|
||||
#else
|
||||
// does sangoma_tdm_read_rbs is available here?
|
||||
ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -817,7 +837,6 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
|
||||
{
|
||||
uint32_t i,err;
|
||||
zap_oob_event_t event_id;
|
||||
|
||||
for(i = 1; i <= span->chan_count; i++) {
|
||||
if (span->channels[i]->last_event_time && !zap_test_flag(span->channels[i], ZAP_CHANNEL_EVENT)) {
|
||||
uint32_t diff = (uint32_t)(zap_current_time_in_ms() - span->channels[i]->last_event_time);
|
||||
@ -856,7 +875,7 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
|
||||
memset(&tdm_api, 0, sizeof(tdm_api));
|
||||
zap_clear_flag(span->channels[i], ZAP_CHANNEL_EVENT);
|
||||
|
||||
err=sangoma_tdm_read_event(zchan->sockfd,&tdm_api);
|
||||
err = sangoma_tdm_read_event(zchan->sockfd, &tdm_api);
|
||||
if (err != ZAP_SUCCESS) {
|
||||
snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
@ -926,9 +945,7 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
|
||||
case WP_TDMAPI_EVENT_RBS:
|
||||
{
|
||||
event_id = ZAP_OOB_CAS_BITS_CHANGE;
|
||||
/* save the CAS bits, user should retrieve it with ZAP_COMMAND_GET_CAS_BITS
|
||||
is there a best play to store this? instead of adding cas_bits member to zap_chan? */
|
||||
span->channels[i]->cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
|
||||
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:
|
||||
|
@ -780,7 +780,6 @@ static ZIO_COMMAND_FUNCTION(zt_command)
|
||||
if (zchan->effective_codec == ZAP_CODEC_SLIN) {
|
||||
zchan->packet_len *= 2;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -792,21 +791,42 @@ static ZIO_COMMAND_FUNCTION(zt_command)
|
||||
break;
|
||||
case ZAP_COMMAND_GET_CAS_BITS:
|
||||
{
|
||||
/* probably we should call ZT_GETRXBITS instead? */
|
||||
ZAP_COMMAND_OBJ_INT = zchan->cas_bits;
|
||||
err = ioctl(zchan->sockfd, codes.GETRXBITS, &zchan->rx_cas_bits);
|
||||
if (!err) {
|
||||
ZAP_COMMAND_OBJ_INT = zchan->rx_cas_bits;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_FLUSH_TX_BUFFERS:
|
||||
{
|
||||
int flushmode = ZT_FLUSH_WRITE;
|
||||
err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_FLUSH_RX_BUFFERS:
|
||||
{
|
||||
int flushmode = ZT_FLUSH_READ;
|
||||
err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
|
||||
}
|
||||
break;
|
||||
case ZAP_COMMAND_FLUSH_BUFFERS:
|
||||
{
|
||||
int flushmode = ZT_FLUSH_BOTH;
|
||||
err = ioctl(zchan->sockfd, codes.FLUSH, &flushmode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
err = ZAP_NOTIMPL;
|
||||
break;
|
||||
};
|
||||
|
||||
if (err) {
|
||||
if (err && err != ZAP_NOTIMPL) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "%s", strerror(errno));
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
return ZAP_SUCCESS;
|
||||
return err == 0 ? ZAP_SUCCESS : err;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1019,7 +1039,7 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
|
||||
if (err) {
|
||||
return ZAP_FAIL;
|
||||
}
|
||||
span->channels[i]->cas_bits = bits;
|
||||
span->channels[i]->rx_cas_bits = bits;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
86
libs/freetdm/src/testr2.c
Normal file
86
libs/freetdm/src/testr2.c
Normal file
@ -0,0 +1,86 @@
|
||||
#include "openzap.h"
|
||||
#include <signal.h>
|
||||
|
||||
static int R = 0;
|
||||
static zap_mutex_t *mutex = NULL;
|
||||
|
||||
static ZIO_SIGNAL_CB_FUNCTION(on_r2_signal)
|
||||
{
|
||||
zap_log(ZAP_LOG_DEBUG, "Got R2 channel sig [%s] in channel\n", zap_signal_event2str(sigmsg->event_id), sigmsg->channel->physical_chan_id);
|
||||
return ZAP_SUCCESS;
|
||||
}
|
||||
|
||||
static void handle_SIGINT(int sig)
|
||||
{
|
||||
zap_mutex_lock(mutex);
|
||||
R = 0;
|
||||
zap_mutex_unlock(mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
zap_span_t *span;
|
||||
zap_mutex_create(&mutex);
|
||||
|
||||
zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
|
||||
|
||||
if (argc < 2) {
|
||||
printf("umm no\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (zap_global_init() != ZAP_SUCCESS) {
|
||||
fprintf(stderr, "Error loading OpenZAP\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("OpenZAP loaded\n");
|
||||
|
||||
if (zap_span_find(atoi(argv[1]), &span) != ZAP_SUCCESS) {
|
||||
fprintf(stderr, "Error finding OpenZAP span\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (zap_configure_span("r2", span, on_r2_signal,
|
||||
"variant", "mx",
|
||||
"max_ani", 10,
|
||||
"max_dnis", 4,
|
||||
"logging", "all",
|
||||
TAG_END) == ZAP_SUCCESS) {
|
||||
|
||||
|
||||
zap_span_start(span);
|
||||
} else {
|
||||
fprintf(stderr, "Error starting R2 span\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
signal(SIGINT, handle_SIGINT);
|
||||
zap_mutex_lock(mutex);
|
||||
R = 1;
|
||||
zap_mutex_unlock(mutex);
|
||||
while(R) {
|
||||
zap_sleep(1 * 1000);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
zap_global_destroy();
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* 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:
|
||||
*/
|
@ -216,14 +216,14 @@ OZ_DECLARE (int) zap_config_get_cas_bits(char *strvalue, unsigned char *outbits)
|
||||
int x = 0;
|
||||
char *double_colon = strchr(strvalue, ':');
|
||||
if (!double_colon) {
|
||||
zap_log(ZAP_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon);
|
||||
zap_log(ZAP_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", strvalue);
|
||||
return -1;
|
||||
}
|
||||
double_colon++;
|
||||
*outbits = 0;
|
||||
cas_bits[4] = 0;
|
||||
if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon);
|
||||
zap_log(ZAP_LOG_ERROR, "Invalid CAS bits specified: '%s', :xxxx definition expected, where x is 1 or 0\n", double_colon);
|
||||
return -1;
|
||||
}
|
||||
zap_log(ZAP_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
|
||||
|
@ -1522,14 +1522,17 @@ OZ_DECLARE(zap_status_t) zap_channel_command(zap_channel_t *zchan, zap_command_t
|
||||
|
||||
if (!zchan->zio->command) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
|
||||
zap_log(ZAP_LOG_ERROR, "no commnand functon!\n");
|
||||
zap_log(ZAP_LOG_ERROR, "no command function defined by the I/O openzap module!\n");
|
||||
GOTO_STATUS(done, ZAP_FAIL);
|
||||
}
|
||||
|
||||
status = zchan->zio->command(zchan, command, obj);
|
||||
|
||||
|
||||
done:
|
||||
if (status == ZAP_NOTIMPL) {
|
||||
snprintf(zchan->last_error, sizeof(zchan->last_error), "I/O command %d not implemented in backend", command);
|
||||
zap_log(ZAP_LOG_ERROR, "I/O backend does not support command %d!\n", command);
|
||||
}
|
||||
done:
|
||||
zap_mutex_unlock(zchan->mutex);
|
||||
return status;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user