From 219ac87d22c7d72a6291bea9c519e8da5a0202ef Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 26 May 2007 04:45:31 +0000 Subject: [PATCH] refactor build git-svn-id: http://svn.openzap.org/svn/openzap/trunk@158 a93c3328-9c30-0410-af19-c9cd2b2d52af --- libs/openzap/mod_openzap/Makefile | 14 + libs/openzap/mod_openzap/mod_openzap.c | 774 +++++++++++++++++++++++++ 2 files changed, 788 insertions(+) create mode 100644 libs/openzap/mod_openzap/Makefile create mode 100644 libs/openzap/mod_openzap/mod_openzap.c diff --git a/libs/openzap/mod_openzap/Makefile b/libs/openzap/mod_openzap/Makefile new file mode 100644 index 0000000000..2ff7f24232 --- /dev/null +++ b/libs/openzap/mod_openzap/Makefile @@ -0,0 +1,14 @@ +BASE=/usr/src/freeswitch.trunk +OZ_DIR=.. +VERBOSE=1 +OZA=$(OZ_DIR)/libopenzap.a +LOCAL_CFLAGS=-w -I$(OZ_DIR)/src/include -I$(OZ_DIR)/src/isdn/include +LOCAL_LIBADD=$(OZA) +include $(BASE)/build/modmake.rules + +local_depend: $(OZA) + +$(OZA): + cd $(OZ_DIR) && $(MAKE) ZAP_MODS=wanpipe + + diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c new file mode 100644 index 0000000000..ffdab55b1f --- /dev/null +++ b/libs/openzap/mod_openzap/mod_openzap.c @@ -0,0 +1,774 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * mod_openzap.c -- OPENZAP Endpoint Module + * + */ +#include +#include "openzap.h" +#include "zap_analog.h" +#include "zap_isdn.h" + +static const char modname[] = "mod_openzap"; + +static switch_memory_pool_t *module_pool = NULL; +static int running = 1; + +struct span_config { + zap_span_t *span; + char dialplan[80]; + char context[80]; +}; + +static struct span_config SPAN_CONFIG[ZAP_MAX_SPANS_INTERFACE] = {0}; + + +typedef enum { + TFLAG_IO = (1 << 0), + TFLAG_INBOUND = (1 << 1), + TFLAG_OUTBOUND = (1 << 2), + TFLAG_DTMF = (1 << 3), + TFLAG_VOICE = (1 << 4), + TFLAG_HANGUP = (1 << 5), + TFLAG_LINEAR = (1 << 6), + TFLAG_CODEC = (1 << 7), + TFLAG_BREAK = (1 << 8) +} TFLAGS; + + +static struct { + int debug; + char *dialplan; + char *codec_string; + char *codec_order[SWITCH_MAX_CODECS]; + int codec_order_last; + char *codec_rates_string; + char *codec_rates[SWITCH_MAX_CODECS]; + int codec_rates_last; + unsigned int flags; + int fd; + int calls; + switch_mutex_t *mutex; +} globals; + +struct private_object { + unsigned int flags; + switch_codec_t read_codec; + switch_codec_t write_codec; + switch_frame_t read_frame; + unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_core_session_t *session; + switch_caller_profile_t *caller_profile; + unsigned int codec; + unsigned int codecs; + unsigned short samprate; + switch_mutex_t *mutex; + switch_mutex_t *flag_mutex; + zap_channel_t *zchan; +}; + +typedef struct private_object private_t; + + +static switch_status_t channel_on_init(switch_core_session_t *session); +static switch_status_t channel_on_hangup(switch_core_session_t *session); +static switch_status_t channel_on_ring(switch_core_session_t *session); +static switch_status_t channel_on_loopback(switch_core_session_t *session); +static switch_status_t channel_on_transmit(switch_core_session_t *session); +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, switch_memory_pool_t **pool); +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id); +static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); + + +static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *session, zap_channel_t *zchan) +{ + char *dname = NULL; + uint32_t interval = 0, srate = 8000; + zap_codec_t codec; + + tech_pvt->zchan = zchan; + tech_pvt->read_frame.data = tech_pvt->databuf; + tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); + switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); + switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); + switch_core_session_set_private(session, tech_pvt); + tech_pvt->session = session; + + zap_channel_command(zchan, ZAP_COMMAND_GET_INTERVAL, &interval); + zap_channel_command(zchan, ZAP_COMMAND_GET_CODEC, &codec); + + + switch(codec) { + case ZAP_CODEC_ULAW: + { + dname = "PCMU"; + } + break; + case ZAP_CODEC_ALAW: + { + dname = "PCMA"; + } + break; + case ZAP_CODEC_SLIN: + { + dname = "L16"; + } + break; + } + + + if (switch_core_codec_init(&tech_pvt->read_codec, + dname, + NULL, + srate, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + return SWITCH_STATUS_GENERR; + } else { + if (switch_core_codec_init(&tech_pvt->write_codec, + dname, + NULL, + srate, + interval, + 1, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n"); + switch_core_codec_destroy(&tech_pvt->read_codec); + return SWITCH_STATUS_GENERR; + } + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set codec %s %dms\n", dname, interval); + switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec); + switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec); + switch_set_flag_locked(tech_pvt, TFLAG_CODEC); + tech_pvt->read_frame.codec = &tech_pvt->read_codec; + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t channel_on_init(switch_core_session_t *session) +{ + switch_channel_t *channel; + private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_set_flag_locked(tech_pvt, TFLAG_IO); + + /* Move Channel's State Machine to RING */ + switch_channel_set_state(channel, CS_RING); + switch_mutex_lock(globals.mutex); + globals.calls++; + switch_mutex_unlock(globals.mutex); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_ring(switch_core_session_t *session) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL RING\n", switch_channel_get_name(channel)); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_execute(switch_core_session_t *session) +{ + + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); + + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_hangup(switch_core_session_t *session) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); + + if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) { + zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_BUSY); + } + + if (tech_pvt->read_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->read_codec); + } + + if (tech_pvt->write_codec.implementation) { + switch_core_codec_destroy(&tech_pvt->write_codec); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel)); + switch_mutex_lock(globals.mutex); + globals.calls--; + if (globals.calls < 0) { + globals.calls = 0; + } + switch_mutex_unlock(globals.mutex); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + switch (sig) { + case SWITCH_SIG_KILL: + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); + if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) { + zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_BUSY); + } + break; + case SWITCH_SIG_BREAK: + switch_set_flag_locked(tech_pvt, TFLAG_BREAK); + break; + default: + break; + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_loopback(switch_core_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n"); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_on_transmit(switch_core_session_t *session) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL TRANSMIT\n"); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_waitfor_read(switch_core_session_t *session, int ms, int stream_id) +{ + private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_waitfor_write(switch_core_session_t *session, int ms, int stream_id) +{ + private_t *tech_pvt = NULL; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t channel_send_dtmf(switch_core_session_t *session, char *dtmf) +{ + private_t *tech_pvt = NULL; + char *digit; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + zap_channel_command(tech_pvt->zchan, ZAP_COMMAND_SEND_DTMF, dtmf); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + zap_size_t len; + zap_wait_flag_t wflags = ZAP_READ; + uint8_t dtmf[128] = ""; + zap_status_t status; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + assert(tech_pvt->zchan != NULL); + + if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_UP) { + return SWITCH_STATUS_GENERR; + } + + status = zap_channel_wait(tech_pvt->zchan, &wflags, timeout); + + if (status == ZAP_FAIL) { + return SWITCH_STATUS_GENERR; + } + + if (status == ZAP_TIMEOUT) { + return SWITCH_STATUS_BREAK; + } + + if (!(wflags & ZAP_READ)) { + return SWITCH_STATUS_GENERR; + } + + len = tech_pvt->read_frame.buflen; + if (zap_channel_read(tech_pvt->zchan, tech_pvt->read_frame.data, &len) != ZAP_SUCCESS) { + return SWITCH_STATUS_GENERR; + } + + *frame = &tech_pvt->read_frame; + tech_pvt->read_frame.datalen = len; + tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen; + + if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) { + tech_pvt->read_frame.samples /= 2; + } + + if (zap_channel_dequeue_dtmf(tech_pvt->zchan, dtmf, sizeof(dtmf))) { + switch_channel_queue_dtmf(channel, dtmf); + } + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + zap_size_t len; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + assert(tech_pvt->zchan != NULL); + + if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_UP) { + return SWITCH_STATUS_GENERR; + } + + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { + return SWITCH_STATUS_FALSE; + } + + len = frame->datalen; + if (zap_channel_write(tech_pvt->zchan, frame->data, &len) != ZAP_SUCCESS) { + return SWITCH_STATUS_GENERR; + } + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t channel_receive_message(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); + + switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_ANSWER: + zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_UP); + break; + case SWITCH_MESSAGE_INDICATE_RINGING: + zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_RING); + break; + default: + break; + } + + return SWITCH_STATUS_SUCCESS; +} + +static const switch_state_handler_table_t channel_event_handlers = { + /*.on_init */ channel_on_init, + /*.on_ring */ channel_on_ring, + /*.on_execute */ channel_on_execute, + /*.on_hangup */ channel_on_hangup, + /*.on_loopback */ channel_on_loopback, + /*.on_transmit */ channel_on_transmit +}; + +static const switch_io_routines_t channel_io_routines = { + /*.outgoing_channel */ channel_outgoing_channel, + /*.read_frame */ channel_read_frame, + /*.write_frame */ channel_write_frame, + /*.kill_channel */ channel_kill_channel, + /*.waitfor_read */ channel_waitfor_read, + /*.waitfor_write */ channel_waitfor_write, + /*.send_dtmf */ channel_send_dtmf, + /*.receive_message*/ channel_receive_message +}; + +static const switch_endpoint_interface_t channel_endpoint_interface = { + /*.interface_name */ "openzap", + /*.io_routines */ &channel_io_routines, + /*.event_handlers */ &channel_event_handlers, + /*.private */ NULL, + /*.next */ NULL +}; + +static const switch_loadable_module_interface_t channel_module_interface = { + /*.module_name */ modname, + /*.endpoint_interface */ &channel_endpoint_interface, + /*.timer_interface */ NULL, + /*.dialplan_interface */ NULL, + /*.codec_interface */ NULL, + /*.application_interface */ NULL +}; + + +/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines +that allocate memory or you will have 1 channel with memory allocated from another channel's pool! +*/ +static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, switch_memory_pool_t **pool) +{ + if ((*new_session = switch_core_session_request(&channel_endpoint_interface, pool)) != 0) { + private_t *tech_pvt; + switch_channel_t *channel; + switch_caller_profile_t *caller_profile; + unsigned int req = 0, cap = 0; + unsigned short samprate = 0; + + switch_core_session_add_stream(*new_session, NULL); + if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) { + channel = switch_core_session_get_channel(*new_session); + tech_init(tech_pvt, *new_session, NULL); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n"); + switch_core_session_destroy(new_session); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + + if (outbound_profile) { + char name[128]; + + snprintf(name, sizeof(name), "OPENZAP/%s-%04x", outbound_profile->destination_number, rand() & 0xffff); + switch_channel_set_name(channel, name); + + caller_profile = switch_caller_profile_clone(*new_session, outbound_profile); + switch_channel_set_caller_profile(channel, caller_profile); + tech_pvt->caller_profile = caller_profile; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Doh! no caller profile\n"); + switch_core_session_destroy(new_session); + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + + + switch_channel_set_flag(channel, CF_OUTBOUND); + switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); + switch_channel_set_state(channel, CS_INIT); + return SWITCH_CAUSE_SUCCESS; + } + + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + +} + +static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal) +{ + zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id)); + return ZAP_SUCCESS; +} +static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal) +{ + switch_core_session_t *session = NULL; + private_t *tech_pvt = NULL; + switch_channel_t *channel = NULL; + char name[128]; + zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id)); + + switch(sigmsg->event_id) { + case ZAP_SIGEVENT_START: + if (!(session = switch_core_session_request(&channel_endpoint_interface, NULL))) { + zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_BUSY); + return ZAP_SUCCESS; + } + + switch_core_session_add_stream(session, NULL); + + tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t)); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + if (tech_init(tech_pvt, session, sigmsg->channel) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n"); + switch_core_session_destroy(&session); + zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_BUSY); + return ZAP_SUCCESS; + } + + tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), + "OpenZAP", + SPAN_CONFIG[sigmsg->span->span_id].dialplan, + sigmsg->channel->chan_name, + sigmsg->channel->chan_number, + NULL, + sigmsg->channel->chan_number, + NULL, + NULL, + (char *) modname, + SPAN_CONFIG[sigmsg->span->span_id].context, + sigmsg->dnis); + assert(tech_pvt->caller_profile != NULL); + + snprintf(name, sizeof(name), "OpenZAP/%s", tech_pvt->caller_profile->destination_number); + switch_channel_set_name(channel, name); + switch_channel_set_caller_profile(channel, tech_pvt->caller_profile); + + switch_channel_set_state(channel, CS_INIT); + if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error spawning thread\n"); + switch_core_session_destroy(&session); + zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_BUSY); + return ZAP_SUCCESS; + } + + //zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_RING); + + break; + default: + break; + } + + return ZAP_SUCCESS; +} + + + +static void zap_logger(char *file, const char *func, int line, int level, char *fmt, ...) +{ + char *data = NULL; + va_list ap; + + va_start(ap, fmt); + + if (switch_vasprintf(&data, fmt, ap) != -1) { + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, level, data); + free(data); + } + + va_end(ap); + +} + +static switch_status_t load_config(void) +{ + char *cf = "openzap.conf"; + switch_xml_t cfg, xml, settings, param, spans, span; + + memset(&globals, 0, sizeof(globals)); + switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool); + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); + return SWITCH_STATUS_TERM; + } + + if ((settings = switch_xml_child(cfg, "settings"))) { + for (param = switch_xml_child(settings, "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, "debug")) { + globals.debug = atoi(val); + } + } + } + + if ((spans = switch_xml_child(cfg, "analog_spans"))) { + for (span = switch_xml_child(spans, "span"); span; span = span->next) { + char *mod = (char *) switch_xml_attr_soft(span, "module"); + char *id = (char *) switch_xml_attr_soft(span, "id"); + char *context = "default"; + char *dialplan = "XML"; + char *tonegroup = NULL; + char *digit_timeout = NULL; + char *max_digits = NULL; + uint32_t span_id = 0, to = 0, max = 0; + zap_span_t *span = NULL; + + for (param = switch_xml_child(span, "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")) { + digit_timeout = val; + } else if (!strcasecmp(var, "context")) { + context = val; + } else if (!strcasecmp(var, "dialplan")) { + dialplan = val; + } else if (!strcasecmp(var, "max_digits")) { + digit_timeout = val; + } + } + + if (!mod) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'module'\n"); + } + + if (!id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n"); + } + + 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(mod, span_id, &span) != ZAP_SUCCESS) { + zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span %s:%d\n", mod, span_id); + continue; + } + + if (zap_analog_configure_span(span, tonegroup, to, max, span->trunk_type == ZAP_TRUNK_FXS ? on_fxs_signal : on_fxo_signal) != ZAP_SUCCESS) { + zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %s:%d\n", mod, span_id); + continue; + } + + 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)); + + + zap_analog_start(span); + } + } + + + switch_xml_free(xml); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename) +{ + + if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n"); + return SWITCH_STATUS_TERM; + } + + zap_global_set_logger(zap_logger); + + if (zap_global_init() != ZAP_SUCCESS) { + zap_log(ZAP_LOG_ERROR, "Error loading OpenZAP\n"); + return SWITCH_STATUS_TERM; + } + + if (load_config() != SWITCH_STATUS_SUCCESS) { + zap_global_destroy(); + return SWITCH_STATUS_TERM; + } + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = &channel_module_interface; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + + + +/* 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: + */