From 3c67e821928b3e0fb7185301a825eb73f9518d2f Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 17 Sep 2008 16:33:43 +0000 Subject: [PATCH] Check in of a very incomplete mod_unicall, in the hope of getting some buy in while I'm too buy with other stuff. :-\ git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9578 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/mod/endpoints/mod_unicall/mod_unicall.c | 1953 +++++++++++++++++++ 1 file changed, 1953 insertions(+) create mode 100644 src/mod/endpoints/mod_unicall/mod_unicall.c diff --git a/src/mod/endpoints/mod_unicall/mod_unicall.c b/src/mod/endpoints/mod_unicall/mod_unicall.c new file mode 100644 index 0000000000..085e57ddbe --- /dev/null +++ b/src/mod/endpoints/mod_unicall/mod_unicall.c @@ -0,0 +1,1953 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2008, 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 + * Steve Underwood 0.0.1 + * + * + * mod_unicall.c -- UniCall endpoint module + * + */ + +/* This is a work in progress. Unfinished. Non-functional */ + +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_unicall_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_unicall_shutdown); +//SWITCH_MODULE_RUNTIME_FUNCTION(mod_unicall_runtime); +SWITCH_MODULE_DEFINITION(mod_unicall, mod_unicall_load, mod_unicall_shutdown, NULL); //mod_unicall_runtime); + +#define MAX_SPANS 128 + +switch_endpoint_interface_t *unicall_endpoint_interface; +static switch_memory_pool_t *module_pool = NULL; +static volatile int running = 1; + +typedef struct +{ + int span; + const char *id; + const char *protocol_class; + const char *protocol_variant; + int protocol_end; + int outgoing_ok; + char *dialplan; + int fd; + uc_t *uc; +} span_data_t; + +span_data_t *span_data[MAX_SPANS]; + +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; + +typedef enum { + GFLAG_MY_CODEC_PREFS = (1 << 0) +} GFLAGS; + + +static struct +{ + int debug; + /*! Requested frame duration, in ms */ + uint32_t frame_duration; + int dtmf_on; + int dtmf_off; + int suppress_dtmf_tone; + int ignore_dtmf_tone; + 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 calls; + int configured_spans; + switch_hash_t *call_hash; + switch_mutex_t *mutex; + switch_mutex_t *hash_mutex; + switch_mutex_t *channel_mutex; +} globals; + +typedef struct +{ + unsigned int flags; + switch_codec_t read_codec; + switch_codec_t write_codec; + switch_frame_t read_frame; + uint8_t databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_core_session_t *session; + switch_caller_profile_t *caller_profile; + switch_mutex_t *mutex; + switch_mutex_t *flag_mutex; + //switch_thread_cond_t *cond; + uc_t *uc; +} private_t; + + +SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan); + + + +static switch_status_t unicall_on_init(switch_core_session_t *session); +static switch_status_t unicall_on_routing(switch_core_session_t *session); +static switch_status_t unicall_on_execute(switch_core_session_t *session); +static switch_status_t unicall_on_hangup(switch_core_session_t *session); +static switch_status_t unicall_on_exchange_media(switch_core_session_t *session); +static switch_status_t unicall_on_soft_execute(switch_core_session_t *session); + +static switch_call_cause_t unicall_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags); +static switch_status_t unicall_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); +static switch_status_t unicall_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); +static switch_status_t unicall_kill_channel(switch_core_session_t *session, int sig); +static switch_status_t unicall_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); +static switch_status_t unicall_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); +static switch_status_t unicall_receive_event(switch_core_session_t *session, switch_event_t *event); + +#if 0 +static switch_call_cause_t unicall_incoming_channel(zap_sigmsg_t *sigmsg, switch_core_session_t **sp) +{ + switch_core_session_t *session = NULL; + private_t *tech_pvt = NULL; + switch_channel_t *channel = NULL; + char name[128]; + + *sp = NULL; + + if (!(session = switch_core_session_request(openzap_endpoint_interface, NULL))) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Initilization Error!\n"); + return ZAP_FAIL; + } + + 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); + return ZAP_FAIL; + } + + *sigmsg->channel->caller_data.collected = '\0'; + + if (switch_strlen_zero(sigmsg->channel->caller_data.cid_name)) + { + switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name); + } + + if (switch_strlen_zero(sigmsg->channel->caller_data.cid_num.digits)) + { + if (!switch_strlen_zero(sigmsg->channel->caller_data.ani.digits)) + { + switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->caller_data.ani.digits); + } + else + { + switch_set_string(sigmsg->channel->caller_data.cid_num.digits, sigmsg->channel->chan_number); + } + } + + tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), + "UniCall", + SPAN_CONFIG[sigmsg->channel->span_id].dialplan, + sigmsg->channel->caller_data.cid_name, + sigmsg->channel->caller_data.cid_num.digits, + NULL, + sigmsg->channel->caller_data.ani.digits, + sigmsg->channel->caller_data.aniII, + sigmsg->channel->caller_data.rdnis.digits, + (char *) modname, + SPAN_CONFIG[sigmsg->channel->span_id].context, + sigmsg->channel->caller_data.dnis.digits); + + assert(tech_pvt->caller_profile != NULL); + + if (sigmsg->channel->caller_data.screen == 1 || sigmsg->channel->caller_data.screen == 3) + { + switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN); + } + + if (sigmsg->channel->caller_data.pres) + { + switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER); + } + + snprintf(name, sizeof(name), "UNICALL/%u:%u/%s", sigmsg->channel->span_id, sigmsg->channel->chan_id, tech_pvt->caller_profile->destination_number); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect inbound channel %s\n", name); + 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); + return ZAP_FAIL; + } + + if (zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session), 0) != ZAP_SUCCESS) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding token\n"); + switch_core_session_destroy(&session); + return ZAP_FAIL; + } + *sp = session; + + return ZAP_SUCCESS; +} +#endif + +static void on_devicefail(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_devicefail\n"); +} + +static void on_protocolfail(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_protocolfail\n"); +} + +static void on_sigchanstatus(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_sigchanstatus\n"); +} + +static void on_detected(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + //struct channel_map *chanmap; + //char name[128]; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_detected\n"); + switch_mutex_lock(globals.channel_mutex); + + //chanmap = spri->private_info; + +#if 0 + if ((session = switch_core_session_locate(chanmap->map[e->offered.channel]))) + { + switch_log_printf(SWITCH_CHANNEL_LOG, + SWITCH_LOG_NOTICE, + "--Duplicate detected on channel s%dc%d (ignored)\n", + spri->span, + e->offered.channel); + switch_core_session_rwunlock(session); + switch_mutex_unlock(globals.channel_mutex); + return; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, + SWITCH_LOG_NOTICE, + "-- Detected on channel s%dc%d (from %s to %s)\n", + spri->span, + e->offered.channel, + e->offered.parms.originating_number, + e->offered.parms.destination_number); + + switch_mutex_unlock(chanmap->mutex); + + //pri_proceeding(spri->pri, e->offered.call, e->offered.channel, 0); + //pri_acknowledge(spri->pri, e->offered.call, e->offered.channel, 0); + + switch_mutex_unlock(chanmap->mutex); + + if ((session = unicall_incoming_channel(sigmsg, &session))) + { + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create new inbound channel!\n"); + } +#endif + switch_mutex_unlock(globals.channel_mutex); +} + +static void on_offered(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + //struct channel_map *chanmap; + //char name[128]; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_offered\n"); +} + +static void on_requestmoreinfo(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_requestmoreinfo\n"); +} + +static void on_accepted(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_accepted\n"); +} + +static void on_callinfo(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_callinfo\n"); +} + +static void on_facility(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_facility\n"); +} + +static void on_dialednumber(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_dialednumber\n"); +} + +static void on_dialtone(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_dialtone\n"); +} + +static void on_dialing(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_dialing\n"); +} + +static void on_sendmoreinfo(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_sendmoreinfo\n"); +} + +static void on_proceeding(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + //struct channel_map *chanmap; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_proceeding\n"); + +#if 0 + chanmap = spri->private_info; + + if ((session = switch_core_session_locate(chanmap->map[e->proceeding.channel]))) + { + switch_core_session_message_t *msg; + + switch_log_printf(SWITCH_CHANNEL_LOG, + SWITCH_LOG_NOTICE, + "-- Proceeding on channel s%dc%d\n", + spri->span, + e->proceeding.channel); + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_PROGRESS); + switch_channel_mark_pre_answered(channel); + + switch_core_session_rwunlock(session); + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, + SWITCH_LOG_NOTICE, + "-- Proceeding on channel s%dc%d but it's not in use?\n", + spri->span, + e->proceeding.channel); + } +#endif +} + +static void on_alerting(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + //struct channel_map *chanmap; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_alerting\n"); + +#if 0 + chanmap = spri->private_info; + + if ((session = switch_core_session_locate(chanmap->map[e->alerting.channel]))) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "-- Ringing on channel s%dc%d\n", spri->span, e->alerting.channel); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_RINGING); + switch_channel_mark_ring_ready(channel); + + switch_core_session_rwunlock(session); + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "-- Ringing on channel s%dc%d %s but it's not in use?\n", spri->span, e->alerting.channel, chanmap->map[e->alerting.channel]); + } +#endif +} + +static void on_connected(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_connected\n"); +} + +static void on_answered(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_answered\n"); +} + +static void on_fardisconnected(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_fardisconnected\n"); +} + +static void on_dropcall(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_dropcall\n"); +} + +static void on_releasecall(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_releasecall\n"); +} + +static void on_farblocked(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_farblocked\n"); +} + +static void on_farunblocked(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_farunblocked\n"); +} + +static void on_localblocked(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_localblocked\n"); +} + +static void on_localunblocked(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + //switch_channel_t *channel; + //private_t *tech_pvt; + + //tech_pvt = switch_core_session_get_private(session); + //assert(tech_pvt != NULL); + //channel = switch_core_session_get_channel(session); + //assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_localunblocked\n"); +} + +static void on_alarm(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_alarm\n"); +} + +static void on_resetlinedev(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_resetlinedev\n"); +} + +static void on_l2frame(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_l2frame\n"); +} + +static void on_l2bufferfull(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_l2bufferfull\n"); +} + +static void on_l2nobuffer(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_l2nobuffer\n"); +} + +static void on_usrinfo(uc_t *uc, switch_core_session_t *session, uc_event_t *e) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "on_usrinfo\n"); +} + +static void handle_uc_event(uc_t *uc, void *user_data, uc_event_t *e) +{ + switch_core_session_t *session; + + session = (switch_core_session_t *) user_data; + assert(session != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "event %d\n", e->e); + switch (e->e) + { + case UC_EVENT_DEVICEFAIL: + on_devicefail(uc, session, e); + break; + case UC_EVENT_PROTOCOLFAIL: + on_protocolfail(uc, session, e); + break; + case UC_EVENT_SIGCHANSTATUS: + on_sigchanstatus(uc, session, e); + break; + case UC_EVENT_DETECTED: + on_detected(uc, session, e); + break; + case UC_EVENT_OFFERED: + on_offered(uc, session, e); + break; + case UC_EVENT_REQUESTMOREINFO: + on_requestmoreinfo(uc, session, e); + break; + case UC_EVENT_ACCEPTED: + on_accepted(uc, session, e); + break; + case UC_EVENT_CALLINFO: + on_callinfo(uc, session, e); + break; + case UC_EVENT_FACILITY: + on_facility(uc, session, e); + break; + case UC_EVENT_DIALEDNUMBER: + on_dialednumber(uc, session, e); + break; + case UC_EVENT_DIALTONE: + on_dialtone(uc, session, e); + break; + case UC_EVENT_DIALING: + on_dialing(uc, session, e); + break; + case UC_EVENT_SENDMOREINFO: + on_sendmoreinfo(uc, session, e); + break; + case UC_EVENT_PROCEEDING: + on_proceeding(uc, session, e); + break; + case UC_EVENT_ALERTING: + on_alerting(uc, session, e); + break; + case UC_EVENT_CONNECTED: + on_connected(uc, session, e); + break; + case UC_EVENT_ANSWERED: + on_answered(uc, session, e); + break; + case UC_EVENT_FARDISCONNECTED: + on_fardisconnected(uc, session, e); + break; + case UC_EVENT_DROPCALL: + on_dropcall(uc, session, e); + break; + case UC_EVENT_RELEASECALL: + on_releasecall(uc, session, e); + break; + case UC_EVENT_FARBLOCKED: + on_farblocked(uc, session, e); + break; + case UC_EVENT_FARUNBLOCKED: + on_farunblocked(uc, session, e); + break; + case UC_EVENT_LOCALBLOCKED: + on_localblocked(uc, session, e); + break; + case UC_EVENT_LOCALUNBLOCKED: + on_localunblocked(uc, session, e); + break; + case UC_EVENT_ALARM: + on_alarm(uc, session, e); + break; + case UC_EVENT_RESETLINEDEV: + on_resetlinedev(uc, session, e); + break; + case UC_EVENT_L2FRAME: + on_l2frame(uc, session, e); + break; + case UC_EVENT_L2BUFFERFULL: + on_l2bufferfull(uc, session, e); + break; + case UC_EVENT_L2NOBUFFER: + on_l2nobuffer(uc, session, e); + break; + case UC_EVENT_USRINFO: + on_usrinfo(uc, session, e); + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unknown unicall event %d\n", e->e); + break; + } +} + +static void tech_init(private_t *tech_pvt, switch_core_session_t *session) +{ + 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; +} + +/* + State methods they get called when the state changes to the specific state + returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next + so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. +*/ +static switch_status_t unicall_on_init(switch_core_session_t *session) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_on_init(%p)\n", (void *) session); + + switch_set_flag_locked(tech_pvt, TFLAG_IO); + + /* Move channel's state machine to ROUTING. This means the call is trying + to get from the initial start where the call because, to the point + where a destination has been identified. If the channel is simply + left in the initial state, nothing will happen. */ + switch_channel_set_state(channel, CS_ROUTING); + switch_mutex_lock(globals.mutex); + globals.calls++; + switch_mutex_unlock(globals.mutex); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_on_routing(switch_core_session_t *session) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + 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_CRIT, "unicall_on_routing(%p)\n", (void *) session); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel)); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_on_execute(switch_core_session_t *session) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + 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_CRIT, "unicall_on_execute(%p)\n", (void *) session); + + 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 unicall_on_hangup(switch_core_session_t *session) +{ + switch_channel_t *channel; + private_t *tech_pvt; + + 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_CRIT, "unicall_on_hangup(%p)\n", (void *) session); + + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); + //switch_thread_cond_signal(tech_pvt->cond); + + 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)); + + //if ((ret = uc_call_control(uc, UC_OP_DROPCALL, crn, (void *) switch_channel_get_cause(channel)))) + // ???; + + switch_mutex_lock(globals.mutex); + if (--globals.calls < 0) + globals.calls = 0; + switch_mutex_unlock(globals.mutex); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_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_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_kill_channel(%p, %d)\n", (void *) session, sig); + + switch (sig) + { + case SWITCH_SIG_KILL: +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_kill_channel(%p, %d) SIG_KILL\n", (void *) session, sig); + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); + switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); + //switch_thread_cond_signal(tech_pvt->cond); + break; + case SWITCH_SIG_BREAK: +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_kill_channel(%p, %d) SIG_BREAK\n", (void *) session, sig); + switch_set_flag_locked(tech_pvt, TFLAG_BREAK); + break; + default: +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_kill_channel(%p, %d) DEFAULT\n", (void *) session, sig); + break; + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_on_exchange_media(switch_core_session_t *session) +{ +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_on_exchange_media(%p)\n", (void *) session); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL LOOPBACK\n"); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_on_soft_execute(switch_core_session_t *session) +{ +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_on_soft_execute(%p)\n", (void *) session); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CHANNEL TRANSMIT\n"); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) +{ + private_t *tech_pvt = switch_core_session_get_private(session); + switch_assert(tech_pvt != NULL); + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_send_dtmf(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + //switch_time_t started = switch_time_now(); + //unsigned int elapsed; + switch_byte_t *data; + + 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_CRIT, "unicall_read_frame(%p)\n", (void *) session); + + tech_pvt->read_frame.flags = SFF_NONE; + *frame = NULL; + + while (switch_test_flag(tech_pvt, TFLAG_IO)) + { + if (switch_test_flag(tech_pvt, TFLAG_BREAK)) + { + switch_clear_flag(tech_pvt, TFLAG_BREAK); + data = (switch_byte_t *) tech_pvt->read_frame.data; + data[0] = 65; + data[1] = 0; + tech_pvt->read_frame.datalen = 2; + tech_pvt->read_frame.flags = SFF_CNG; + *frame = &tech_pvt->read_frame; + return SWITCH_STATUS_SUCCESS; + } + + if (!switch_test_flag(tech_pvt, TFLAG_IO)) + return SWITCH_STATUS_FALSE; + + if (switch_test_flag(tech_pvt, TFLAG_IO) && switch_test_flag(tech_pvt, TFLAG_VOICE)) + { + switch_clear_flag_locked(tech_pvt, TFLAG_VOICE); + if (!tech_pvt->read_frame.datalen) + continue; + *frame = &tech_pvt->read_frame; +#if defined(BIGENDIAN) + if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) + switch_swap_linear((*frame)->data, (int) (*frame)->datalen / 2); +#endif + return SWITCH_STATUS_SUCCESS; + } + + switch_yield(1000); + } + + return SWITCH_STATUS_FALSE; +} + +static switch_status_t unicall_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) +{ + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + //switch_frame_t *pframe; + + 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_CRIT, "unicall_write_frame(%p)\n", (void *) session); + + if (!switch_test_flag(tech_pvt, TFLAG_IO)) + return SWITCH_STATUS_FALSE; +#if defined(BIGENDIAN) + if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) + switch_swap_linear(frame->data, (int) frame->datalen/sizeof(int16_t)); +#endif + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t redirect_audio(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "redirect_audio(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t transmit_text(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "transmit_text(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t answer(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "answer(%p)\n", (void *) session); + + //if ((ret = uc_call_control(uc, UC_OP_ANSWERCALL, crn, NULL))) + // ???; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t progress(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "progress(%p)\n", (void *) session); + + //if ((ret = uc_call_control(uc, UC_OP_ACCEPTCALL, crn, NULL))) + // ???; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t bridge(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "bridge(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unbridge(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unbridge(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t transfer(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "transfer(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t ringing(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "ringing(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t media(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "media(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t nomedia(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "nomedia(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t hold(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "hold(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unhold(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unhold(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t redirect(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "redirect(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t respond(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "respond(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t broadcast(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "broadcast(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t media_redirect(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "media_redirect(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t deflect(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "deflect(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t video_refresh_req(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "video_refresh_req(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t display(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_channel_t *channel; + private_t *tech_pvt; + uc_t *uc; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + uc = tech_pvt->uc; + assert(uc != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "display(%p)\n", (void *) session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t unicall_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch (msg->message_id) + { + case SWITCH_MESSAGE_REDIRECT_AUDIO: + return redirect_audio(session, msg); + case SWITCH_MESSAGE_TRANSMIT_TEXT: + return transmit_text(session, msg); + case SWITCH_MESSAGE_INDICATE_ANSWER: + return answer(session, msg); + case SWITCH_MESSAGE_INDICATE_PROGRESS: + return progress(session, msg); + case SWITCH_MESSAGE_INDICATE_BRIDGE: + return bridge(session, msg); + case SWITCH_MESSAGE_INDICATE_UNBRIDGE: + return unbridge(session, msg); + case SWITCH_MESSAGE_INDICATE_TRANSFER: + return transfer(session, msg); + case SWITCH_MESSAGE_INDICATE_RINGING: + return ringing(session, msg); + case SWITCH_MESSAGE_INDICATE_MEDIA: + return media(session, msg); + case SWITCH_MESSAGE_INDICATE_NOMEDIA: + return nomedia(session, msg); + case SWITCH_MESSAGE_INDICATE_HOLD: + return hold(session, msg); + case SWITCH_MESSAGE_INDICATE_UNHOLD: + return unhold(session, msg); + case SWITCH_MESSAGE_INDICATE_REDIRECT: + return redirect(session, msg); + case SWITCH_MESSAGE_INDICATE_RESPOND: + return respond(session, msg); + case SWITCH_MESSAGE_INDICATE_BROADCAST: + return broadcast(session, msg); + case SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT: + return media_redirect(session, msg); + case SWITCH_MESSAGE_INDICATE_DEFLECT: + return deflect(session, msg); + case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ: + return video_refresh_req(session, msg); + case SWITCH_MESSAGE_INDICATE_DISPLAY: + return display(session, msg); + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_receive_message(%p) %d\n", (void *) session, msg->message_id); + break; + } + + return SWITCH_STATUS_SUCCESS; +} + +/* 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 unicall_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags) +{ + private_t *tech_pvt; + switch_channel_t *channel; + switch_caller_profile_t *caller_profile; + uc_t *uc; + uc_makecall_t makecall; + uc_callparms_t *callparms; + int screen; + int hide; + char name[128]; + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_outgoing_channel(%p)\n", (void *) session); + + if ((*new_session = switch_core_session_request(unicall_endpoint_interface, pool)) == NULL) + { + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + } + + switch_core_session_add_stream(*new_session, NULL); + if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) == NULL) + { + 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; + } + channel = switch_core_session_get_channel(*new_session); + tech_init(tech_pvt, *new_session); + + if (outbound_profile == NULL) + { + 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; + } + snprintf(name, sizeof(name), "UNICALL/%s", outbound_profile->destination_number); + 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; + + uc = tech_pvt->uc; + + if ((callparms = uc_new_callparms(NULL)) == NULL) + return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; + + //uc_callparm_bear_cap_transfer_cap(callparms, cap); + //uc_callparm_bear_cap_transfer_mode(callparms, mode); + //uc_callparm_bear_cap_transfer_rate(callparms, rate); + //uc_callparm_userinfo_layer1_protocol(callparms, prot); + //uc_callparm_user_rate(callparms, rate); + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "destination '%s'\n", outbound_profile->destination_number); + uc_callparm_destination_number(callparms, outbound_profile->destination_number); + uc_callparm_destination_ton(callparms, outbound_profile->destination_number_ton); + uc_callparm_destination_npi(callparms, outbound_profile->destination_number_numplan); + //uc_callparm_destination_sub_addr_number(callparms, num); + //uc_callparm_destination_sub_addr_ton(callparms, ton); + //uc_callparm_destination_sub_addr_npi(callparms, npi); + + //uc_callparm_redirecting_cause(callparms, cause); + //uc_callparm_redirecting_presentation(callparms, pres); + uc_callparm_redirecting_number(callparms, outbound_profile->rdnis); + uc_callparm_redirecting_ton(callparms, outbound_profile->rdnis_ton); + uc_callparm_redirecting_npi(callparms, outbound_profile->rdnis_numplan); + //uc_callparm_redirecting_subaddr(callparms, num); + //uc_callparm_redirecting_subaddr_ton(callparms, ton); + //uc_callparm_redirecting_subaddr_npi(callparms, npi); + + //uc_callparm_original_called_number(callparms, num); + //uc_callparm_original_called_number_ton(callparms, ton); + //uc_callparm_original_called_number_npi(callparms, npi); + +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "caller id name '%s'\n", outbound_profile->caller_id_name); +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "caller id number '%s'\n", outbound_profile->caller_id_number); + uc_callparm_originating_name(callparms, outbound_profile->caller_id_name); + uc_callparm_originating_number(callparms, outbound_profile->caller_id_number); + screen = switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN); + hide = switch_test_flag(outbound_profile, SWITCH_CPF_HIDE_NUMBER); + if (!screen && !hide) + uc_callparm_originating_presentation(callparms, UC_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED); + else if (!screen && hide) + uc_callparm_originating_presentation(callparms, UC_PRES_PROHIB_USER_NUMBER_NOT_SCREENED); + else if (screen && !hide) + uc_callparm_originating_presentation(callparms, UC_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN); + else + uc_callparm_originating_presentation(callparms, UC_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN); + uc_callparm_originating_ton(callparms, outbound_profile->caller_ton); + uc_callparm_originating_npi(callparms, outbound_profile->caller_numplan); + //uc_callparm_originating_sub_addr_ton(callparms, ton); + //uc_callparm_originating_sub_addr_npi(callparms, npi); + //uc_callparm_originating_sub_addr_number(callparms, num); + + uc_callparm_calling_party_category(callparms, UC_CALLER_CATEGORY_NATIONAL_SUBSCRIBER_CALL); + + makecall.callparms = callparms; + makecall.crn = 0; + +#if 0 + if ((ret = uc_call_control(uc, UC_OP_MAKECALL, 0, (void *) &makecall))) + ????; +#endif + free(callparms); + + switch_channel_set_flag(channel, CF_OUTBOUND); + switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); + switch_channel_set_state(channel, CS_INIT); +switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_outgoing_channel(%p) SUCCESS\n", (void *) session); + return SWITCH_CAUSE_SUCCESS; +} + +static switch_status_t unicall_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + struct private_object *tech_pvt = switch_core_session_get_private(session); + char *body = switch_event_get_body(event); + + switch_assert(tech_pvt != NULL); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "unicall_receive_event(%p)\n", (void *) session); + + if (body == NULL) + body = ""; + + return SWITCH_STATUS_SUCCESS; +} + +static void *SWITCH_THREAD_FUNC unicall_thread_run(switch_thread_t *thread, void *obj) +{ + fd_set read; + fd_set write; + fd_set oob; + int fd; + int i; + int sel_on; + int ret; + switch_event_t *s_event; + uc_t *uc = (uc_t *) obj; + +#if 0 + switch_mutex_init(&chanmap.mutex, SWITCH_MUTEX_NESTED, module_pool); +#endif + + if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) + { + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_uc._tcp"); + switch_event_fire(&s_event); + } + + for (i = 0; i < MAX_SPANS; i++) + { + if (span_data[i]) + { + if ((ret = uc_call_control(span_data[i]->uc, UC_OP_UNBLOCK, 0, (void *) (intptr_t) -1)) < 0) + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Unblock failed - %s\n", uc_ret_to_str(ret)); + /*endif*/ + } + } + FD_ZERO(&read); + FD_ZERO(&write); + FD_ZERO(&oob); + for (;;) + { + i = 0; + sel_on = -1; + for (i = 0; i < MAX_SPANS; i++) + { + if (span_data[i]) + { + fd = span_data[i]->fd; + FD_SET(fd, &read); + //FD_SET(fd, &write); + //FD_SET(fd, &oob); + if (fd > sel_on) + sel_on = fd; + } + } + + if (sel_on > -1) + { + if (select(++sel_on, &read, NULL, NULL, NULL)) + { + for (i = 0; i < MAX_SPANS; i++) + { + if (span_data[i]) + { + fd = span_data[i]->fd; + if (FD_ISSET(fd, &read)) + { + uc_check_event(span_data[i]->uc); + uc_schedule_run(span_data[i]->uc); + } + } + } + } + } + } + + uc_delete(uc); + return NULL; +} + +static void unicall_thread_launch(uc_t *uc) +{ + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; + + switch_threadattr_create(&thd_attr, module_pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + switch_thread_create(&thread, thd_attr, unicall_thread_run, uc, module_pool); +} + +switch_state_handler_table_t unicall_state_handlers = +{ + /*.on_init */ unicall_on_init, + /*.on_routing */ unicall_on_routing, + /*.on_execute */ unicall_on_execute, + /*.on_hangup */ unicall_on_hangup, + /*.on_exchange_media */ unicall_on_exchange_media, + /*.on_soft_execute */ unicall_on_soft_execute +}; + +switch_io_routines_t unicall_io_routines = +{ + /*.outgoing_channel */ unicall_outgoing_channel, + /*.read_frame */ unicall_read_frame, + /*.write_frame */ unicall_write_frame, + /*.kill_channel */ unicall_kill_channel, + /*.send_dtmf */ unicall_send_dtmf, + /*.receive_message */ unicall_receive_message, + /*.receive_event */ unicall_receive_event +}; + +static switch_status_t config_unicall(int reload) +{ + const char *cf = "unicall.conf"; + switch_xml_t cfg; + switch_xml_t xml; + switch_xml_t settings; + switch_xml_t param; + switch_xml_t spans; + switch_xml_t span; + int current_span = 0; + int min_span = 0; + int max_span = 0; + int i; + char *id; + span_data_t *sp; + + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "opening %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 (!strcmp(var, "debug")) + { + globals.debug = atoi(val); + } + else if (!strcmp(var, "ms-per-frame")) + { + globals.frame_duration = atoi(val); + } + else if (!strcmp(var, "dtmf-on")) + { + globals.dtmf_on = atoi(val); + } + else if (!strcmp(var, "dtmf-off")) + { + globals.dtmf_off = atoi(val); + } + else if (!strcmp(var, "dialplan")) + { + set_global_dialplan(val); + } + else if (!strcmp(var, "suppress-dtmf-tone")) + { + globals.suppress_dtmf_tone = switch_true(val); + } + else if (!strcmp(var, "ignore-dtmf-tone")) + { + globals.ignore_dtmf_tone = switch_true(val); + } + } + } + spans = switch_xml_child(cfg, "spans"); + id = NULL; + for (span = switch_xml_child(spans, "span"); span; span = span->next) + { + id = (char *) switch_xml_attr(span, "id"); + + current_span = 0; + + if (id) + { + char *p; + + min_span = atoi(id); + if ((p = strchr(id, '-'))) + { + p++; + max_span = atoi(p); + } + else + { + max_span = min_span; + } + if (min_span < 1 || max_span < min_span) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Span Config! [%s]\n", id); + continue; + } + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing SPAN ID!\n"); + continue; + } + for (i = min_span; i <= max_span; i++) + { + current_span = i; + + if (current_span <= 0 || current_span > MAX_SPANS) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid SPAN %d!\n", current_span); + current_span = 0; + continue; + } + if (span_data[current_span] == NULL) + { + if ((span_data[current_span] = switch_core_alloc(module_pool, sizeof(*span_data[current_span]))) == NULL) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "MEMORY ERROR\n"); + break; + } + sp = span_data[current_span]; + memset(sp, 0, sizeof(*sp)); + sp->span = current_span; + sp->protocol_class = NULL; + sp->protocol_variant = NULL; + sp->protocol_end = UC_MODE_CPE; + sp->outgoing_ok = TRUE; + } + sp = span_data[current_span]; + sp->id = strdup(id); + 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 (strcmp(var, "protocol-class") == 0) + { + sp->protocol_class = strdup(val); + } + else if (strcmp(var, "protocol-variant") == 0) + { + sp->protocol_variant = strdup(val); + } + else if (strcmp(var, "protocol-end") == 0) + { + if (strcasecmp(val, "co") == 0) + sp->protocol_end = UC_MODE_CO; + else if (strcasecmp(val, "cpe") == 0) + sp->protocol_end = UC_MODE_CPE; + else if (strcasecmp(val, "peer") == 0) + sp->protocol_end = UC_MODE_PEER; + } + else if (strcmp(var, "outgoing-allowed") == 0) + { + sp->outgoing_ok = switch_true(var); + } + else if (strcmp(var, "dialplan") == 0) + { + sp->dialplan = strdup(val); + } + else + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "UNKNOWN PARAMETER %s\n", var); + } + } + } + } + switch_xml_free(xml); + + if (globals.dialplan == NULL) + set_global_dialplan("XML"); + + globals.configured_spans = 0; + for (current_span = 1; current_span < MAX_SPANS; current_span++) + { + if (span_data[current_span]) + { + sp = span_data[current_span]; + if ((sp->uc = uc_create(sp->id, + sp->protocol_class, + sp->protocol_variant, + sp->protocol_end, + sp->outgoing_ok)) == NULL) + { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot launch span %d\n", current_span); + return SWITCH_STATUS_FALSE; + } + uc_get_device_handle(sp->uc, 0, &sp->fd); + uc_set_signaling_callback(sp->uc, handle_uc_event, (void *) (intptr_t) current_span); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Launched span %d\n", current_span); + unicall_thread_launch(sp->uc); + switch_mutex_lock(globals.hash_mutex); + globals.configured_spans++; + switch_mutex_unlock(globals.hash_mutex); + } + } + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_unicall_load) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + + memset(span_data, 0, sizeof(span_data)); + + module_pool = pool; + + memset(&globals, 0, sizeof(globals)); + switch_core_hash_init(&globals.call_hash, module_pool); + switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool); + switch_mutex_init(&globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool); + switch_mutex_init(&globals.channel_mutex, SWITCH_MUTEX_NESTED, module_pool); + + if ((status = config_unicall(FALSE)) != SWITCH_STATUS_SUCCESS) + return status; + + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + unicall_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); + unicall_endpoint_interface->interface_name = "unicall"; + unicall_endpoint_interface->io_routines = &unicall_io_routines; + unicall_endpoint_interface->state_handler = &unicall_state_handlers; + + /* Indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* +SWITCH_MODULE_RUNTIME_FUNCTION(mod_unicall_runtime) +{ + return SWITCH_STATUS_TERM; +} +*/ + +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_unicall_shutdown) +{ + int x = 0; + + for (x = 0, running = -1; running && x <= 100; x++) + switch_yield(20000); + return SWITCH_STATUS_SUCCESS; +}