Merge branch 'v1.2.stable' into v1.2.stable-em_management

Conflicts:
	libs/freetdm/mod_freetdm/mod_freetdm.c
This commit is contained in:
Moises Silva 2013-11-08 02:04:58 -05:00
commit 2f6ccf659c
33 changed files with 1373 additions and 265 deletions

View File

@ -16,6 +16,12 @@
<param name="default-recognizer" value="pocketsphinx"/>
</input>
<!-- receivefax component params -->
<receivefax>
<!-- where to store incoming faxes -->
<param name="file-prefix" value="/tmp/"/>
</receivefax>
<!-- XMPP server domain -->
<domain name="$${rayo_domain_name}" shared-secret="ClueCon">
<!-- use this instead if you want secure XMPP client to server connections. Put .crt and .key file in freeswitch/certs -->
@ -65,6 +71,7 @@
<alias name="speed-down" target="output"><![CDATA[<speed-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
<alias name="volume-up" target="output"><![CDATA[<volume-up xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
<alias name="volume-down" target="output"><![CDATA[<volume-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
<alias name="receivefax" target="call"><![CDATA[<receivefax xmlns="urn:xmpp:rayo:fax:1"/>]]></alias>
<alias name="record" target="call"><![CDATA[<record xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
<alias name="record_pause" target="record"><![CDATA[<pause xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
<alias name="record_resume" target="record"><![CDATA[<resume xmlns="urn:xmpp:rayo:record:1"/>]]></alias>

View File

@ -719,14 +719,14 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
name = switch_channel_get_name(channel);
if (!tech_pvt->ftdmchan) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
return SWITCH_STATUS_FALSE;
}
span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan);
chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan);
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id);
return SWITCH_STATUS_FALSE;
}
@ -760,7 +760,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
}
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id);
goto fail;
}
@ -768,7 +768,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
status = ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, chunk);
if (status == FTDM_FAIL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
goto fail;
}
@ -776,7 +776,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
if (!switch_test_flag(tech_pvt, TFLAG_HOLD)) {
total_to -= chunk;
if (total_to <= 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many timeouts while waiting I/O in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "Too many timeouts while waiting I/O in channel %s device %d:%d!\n", name, span_id, chan_id);
goto fail;
}
}
@ -790,12 +790,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
len = tech_pvt->read_frame.buflen;
if (ftdm_channel_read(tech_pvt->ftdmchan, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) {
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to read from dead channel %s device %d:%d\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Failed to read from dead channel %s device %d:%d\n", name, span_id, chan_id);
goto normal_failure;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
if (++tech_pvt->read_error > FTDM_MAX_READ_WRITE_ERRORS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "too many I/O read errors on channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "too many I/O read errors on channel %s device %d:%d!\n", name, span_id, chan_id);
goto fail;
}
@ -817,7 +817,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
for (p = dtmf; p && *p; p++) {
if (is_dtmf(*p)) {
_dtmf.digit = *p;
ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id);
switch_channel_queue_dtmf(channel, &_dtmf);
}
}
@ -826,7 +826,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
return SWITCH_STATUS_SUCCESS;
fail:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "clearing IO in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_ERROR, "clearing IO in channel %s device %d:%d!\n", name, span_id, chan_id);
normal_failure:
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
return SWITCH_STATUS_GENERR;
@ -850,7 +850,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
name = switch_channel_get_name(channel);
if (!tech_pvt->ftdmchan) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
return SWITCH_STATUS_FALSE;
}
@ -858,7 +858,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan);
if (switch_test_flag(tech_pvt, TFLAG_DEAD)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_DEAD is set in channel %s device %d:%d!\n", name, span_id, chan_id);
return SWITCH_STATUS_FALSE;
}
@ -867,7 +867,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
}
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "TFLAG_IO is not set in channel %s device %d:%d!\n", name, span_id, chan_id);
goto fail;
}
@ -885,15 +885,15 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdmchan) * 10);
if (!(wflags & FTDM_WRITE)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id);
return SWITCH_STATUS_SUCCESS;
}
len = frame->datalen;
if (ftdm_channel_write(tech_pvt->ftdmchan, frame->data, frame->buflen, &len) != FTDM_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id);
if (++tech_pvt->write_error > FTDM_MAX_READ_WRITE_ERRORS) {
switch_log_printf(SWITCH_CHANNEL_LOG,
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel),
SWITCH_LOG_ERROR, "Too many I/O write errors on channel %s device %d:%d!\n", name, span_id, chan_id);
goto fail;
}
@ -904,7 +904,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
return SWITCH_STATUS_SUCCESS;
fail:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Error writing to channel %s device %d:%d!\n", name, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Error writing to channel %s device %d:%d!\n", name, span_id, chan_id);
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
return SWITCH_STATUS_GENERR;
@ -1245,7 +1245,7 @@ static ftdm_status_t on_channel_found(ftdm_channel_t *fchan, ftdm_caller_data_t
tech_init(hdata->tech_pvt, hdata->new_session, fchan, caller_data);
snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", span_id, chan_id, caller_data->dnis.digits);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
switch_channel_set_name(channel, name);
switch_channel_set_variable(channel, "freetdm_span_name", ftdm_channel_get_span_name(fchan));
switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", span_id);
@ -1273,7 +1273,7 @@ static ftdm_status_t on_channel_found(ftdm_channel_t *fchan, ftdm_caller_data_t
return FTDM_BREAK;
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Attached session %s to channel %d:%d\n", sess_uuid, span_id, chan_id);
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Attached session %s to channel %d:%d\n", sess_uuid, span_id, chan_id);
return FTDM_SUCCESS;
}

View File

@ -127,6 +127,7 @@ typedef struct profile_node_s {
switch_memory_pool_t *pool;
struct switch_caller_profile *next;
switch_call_direction_t direction;
switch_call_direction_t logical_direction;
profile_node_t *soft;
char *uuid_str;
char *clone_of;

View File

@ -633,6 +633,8 @@ SWITCH_DECLARE(int) switch_channel_test_app_flag_key(const char *app, switch_cha
SWITCH_DECLARE(void) switch_channel_set_bridge_time(switch_channel_t *channel);
SWITCH_DECLARE(void) switch_channel_set_hangup_time(switch_channel_t *channel);
SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel);
SWITCH_DECLARE(switch_call_direction_t) switch_channel_logical_direction(switch_channel_t *channel);
SWITCH_DECLARE(void) switch_channel_set_direction(switch_channel_t *channel, switch_call_direction_t direction);
SWITCH_DECLARE(switch_core_session_t *) switch_channel_get_session(switch_channel_t *channel);
SWITCH_DECLARE(char *) switch_channel_get_flag_string(switch_channel_t *channel);
SWITCH_DECLARE(char *) switch_channel_get_cap_string(switch_channel_t *channel);

View File

@ -109,6 +109,7 @@ typedef struct switch_device_stats_s {
uint32_t early;
uint32_t early_in;
uint32_t early_out;
uint32_t ring_wait;
} switch_device_stats_t;

View File

@ -27,6 +27,7 @@
* Bret McDanel <trixter AT 0xdecafbad dot com>
* Joseph Sullivan <jossulli@amazon.com>
* Raymond Chandler <intralanman@freeswitch.org>
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
*
* switch_types.h -- Data Types
*
@ -945,6 +946,7 @@ typedef enum {
SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE,
SWITCH_MESSAGE_INDICATE_STUN_ERROR,
SWITCH_MESSAGE_INDICATE_MEDIA_RENEG,
SWITCH_MESSAGE_REFER_EVENT,
SWITCH_MESSAGE_ANSWER_EVENT,
SWITCH_MESSAGE_PROGRESS_EVENT,
SWITCH_MESSAGE_RING_EVENT,
@ -1114,6 +1116,7 @@ typedef enum {
CCS_EARLY,
CCS_ACTIVE,
CCS_HELD,
CCS_RING_WAIT,
CCS_HANGUP,
CCS_UNHOLD
} switch_channel_callstate_t;

View File

@ -37,11 +37,17 @@
extern "C" {
#endif
#if UINTPTR_MAX == 0xffffffffffffffff
#define _fs__bits "64bit"
#else
#define _fs__bits "32bit"
#endif
#define SWITCH_VERSION_MAJOR "@SWITCH_VERSION_MAJOR@"
#define SWITCH_VERSION_MINOR "@SWITCH_VERSION_MINOR@"
#define SWITCH_VERSION_MICRO "@SWITCH_VERSION_MICRO@"
#define SWITCH_VERSION_REVISION "@SWITCH_VERSION_REVISION@"
#define SWITCH_VERSION_REVISION_HUMAN "@SWITCH_VERSION_REVISION_HUMAN@"
#define SWITCH_VERSION_REVISION "@SWITCH_VERSION_REVISION@" "~" _fs__bits
#define SWITCH_VERSION_REVISION_HUMAN "@SWITCH_VERSION_REVISION_HUMAN@" " " _fs__bits
#define SWITCH_VERSION_FULL SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO SWITCH_VERSION_REVISION
#define SWITCH_VERSION_FULL_HUMAN SWITCH_VERSION_MAJOR "." SWITCH_VERSION_MINOR "." SWITCH_VERSION_MICRO " " SWITCH_VERSION_REVISION_HUMAN

View File

@ -32,6 +32,8 @@
* David Weekly <david@weekly.org>
* Joao Mesquita <jmesquita@gmail.com>
* Raymond Chandler <intralanman@freeswitch.org>
* Seven Du <dujinfang@gmail.com>
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
*
* mod_conference.c -- Software Conference Bridge
*
@ -3605,6 +3607,7 @@ static void conference_loop_output(conference_member_t *member)
const char *ann = switch_channel_get_variable(channel, "conference_auto_outcall_announce");
const char *prefix = switch_channel_get_variable(channel, "conference_auto_outcall_prefix");
const char *maxwait = switch_channel_get_variable(channel, "conference_auto_outcall_maxwait");
const char *delimiter_val = switch_channel_get_variable(channel, "conference_auto_outcall_delimiter");
int to = 60;
int wait_sec = 2;
int loops = 0;
@ -3631,7 +3634,12 @@ static void conference_loop_output(conference_member_t *member)
int x = 0;
switch_assert(cpstr);
argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
if (!zstr(delimiter_val) && strlen(delimiter_val) == 1) {
char delimiter = *delimiter_val;
argc = switch_separate_string(cpstr, delimiter, argv, (sizeof(argv) / sizeof(argv[0])));
} else {
argc = switch_separate_string(cpstr, ',', argv, (sizeof(argv) / sizeof(argv[0])));
}
for (x = 0; x < argc; x++) {
char *dial_str = switch_mprintf("%s%s", switch_str_nil(prefix), argv[x]);
switch_assert(dial_str);

View File

@ -3622,6 +3622,9 @@ static switch_call_cause_t pickup_outgoing_channel(switch_core_session_t *sessio
switch_core_session_set_private(nsession, tech_pvt);
nchannel = switch_core_session_get_channel(nsession);
switch_channel_set_cap(nchannel, CC_PROXY_MEDIA);
switch_channel_set_cap(nchannel, CC_BYPASS_MEDIA);
caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
switch_channel_set_caller_profile(nchannel, caller_profile);

View File

@ -1067,7 +1067,7 @@ static void do_unbridge(switch_core_session_t *consumer_session, switch_core_ses
switch_channel_event_set_data(consumer_channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", MANUAL_QUEUE_NAME);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "bridge-consumer-stop");
if (use_count) {
if (outbound_id) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", use_count);
}
@ -2218,7 +2218,7 @@ SWITCH_STANDARD_API(fifo_add_outbound_function)
}
static void dec_use_count(switch_core_session_t *session, switch_bool_t send_event)
static void dec_use_count(switch_core_session_t *session, const char *type)
{
char *sql;
const char *outbound_id = NULL;
@ -2226,8 +2226,6 @@ static void dec_use_count(switch_core_session_t *session, switch_bool_t send_eve
long now = (long) switch_epoch_time_now(NULL);
switch_channel_t *channel = switch_core_session_get_channel(session);
do_unbridge(session, NULL);
if ((outbound_id = switch_channel_get_variable(channel, "fifo_outbound_uuid"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s untracking call on uuid %s!\n", switch_channel_get_name(channel), outbound_id);
@ -2242,11 +2240,14 @@ static void dec_use_count(switch_core_session_t *session, switch_bool_t send_eve
fifo_dec_use_count(outbound_id);
}
if (send_event) {
do_unbridge(session, NULL);
if (type) {
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", MANUAL_QUEUE_NAME);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-stop");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", type);
if (outbound_id) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(outbound_id));
@ -2262,7 +2263,7 @@ static switch_status_t hanguphook(switch_core_session_t *session)
switch_channel_state_t state = switch_channel_get_state(channel);
if (state >= CS_HANGUP && !switch_channel_test_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_DID_HOOK)) {
dec_use_count(session, SWITCH_TRUE);
dec_use_count(session, "manual");
switch_core_event_hook_remove_state_change(session, hanguphook);
switch_channel_set_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_DID_HOOK);
}
@ -2325,6 +2326,9 @@ SWITCH_STANDARD_APP(fifo_track_call_function)
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", MANUAL_QUEUE_NAME);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-start");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", data);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(data));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", "manual");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Name", cid_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Number", cid_number);
switch_event_fire(&event);
@ -2729,16 +2733,33 @@ SWITCH_STANDARD_APP(fifo_function)
const char *url = NULL;
const char *caller_uuid = NULL;
const char *outbound_id = switch_channel_get_variable(channel, "fifo_outbound_uuid");
switch_event_t *event;
const char *cid_name = NULL, *cid_number = NULL;
//const char *track_use_count = switch_channel_get_variable(channel, "fifo_track_use_count");
//int do_track = switch_true(track_use_count);
if (switch_core_event_hook_remove_receive_message(session, messagehook) == SWITCH_STATUS_SUCCESS) {
dec_use_count(session, SWITCH_FALSE);
dec_use_count(session, NULL);
switch_core_event_hook_remove_state_change(session, hanguphook);
switch_channel_clear_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_TRACKING);
}
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
cid_name = switch_channel_get_variable(channel, "callee_id_name");
cid_number = switch_channel_get_variable(channel, "callee_id_number");
if (!cid_name) {
cid_name = switch_channel_get_variable(channel, "destination_number");
}
if (!cid_number) {
cid_number = cid_name;
}
} else {
cid_name = switch_channel_get_variable(channel, "caller_id_name");
cid_number = switch_channel_get_variable(channel, "caller_id_number");
}
if (!zstr(strat_str)) {
if (!strcasecmp(strat_str, "more_ppl")) {
strat = STRAT_MORE_PPL;
@ -3148,6 +3169,22 @@ SWITCH_STANDARD_APP(fifo_function)
}
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", argv[0]);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-start");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", "onhook");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Name", cid_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Caller-CID-Number", cid_number);
if (outbound_id) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(outbound_id));
}
switch_event_fire(&event);
}
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", argv[0]);
@ -3221,6 +3258,19 @@ SWITCH_STANDARD_APP(fifo_function)
}
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Name", arg_fifo_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Action", "channel-consumer-stop");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Type", "onhook");
if (outbound_id) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Outbound-ID", outbound_id);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "FIFO-Consumer-Use-Count", "%d", fifo_get_use_count(outbound_id));
}
switch_event_fire(&event);
}
del_bridge_call(switch_core_session_get_uuid(session));
del_bridge_call(switch_core_session_get_uuid(other_session));

View File

@ -1,6 +1,6 @@
BASE=../../../..
MONGO_CXX_DRIVER_VERSION=v1.8
MONGO_CXX_DRIVER_VERSION=v2.4
MONGO_CXX_DRIVER_URL=http://downloads.mongodb.org/cxx-driver
MONGO_CXX_DRIVER_TARBALL=mongodb-linux-x86_64-$(MONGO_CXX_DRIVER_VERSION)-latest.tgz
MONGO_CXX_DRIVER_SRC=$(BASE)/libs/mongo-cxx-driver-$(MONGO_CXX_DRIVER_VERSION)
@ -9,7 +9,7 @@ LIBMONGOCLIENT_A =$(MONGO_CXX_DRIVER_SRC)/libmongoclient.a
LOCAL_SOURCES=mongo_conn.cpp
LOCAL_OBJS=mongo_conn.o
LOCAL_CFLAGS=-I$(MONGO_CXX_DRIVER_SRC)/mongo
LOCAL_CFLAGS=-I$(MONGO_CXX_DRIVER_SRC)/src
LOCAL_LIBADD=$(LIBMONGOCLIENT_A)
LOCAL_LDFLAGS=-lboost_thread -lboost_filesystem-mt -lboost_system-mt
MODDIR=$(shell pwd)

View File

@ -1,11 +1,11 @@
--- SConstruct.orig 2011-04-28 19:00:36.000000000 +0200
+++ SConstruct 2011-04-28 19:01:19.000000000 +0200
@@ -45,7 +45,7 @@
linux = True
--- SConstruct 2013-10-30 17:18:51.160645496 -0400
+++ new 2013-10-30 17:22:18.790072856 -0400
@@ -78,7 +78,7 @@
env['DIST_ARCHIVE_SUFFIX'] = '.tgz'
if nix:
- env.Append( CPPFLAGS=" -O3" )
+ env.Append( CPPFLAGS=" -I../pcre -fPIC -O3" )
env.Append( LIBS=["pthread"] )
- env.Append(CCFLAGS=["-O3", "-pthread"])
+ env.Append(CCFLAGS=["-I../pcre", "-fPIC", "-O3", "-pthread"])
if linux:
env.Append( LINKFLAGS=" -Wl,--as-needed -Wl,-zdefs " )
env.Append(LINKFLAGS=["-pthread"])

View File

@ -1,6 +1,6 @@
/*
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
* Copyright (C) 2005-2013, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
@ -22,7 +22,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
*
* Tamas Cseke <cstomi.levlist@gmail.com>
*
* mod_mongo.cpp -- API for MongoDB
@ -53,7 +53,7 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
switch_assert(ns != NULL);
if ((json_query = strchr(ns, DELIMITER))) {
*json_query++ = '\0';
*json_query++ = '\0';
}
if (!zstr(ns) && !zstr(json_query)) {
@ -62,7 +62,7 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
BSONObj out;
BSONObjBuilder cmd;
cmd.append("mapreduce", conn->nsGetCollection(ns));
cmd.append("mapreduce", nsGetCollection(ns));
if (!zstr(globals.map)) {
cmd.appendCode("map", globals.map);
}
@ -79,10 +79,10 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
conn = mongo_connection_pool_get(globals.conn_pool);
if (conn) {
conn->runCommand(conn->nsGetDB(ns), cmd.done(), out);
conn->runCommand(nsGetDB(ns), cmd.done(), out);
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
stream->write_function(stream, "-OK\n%s\n", out.toString().c_str());
stream->write_function(stream, "-OK\n%s\n", out.jsonString().c_str());
} else {
stream->write_function(stream, "-ERR\nNo connection\n");
}
@ -93,7 +93,7 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
}
} else {
stream->write_function(stream, "-ERR\n%s\n", MAPREDUCE_SYNTAX);
stream->write_function(stream, "-ERR\n%s\n", MAPREDUCE_SYNTAX);
}
switch_safe_free(ns);
@ -104,50 +104,50 @@ SWITCH_STANDARD_API(mongo_mapreduce_function)
SWITCH_STANDARD_API(mongo_find_one_function)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
char *ns = NULL, *json_query = NULL, *json_fields = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
char *ns = NULL, *json_query = NULL, *json_fields = NULL;
ns = strdup(cmd);
switch_assert(ns != NULL);
ns = strdup(cmd);
switch_assert(ns != NULL);
if ((json_query = strchr(ns, DELIMITER))) {
*json_query++ = '\0';
if ((json_fields = strchr(json_query, DELIMITER))) {
*json_fields++ = '\0';
}
}
if ((json_query = strchr(ns, DELIMITER))) {
*json_query++ = '\0';
if ((json_fields = strchr(json_query, DELIMITER))) {
*json_fields++ = '\0';
}
}
if (!zstr(ns) && !zstr(json_query) && !zstr(json_fields)) {
if (!zstr(ns) && !zstr(json_query) && !zstr(json_fields)) {
DBClientBase *conn = NULL;
DBClientBase *conn = NULL;
try {
BSONObj query = fromjson(json_query);
BSONObj fields = fromjson(json_fields);
try {
BSONObj query = fromjson(json_query);
BSONObj fields = fromjson(json_fields);
conn = mongo_connection_pool_get(globals.conn_pool);
if (conn) {
BSONObj res = conn->findOne(ns, Query(query), &fields);
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
conn = mongo_connection_pool_get(globals.conn_pool);
if (conn) {
BSONObj res = conn->findOne(ns, Query(query), &fields);
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_FALSE);
stream->write_function(stream, "-OK\n%s\n", res.toString().c_str());
} else {
stream->write_function(stream, "-ERR\nNo connection\n");
}
} catch (DBException &e) {
if (conn) {
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_TRUE);
}
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
}
stream->write_function(stream, "-OK\n%s\n", res.jsonString().c_str());
} else {
stream->write_function(stream, "-ERR\nNo connection\n");
}
} catch (DBException &e) {
if (conn) {
mongo_connection_pool_put(globals.conn_pool, conn, SWITCH_TRUE);
}
stream->write_function(stream, "-ERR\n%s\n", e.toString().c_str());
}
} else {
} else {
stream->write_function(stream, "-ERR\n%s\n", FIND_ONE_SYNTAX);
}
}
switch_safe_free(ns);
switch_safe_free(ns);
return status;
return status;
}
static switch_status_t config(void)
@ -214,21 +214,21 @@ SWITCH_MODULE_DEFINITION(mod_mongo, mod_mongo_load, mod_mongo_shutdown, NULL);
SWITCH_MODULE_LOAD_FUNCTION(mod_mongo_load)
{
switch_api_interface_t *api_interface;
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
switch_application_interface_t *app_interface;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
memset(&globals, 0, sizeof(globals));
memset(&globals, 0, sizeof(globals));
if (config() != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
SWITCH_ADD_API(api_interface, "mongo_find_one", "findOne", mongo_find_one_function, FIND_ONE_SYNTAX);
SWITCH_ADD_API(api_interface, "mongo_mapreduce", "Map/Reduce", mongo_mapreduce_function, MAPREDUCE_SYNTAX);
if (config() != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
return SWITCH_STATUS_SUCCESS;
SWITCH_ADD_API(api_interface, "mongo_find_one", "findOne", mongo_find_one_function, FIND_ONE_SYNTAX);
SWITCH_ADD_API(api_interface, "mongo_mapreduce", "Map/Reduce", mongo_mapreduce_function, MAPREDUCE_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_mongo_shutdown)

View File

@ -1,6 +1,6 @@
/*
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
* Copyright (C) 2005-2013, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
@ -32,22 +32,19 @@
#ifndef MOD_MONGO_H
#define MOD_MONGO_H
#include <client/dbclient.h>
#include <client/connpool.h>
#include <db/json.h>
#include <bson/bson.h>
#include <mongo/client/dbclient.h>
using namespace mongo;
typedef struct {
char *conn_str;
char *conn_str;
switch_size_t min_connections;
switch_size_t max_connections;
switch_size_t size;
switch_queue_t *connections;
switch_mutex_t *mutex;
switch_memory_pool_t *pool;
switch_size_t min_connections;
switch_size_t max_connections;
switch_size_t size;
switch_queue_t *connections;
switch_mutex_t *mutex;
switch_memory_pool_t *pool;
} mongo_connection_pool_t;
@ -56,7 +53,7 @@ switch_status_t mongo_connection_create(DBClientBase **connection, const char *c
void mongo_connection_destroy(DBClientBase **conn);
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
const char *conn_str);
const char *conn_str);
void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool);

View File

@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
* Copyright (C) 2005-2013, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
@ -42,162 +42,161 @@
switch_status_t mongo_connection_create(DBClientBase **connection, const char *conn_str)
{
DBClientBase *conn = NULL;
string conn_string(conn_str), err_msg;
ConnectionString cs = ConnectionString::parse(conn_string, err_msg);
switch_status_t status = SWITCH_STATUS_FALSE;
if (!cs.isValid()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't parse url: %s\n", err_msg.c_str());
return status;
}
DBClientBase *conn = NULL;
string conn_string(conn_str), err_msg;
ConnectionString cs = ConnectionString::parse(conn_string, err_msg);
switch_status_t status = SWITCH_STATUS_FALSE;
try {
conn = cs.connect(err_msg);
} catch (DBException &e) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't connect to mongo [%s]: %s\n", conn_str, err_msg.c_str());
return status;
}
if (!cs.isValid()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't parse url: %s\n", err_msg.c_str());
return status;
}
if (conn) {
*connection = conn;
status = SWITCH_STATUS_SUCCESS;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", conn_str);
}
try {
conn = cs.connect(err_msg);
} catch (DBException &e) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't connect to mongo [%s]: %s\n", conn_str, err_msg.c_str());
return status;
}
return status;
if (conn) {
*connection = conn;
status = SWITCH_STATUS_SUCCESS;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to mongo [%s]\n", conn_str);
}
return status;
}
void mongo_connection_destroy(DBClientBase **conn)
{
switch_assert(*conn != NULL);
delete *conn;
switch_assert(*conn != NULL);
delete *conn;
*conn = NULL;
*conn = NULL;
}
switch_status_t mongo_connection_pool_create(mongo_connection_pool_t **conn_pool, switch_size_t min_connections, switch_size_t max_connections,
const char *conn_str)
const char *conn_str)
{
switch_memory_pool_t *pool = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
mongo_connection_pool_t *cpool = NULL;
DBClientBase *conn = NULL;
switch_memory_pool_t *pool = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
mongo_connection_pool_t *cpool = NULL;
DBClientBase *conn = NULL;
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if (!(cpool = (mongo_connection_pool_t *)switch_core_alloc(pool, sizeof(mongo_connection_pool_t)))) {
switch_goto_status(SWITCH_STATUS_MEMERR, done);
}
if (!(cpool = (mongo_connection_pool_t *)switch_core_alloc(pool, sizeof(mongo_connection_pool_t)))) {
switch_goto_status(SWITCH_STATUS_MEMERR, done);
}
if ((status = switch_mutex_init(&cpool->mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
goto done;
}
if ((status = switch_mutex_init(&cpool->mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
goto done;
}
if ((status = switch_queue_create(&cpool->connections, max_connections, pool)) != SWITCH_STATUS_SUCCESS) {
goto done;
}
if ((status = switch_queue_create(&cpool->connections, max_connections, pool)) != SWITCH_STATUS_SUCCESS) {
goto done;
}
cpool->min_connections = min_connections;
cpool->max_connections = max_connections;
cpool->conn_str = switch_core_strdup(pool, conn_str);
cpool->pool = pool;
cpool->min_connections = min_connections;
cpool->max_connections = max_connections;
cpool->conn_str = switch_core_strdup(pool, conn_str);
cpool->pool = pool;
for (cpool->size = 0; cpool->size < min_connections; cpool->size++) {
for (cpool->size = 0; cpool->size < min_connections; cpool->size++) {
if (mongo_connection_create(&conn, conn_str) == SWITCH_STATUS_SUCCESS) {
mongo_connection_pool_put(cpool, conn, SWITCH_FALSE);
} else {
break;
}
}
if (mongo_connection_create(&conn, conn_str) == SWITCH_STATUS_SUCCESS) {
mongo_connection_pool_put(cpool, conn, SWITCH_FALSE);
} else {
break;
}
}
done:
if (status == SWITCH_STATUS_SUCCESS) {
*conn_pool = cpool;
} else {
switch_core_destroy_memory_pool(&pool);
}
if (status == SWITCH_STATUS_SUCCESS) {
*conn_pool = cpool;
} else {
switch_core_destroy_memory_pool(&pool);
}
return status;
return status;
}
void mongo_connection_pool_destroy(mongo_connection_pool_t **conn_pool)
{
mongo_connection_pool_t *cpool = *conn_pool;
void *data = NULL;
mongo_connection_pool_t *cpool = *conn_pool;
void *data = NULL;
switch_assert(cpool != NULL);
switch_assert(cpool != NULL);
while (switch_queue_trypop(cpool->connections, &data) == SWITCH_STATUS_SUCCESS) {
mongo_connection_destroy((DBClientBase **)&data);
}
while (switch_queue_trypop(cpool->connections, &data) == SWITCH_STATUS_SUCCESS) {
mongo_connection_destroy((DBClientBase **)&data);
}
switch_mutex_destroy(cpool->mutex);
switch_core_destroy_memory_pool(&cpool->pool);
switch_mutex_destroy(cpool->mutex);
switch_core_destroy_memory_pool(&cpool->pool);
*conn_pool = NULL;
*conn_pool = NULL;
}
DBClientBase *mongo_connection_pool_get(mongo_connection_pool_t *conn_pool)
{
DBClientBase *conn = NULL;
void *data = NULL;
DBClientBase *conn = NULL;
void *data = NULL;
switch_assert(conn_pool != NULL);
switch_assert(conn_pool != NULL);
switch_mutex_lock(conn_pool->mutex);
switch_mutex_lock(conn_pool->mutex);
if (switch_queue_trypop(conn_pool->connections, &data) == SWITCH_STATUS_SUCCESS) {
conn = (DBClientBase *) data;
} else if (mongo_connection_create(&conn, conn_pool->conn_str) == SWITCH_STATUS_SUCCESS) {
if (++conn_pool->size > conn_pool->max_connections) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Connection pool is empty. You may want to increase 'max-connections'\n");
}
}
if (switch_queue_trypop(conn_pool->connections, &data) == SWITCH_STATUS_SUCCESS) {
conn = (DBClientBase *) data;
} else if (mongo_connection_create(&conn, conn_pool->conn_str) == SWITCH_STATUS_SUCCESS) {
if (++conn_pool->size > conn_pool->max_connections) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Connection pool is empty. You may want to increase 'max-connections'\n");
}
}
switch_mutex_unlock(conn_pool->mutex);
switch_mutex_unlock(conn_pool->mutex);
#ifdef MONGO_POOL_DEBUG
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL get: size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL get: size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
#endif
return conn;
return conn;
}
switch_status_t mongo_connection_pool_put(mongo_connection_pool_t *conn_pool, DBClientBase *conn, switch_bool_t destroy)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_assert(conn_pool != NULL);
switch_assert(conn != NULL);
switch_assert(conn_pool != NULL);
switch_assert(conn != NULL);
switch_mutex_lock(conn_pool->mutex);
if (destroy || conn_pool->size > conn_pool->max_connections) {
switch_mutex_lock(conn_pool->mutex);
if (destroy || conn_pool->size > conn_pool->max_connections) {
#ifdef MONGO_POOL_DEBUG
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: Destroy connection %p\n", conn);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: Destroy connection %p\n", conn);
#endif
mongo_connection_destroy(&conn);
conn_pool->size--;
} else {
mongo_connection_destroy(&conn);
conn_pool->size--;
} else {
#ifdef MONGO_POOL_DEBUG
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: push connection %p\n", conn);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: push connection %p\n", conn);
#endif
status = switch_queue_push(conn_pool->connections, conn);
}
status = switch_queue_push(conn_pool->connections, conn);
}
switch_mutex_unlock(conn_pool->mutex);
switch_mutex_unlock(conn_pool->mutex);
#ifdef MONGO_POOL_DEBUG
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: put size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "POOL: put size %d conn: %p\n", (int) switch_queue_size(conn_pool->connections), conn);
#endif
return status;
return status;
}
/* For Emacs:

View File

@ -36,36 +36,231 @@
SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load);
SWITCH_MODULE_DEFINITION(mod_opus, mod_opus_load, NULL, NULL);
/*! \brief Various codec settings */
struct opus_codec_settings {
int useinbandfec;
int usedtx;
int maxaveragebitrate;
int stereo;
int cbr;
int sprop_maxcapturerate;
int sprop_stereo;
int maxptime;
int minptime;
int ptime;
int samplerate;
};
typedef struct opus_codec_settings opus_codec_settings_t;
static opus_codec_settings_t default_codec_settings = {
/*.useinbandfec */ 1,
/*.usedtx */ 1,
/*.maxaveragebitrate */ 30000,
/*.stereo*/ 0,
/*.cbr*/ 0,
/*.sprop_maxcapturerate*/ 0,
/*.sprop_stereo*/ 0,
/*.maxptime*/ 0,
/*.minptime*/ 0,
/*.ptime*/ 0,
/*.samplerate*/ 0
};
struct opus_context {
OpusEncoder *encoder_object;
OpusDecoder *decoder_object;
int frame_size;
};
static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
{
if (codec_fmtp) {
opus_codec_settings_t local_settings = { 0 };
opus_codec_settings_t *codec_settings = &local_settings;
if (codec_fmtp->private_info) {
codec_settings = codec_fmtp->private_info;
if (zstr(fmtp)) {
memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
}
}
if (fmtp) {
int x, argc;
char *argv[10];
char *fmtp_dup = strdup(fmtp);
switch_assert(fmtp_dup);
argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
for (x = 0; x < argc; x++) {
char *data = argv[x];
char *arg;
switch_assert(data);
while (*data == ' ') {
data++;
}
if ((arg = strchr(data, '='))) {
*arg++ = '\0';
if (codec_settings) {
if (!strcasecmp(data, "useinbandfec")) {
codec_settings->useinbandfec = switch_true(arg);
}
if (!strcasecmp(data, "usedtx")) {
codec_settings->usedtx = switch_true(arg);
}
if (!strcasecmp(data, "sprop-maxcapturerate")) {
codec_settings->sprop_maxcapturerate = atoi(arg);
}
if (!strcasecmp(data, "maxptime")) {
codec_settings->maxptime = atoi(arg);
}
if (!strcasecmp(data, "minptime")) {
codec_settings->minptime = atoi(arg);
}
if (!strcasecmp(data, "ptime")) {
codec_settings->ptime = atoi(arg);
codec_fmtp->microseconds_per_packet = codec_settings->ptime * 1000;
}
if (!strcasecmp(data, "samplerate")) {
codec_settings->samplerate = atoi(arg);
codec_fmtp->actual_samples_per_second = codec_settings->samplerate;
}
if (!strcasecmp(data, "maxaveragebitrate")) {
codec_settings->maxaveragebitrate = atoi(arg);
switch(codec_fmtp->actual_samples_per_second) {
case 8000:
{
if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) {
codec_settings->maxaveragebitrate = 20000;
}
break;
}
case 12000:
{
if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) {
codec_settings->maxaveragebitrate = 25000;
}
break;
}
case 16000:
{
if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) {
codec_settings->maxaveragebitrate = 30000;
}
break;
}
case 24000:
{
if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) {
codec_settings->maxaveragebitrate = 40000;
}
break;
}
default:
/* this should never happen but 20000 is common among all rates */
codec_settings->maxaveragebitrate = 20000;
break;
}
codec_fmtp->bits_per_second = codec_settings->maxaveragebitrate;
}
}
}
}
free(fmtp_dup);
}
//codec_fmtp->bits_per_second = bit_rate;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *pool)
{
char buf[256] = "";
if (settings->useinbandfec) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1;");
}
if (settings->usedtx) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1;");
}
if (settings->maxaveragebitrate) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d;", settings->maxaveragebitrate);
}
if (settings->ptime) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ptime=%d;", settings->ptime);
}
if (settings->minptime) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "minptime=%d;", settings->minptime);
}
if (settings->maxptime) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d;", settings->maxptime);
}
if (settings->samplerate) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d;", settings->samplerate);
}
if (end_of(buf) == ';') {
end_of(buf) = '\0';
}
return switch_core_strdup(pool, buf);
}
static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
{
struct opus_context *context = NULL;
int encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
int decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
switch_codec_fmtp_t codec_fmtp;
opus_codec_settings_t opus_codec_settings = { 0 };
if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) {
return SWITCH_STATUS_FALSE;
}
context->frame_size = codec->implementation->samples_per_packet;
memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
codec_fmtp.private_info = &opus_codec_settings;
switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp);
codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool);
if (encoding) {
/* come up with a way to specify these */
int bitrate_bps = codec->implementation->bits_per_second;
int bitrate_bps = OPUS_AUTO;
int use_vbr = 1;
int complexity = 10;
int use_inbandfec = 1;
int use_dtx = 1;
int bandwidth = OPUS_BANDWIDTH_FULLBAND;
int err;
int samplerate = opus_codec_settings.samplerate ? opus_codec_settings.samplerate : codec->implementation->actual_samples_per_second;
context->encoder_object = opus_encoder_create(codec->implementation->actual_samples_per_second,
codec->implementation->number_of_channels, OPUS_APPLICATION_VOIP, &err);
context->encoder_object = opus_encoder_create(samplerate,
codec->implementation->number_of_channels,
OPUS_APPLICATION_VOIP, &err);
if (err != OPUS_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err));
@ -73,12 +268,24 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
}
opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps));
opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(bandwidth));
if (codec->implementation->actual_samples_per_second == 8000) {
opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
} else {
opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
}
opus_encoder_ctl(context->encoder_object, OPUS_SET_VBR(use_vbr));
opus_encoder_ctl(context->encoder_object, OPUS_SET_COMPLEXITY(complexity));
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(use_inbandfec));
opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(use_dtx));
if (opus_codec_settings.useinbandfec) {
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(opus_codec_settings.useinbandfec));
}
if (opus_codec_settings.usedtx) {
opus_encoder_ctl(context->encoder_object, OPUS_SET_DTX(opus_codec_settings.usedtx));
}
}
if (decoding) {
@ -143,7 +350,7 @@ static switch_status_t switch_opus_encode(switch_codec_t *codec,
if (len > 1275) len = 1275;
bytes = opus_encode(context->encoder_object, (void *) decoded_data, decoded_data_len / 2, (unsigned char *) encoded_data, len);
if (bytes > 0) {
*encoded_data_len = (uint32_t) bytes;
return SWITCH_STATUS_SUCCESS;
@ -186,26 +393,40 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
int mss = 10000;
int x = 0;
int rate = 48000;
int bits = 32000;
int bits = 0;
char *dft_fmtp = NULL;
opus_codec_settings_t settings = { 0 };
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "OPUS (STANDARD)");
codec_interface->parse_fmtp = switch_opus_fmtp_parse;
settings = default_codec_settings;
for (x = 0; x < 3; x++) {
settings.ptime = mss / 1000;
settings.maxptime = settings.ptime;
settings.minptime = settings.ptime;
settings.samplerate = rate;
dft_fmtp = gen_fmtp(&settings, pool);
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
116, /* the IANA code number */
"opus",/* the IANA code name */
NULL, /* default fmtp to send (can be overridden by the init function) */
rate, /* samples transferred per second */
dft_fmtp, /* default fmtp to send (can be overridden by the init function) */
48000, /* samples transferred per second */
rate, /* actual samples transferred per second */
bits, /* bits transferred per second */
mss, /* number of microseconds per frame */
samples, /* number of samples per frame */
bytes, /* number of bytes per frame decompressed */
0, /* number of bytes per frame compressed */
1, /* number of channels represented */
1,/* number of channels represented */
1, /* number of frames per network packet */
switch_opus_init, /* function to initialize a codec handle using this implementation */
switch_opus_encode, /* function to encode raw data into encoded data */
@ -218,6 +439,44 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
}
samples = 80;
bytes = 160;
mss = 10000;
rate = 8000;
for (x = 0; x < 3; x++) {
settings.ptime = mss / 1000;
settings.maxptime = settings.ptime;
settings.minptime = settings.ptime;
settings.samplerate = rate;
dft_fmtp = gen_fmtp(&settings, pool);
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
116, /* the IANA code number */
"opus",/* the IANA code name */
dft_fmtp, /* default fmtp to send (can be overridden by the init function) */
48000, /* samples transferred per second */
rate, /* actual samples transferred per second */
bits, /* bits transferred per second */
mss, /* number of microseconds per frame */
samples, /* number of samples per frame */
bytes, /* number of bytes per frame decompressed */
0, /* number of bytes per frame compressed */
1,/* number of channels represented */
1, /* number of frames per network packet */
switch_opus_init, /* function to initialize a codec handle using this implementation */
switch_opus_encode, /* function to encode raw data into encoded data */
switch_opus_decode, /* function to decode encoded data into raw data */
switch_opus_destroy); /* deinitalize a codec handle using this implementation */
bytes += 160;
samples += 80;
mss += 10000;
}
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}

View File

@ -304,7 +304,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session)
static switch_status_t channel_on_destroy(switch_core_session_t *session)
{
crtp_private_t *tech_pvt = switch_core_session_get_private(session);
crtp_private_t *tech_pvt = NULL;
if ((tech_pvt = switch_core_session_get_private(session))) {

View File

@ -179,7 +179,7 @@ static void extract_header_vars(sofia_profile_t *profile, sip_t const *sip,
if (sip->sip_route) {
if ((full = sip_header_as_string(nh->nh_home, (void *) sip->sip_route))) {
const char *v = switch_channel_get_variable(channel, "sip_full_route");
if (!v) {
if (!v) {
switch_channel_set_variable(channel, "sip_full_route", full);
}
su_free(nh->nh_home, full);
@ -5755,9 +5755,9 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
if (r_sdp) {
sdp_parser_t *parser;
sdp_session_t *sdp;
tech_pvt->remote_sdp_str = NULL;
switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
printf("WTF %d\n---\n%s\n---\n%s", (profile->ndlb & PFLAG_NDLB_ALLOW_NONDUP_SDP), tech_pvt->remote_sdp_str, r_sdp);
if (!(profile->ndlb & PFLAG_NDLB_ALLOW_NONDUP_SDP) || (!zstr(tech_pvt->remote_sdp_str) && !strcmp(tech_pvt->remote_sdp_str, r_sdp))) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Duplicate SDP\n%s\n", r_sdp);
is_dup_sdp = 1;
@ -5855,6 +5855,39 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
if (r_sdp) {
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
char ibuf[35] = "", pbuf[35] = "";
const char *ptr;
if ((ptr = switch_stristr("c=IN IP4", r_sdp))) {
int i = 0;
ptr += 8;
while(*ptr == ' ') {
ptr++;
}
while(*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
ibuf[i++] = *ptr++;
}
switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, ibuf);
}
if ((ptr = switch_stristr("m=audio", r_sdp))) {
int i = 0;
ptr += 7;
while(*ptr == ' ') {
ptr++;
}
while(*ptr && *ptr != ' ' && *ptr != '\r' && *ptr != '\n') {
pbuf[i++] = *ptr++;
}
switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, pbuf);
}
if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA");
}
@ -6785,6 +6818,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
exten = (char *) refer_to->r_url->url_user;
}
switch_core_session_queue_indication(session, SWITCH_MESSAGE_REFER_EVENT);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
switch_channel_set_variable(tech_pvt->channel, "transfer_disposition", "recv_replace");

View File

@ -39,13 +39,13 @@
switch_cache_db_handle_t *_sofia_glue_get_db_handle(sofia_profile_t *profile, const char *file, const char *func, int line);
#define sofia_glue_get_db_handle(_p) _sofia_glue_get_db_handle(_p, __FILE__, __SWITCH_FUNC__, __LINE__)
static int get_channels(const switch_codec_implementation_t *imp)
static int get_channels(const char *name, int dft)
{
if (!strcasecmp(imp->iananame, "opus")) {
if (!strcasecmp(name, "opus")) {
return 2; /* IKR???*/
}
return imp->number_of_channels;
return dft ? dft : 1;
}
void sofia_glue_set_udptl_image_sdp(private_object_t *tech_pvt, switch_t38_options_t *t38_options, int insist)
@ -317,7 +317,7 @@ static void generate_m(private_object_t *tech_pvt, char *buf, size_t buflen,
}
if (tech_pvt->ianacodes[i] > 95 || verbose_sdp) {
int channels = get_channels(imp);
int channels = get_channels(imp->iananame, imp->number_of_channels);
if (channels > 1) {
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", tech_pvt->ianacodes[i], imp->iananame, rate, channels);
@ -547,6 +547,10 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
rate = tech_pvt->adv_rm_rate;
if (!tech_pvt->adv_channels) {
tech_pvt->adv_channels = get_channels(tech_pvt->rm_encoding, 1);
}
if (tech_pvt->adv_channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n",
tech_pvt->agreed_pt, tech_pvt->rm_encoding, rate, tech_pvt->adv_channels);
@ -776,7 +780,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, switch
rate = imp->samples_per_second;
}
channels = get_channels(imp);
channels = get_channels(imp->iananame, imp->number_of_channels);
if (channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", ianacode, imp->iananame,

View File

@ -11,6 +11,7 @@ LOCAL_OBJS= $(IKS_LA) \
nlsml.o \
rayo_components.o \
rayo_elements.o \
rayo_fax_components.o \
rayo_input_component.o \
rayo_output_component.o \
rayo_prompt_component.o \
@ -23,6 +24,7 @@ LOCAL_SOURCES= \
nlsml.c \
rayo_components.c \
rayo_elements.c \
rayo_fax_components.c \
rayo_input_component.c \
rayo_output_component.c \
rayo_prompt_component.c \

View File

@ -16,6 +16,12 @@
<param name="default-recognizer" value="pocketsphinx"/>
</input>
<!-- send/receivefax component params -->
<fax>
<!-- where to store incoming faxes -->
<param name="receivefax-file-prefix" value="/tmp/"/>
</fax>
<!-- XMPP server domain -->
<domain name="$${rayo_domain_name}" shared-secret="ClueCon">
<!-- use this instead if you want secure XMPP client to server connections. Put .crt and .key file in freeswitch/certs -->
@ -65,6 +71,7 @@
<alias name="speed-down" target="output"><![CDATA[<speed-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
<alias name="volume-up" target="output"><![CDATA[<volume-up xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
<alias name="volume-down" target="output"><![CDATA[<volume-down xmlns="urn:xmpp:rayo:output:1"/>]]></alias>
<alias name="receivefax" target="call"><![CDATA[<receivefax xmlns="urn:xmpp:rayo:fax:1"/>]]></alias>
<alias name="record" target="call"><![CDATA[<record xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
<alias name="record_pause" target="record"><![CDATA[<pause xmlns="urn:xmpp:rayo:record:1"/>]]></alias>
<alias name="record_resume" target="record"><![CDATA[<resume xmlns="urn:xmpp:rayo:record:1"/>]]></alias>

View File

@ -126,6 +126,8 @@ struct rayo_call {
switch_hash_t *pcps;
/** current idle start time */
switch_time_t idle_start_time;
/** true if fax is in progress */
int faxing;
/** 1 if joined to call, 2 if joined to mixer */
int joined;
/** pending join */
@ -950,6 +952,7 @@ static void rayo_call_cleanup(struct rayo_actor *actor)
iks_delete(revent);
switch_event_destroy(&event);
switch_core_hash_destroy(&call->pcps);
}
/**
@ -963,11 +966,35 @@ const char *rayo_call_get_dcp_jid(struct rayo_call *call)
/**
* @param call the Rayo call
* @return true if joined
* @return true if joined (or a join is in progress)
*/
static int rayo_call_is_joined(struct rayo_call *call)
int rayo_call_is_joined(struct rayo_call *call)
{
return call->joined;
return call->joined || call->pending_join_request;
}
/**
* @param call to check if faxing
* @return true if faxing is in progress
*/
int rayo_call_is_faxing(struct rayo_call *call)
{
return call->faxing;
}
/**
* Set faxing flag if faxing is not in progress
* @param call the call to flag
* @param faxing true if faxing is in progress
* @return true if set, false if can't set because faxing is already in progress. Reset always succeeds.
*/
int rayo_call_set_faxing(struct rayo_call *call, int faxing)
{
if (!faxing || (faxing && !call->faxing)) {
call->faxing = faxing;
return 1;
}
return 0;
}
#define RAYO_MIXER_LOCATE(mixer_name) rayo_mixer_locate(mixer_name, __FILE__, __LINE__)
@ -1104,13 +1131,23 @@ static struct rayo_call *_rayo_call_create(const char *uuid, const char *file, i
return rayo_call_init(call, pool, uuid, file, line);
}
/**
* Mixer destructor
*/
static void rayo_mixer_cleanup(struct rayo_actor *actor)
{
struct rayo_mixer *mixer = RAYO_MIXER(actor);
switch_core_hash_destroy(&mixer->members);
switch_core_hash_destroy(&mixer->subscribers);
}
/**
* Initialize mixer
*/
static struct rayo_mixer *rayo_mixer_init(struct rayo_mixer *mixer, switch_memory_pool_t *pool, const char *name, const char *file, int line)
{
char *mixer_jid = switch_mprintf("%s@%s", name, RAYO_JID(globals.server));
rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, NULL, rayo_mixer_send, file, line);
rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, rayo_mixer_cleanup, rayo_mixer_send, file, line);
switch_core_hash_init(&mixer->members, pool);
switch_core_hash_init(&mixer->subscribers, pool);
switch_safe_free(mixer_jid);
@ -1281,6 +1318,7 @@ static void rayo_peer_server_cleanup(struct rayo_actor *actor)
RAYO_UNLOCK(client);
RAYO_DESTROY(client);
}
switch_core_hash_destroy(&rserver->clients);
switch_mutex_unlock(globals.clients_mutex);
}
@ -1942,6 +1980,12 @@ static iks *on_rayo_join(struct rayo_actor *call, struct rayo_message *msg, void
goto done;
}
if (rayo_call_is_faxing(RAYO_CALL(call))) {
/* can't join a call while it's faxing */
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "fax is in progress");
goto done;
}
if (RAYO_CALL(call)->pending_join_request) {
/* don't allow concurrent join requests */
response = iks_new_error_detailed(msg->payload, STANZA_ERROR_UNEXPECTED_REQUEST, "(un)join request is pending");
@ -2339,11 +2383,14 @@ static iks *on_iq_get_xmpp_disco(struct rayo_actor *server, struct rayo_message
iks *node = msg->payload;
iks *response = NULL;
iks *x;
iks *feature;
response = iks_new_iq_result(node);
x = iks_insert(response, "query");
iks_insert_attrib(x, "xmlns", IKS_NS_XMPP_DISCO);
x = iks_insert(x, "feature");
iks_insert_attrib(x, "var", RAYO_NS);
feature = iks_insert(x, "feature");
iks_insert_attrib(feature, "var", RAYO_NS);
feature = iks_insert(x, "feature");
iks_insert_attrib(feature, "var", RAYO_FAX_NS);
/* TODO The response MUST also include features for the application formats and transport methods supported by
* the responding entity, as described in the relevant specifications.
@ -3074,12 +3121,22 @@ static switch_status_t rayo_call_on_read_frame(switch_core_session_t *session, s
switch_time_t idle_start = call->idle_start_time;
int idle_duration_ms = (now - idle_start) / 1000;
/* detect idle session (rayo-client has stopped controlling call) and terminate call */
if (rayo_call_is_joined(call)) {
if (rayo_call_is_joined(call) || rayo_call_is_faxing(call)) {
call->idle_start_time = now;
} else if (idle_duration_ms > globals.max_idle_ms) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ending abandoned call. idle_duration_ms = %i ms\n", idle_duration_ms);
switch_channel_hangup(channel, RAYO_CAUSE_HANGUP);
}
/* check for break request */
{
const char *break_jid = switch_channel_get_variable(channel, "rayo_read_frame_interrupt");
struct rayo_actor *actor;
if (break_jid && (actor = RAYO_LOCATE(break_jid))) {
RAYO_UNLOCK(actor);
return SWITCH_STATUS_FALSE;
}
}
}
return SWITCH_STATUS_SUCCESS;
}

View File

@ -153,6 +153,9 @@ extern void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int l
#define RAYO_DESTROY(x) rayo_actor_destroy(RAYO_ACTOR(x), __FILE__, __LINE__)
#define RAYO_SEQ_NEXT(x) rayo_actor_seq_next(RAYO_ACTOR(x))
extern int rayo_call_is_joined(struct rayo_call *call);
extern int rayo_call_is_faxing(struct rayo_call *call);
extern int rayo_call_set_faxing(struct rayo_call *call, int faxing);
extern const char *rayo_call_get_dcp_jid(struct rayo_call *call);
#define rayo_mixer_get_name(mixer) RAYO_ID(mixer)

View File

@ -226,7 +226,8 @@ switch_status_t rayo_components_load(switch_loadable_module_interface_t **module
if (rayo_input_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_output_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_prompt_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_record_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) {
rayo_record_component_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS ||
rayo_fax_components_load(module_interface, pool, config_file) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
return SWITCH_STATUS_SUCCESS;
@ -241,6 +242,7 @@ switch_status_t rayo_components_shutdown(void)
rayo_output_component_shutdown();
rayo_prompt_component_shutdown();
rayo_record_component_shutdown();
rayo_fax_components_shutdown();
return SWITCH_STATUS_SUCCESS;
}

View File

@ -49,6 +49,9 @@
#define RAYO_PROMPT_NS RAYO_BASE "prompt:" RAYO_VERSION
#define RAYO_PROMPT_COMPLETE_NS RAYO_BASE "prompt:complete:" RAYO_VERSION
#define RAYO_FAX_NS RAYO_BASE "fax:" RAYO_VERSION
#define RAYO_FAX_COMPLETE_NS RAYO_BASE "fax:complete:" RAYO_VERSION
#define COMPONENT_COMPLETE_STOP "stop", RAYO_EXT_COMPLETE_NS
#define COMPONENT_COMPLETE_ERROR "error", RAYO_EXT_COMPLETE_NS
#define COMPONENT_COMPLETE_HANGUP "hangup", RAYO_EXT_COMPLETE_NS
@ -58,12 +61,14 @@ extern switch_status_t rayo_input_component_load(switch_loadable_module_interfac
extern switch_status_t rayo_output_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_prompt_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_record_component_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_fax_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file);
extern switch_status_t rayo_components_shutdown(void);
extern switch_status_t rayo_input_component_shutdown(void);
extern switch_status_t rayo_output_component_shutdown(void);
extern switch_status_t rayo_prompt_component_shutdown(void);
extern switch_status_t rayo_record_component_shutdown(void);
extern switch_status_t rayo_fax_components_shutdown(void);
extern void rayo_component_send_start(struct rayo_component *component, iks *iq);
extern void rayo_component_send_iq_error(struct rayo_component *component, iks *iq, const char *error_name, const char *error_type);

View File

@ -32,6 +32,7 @@
* <input> component validation
*/
ELEMENT(RAYO_INPUT)
ATTRIB(xmlns,, any)
STRING_ATTRIB(mode, any, "any,dtmf,voice")
OPTIONAL_ATTRIB(terminator,, dtmf_digit)
ATTRIB(recognizer,, any)
@ -48,10 +49,22 @@ ELEMENT(RAYO_INPUT)
ATTRIB(start-timers, true, bool)
ELEMENT_END
/**
* <join> command validation
*/
ELEMENT(RAYO_JOIN)
ATTRIB(xmlns,, any)
STRING_ATTRIB(direction, duplex, "send,recv,duplex")
STRING_ATTRIB(media, bridge, "bridge,direct")
ATTRIB(call-uri,, any)
ATTRIB(mixer-name,, any)
ELEMENT_END
/**
* <output> component validation
*/
ELEMENT(RAYO_OUTPUT)
ATTRIB(xmlns,, any)
ATTRIB(start-offset, 0, not_negative)
ATTRIB(start-paused, false, bool)
ATTRIB(repeat-interval, 0, not_negative)
@ -65,6 +78,7 @@ ELEMENT_END
* <output><seek> validation
*/
ELEMENT(RAYO_OUTPUT_SEEK)
ATTRIB(xmlns,, any)
STRING_ATTRIB(direction,, "forward,back")
ATTRIB(amount,-1, positive)
ELEMENT_END
@ -73,14 +87,23 @@ ELEMENT_END
* <prompt> component validation
*/
ELEMENT(RAYO_PROMPT)
ATTRIB(xmlns,, any)
ATTRIB(barge-in, true, bool)
ELEMENT_END
/**
* <receivefax> command validation
*/
ELEMENT(RAYO_RECEIVEFAX)
ATTRIB(xmlns,, any)
ELEMENT_END
/**
* <record> component validation
*/
ELEMENT(RAYO_RECORD)
ATTRIB(format, mp3, any)
ATTRIB(xmlns,, any)
ATTRIB(format, wav, any)
ATTRIB(start-beep, false, bool)
ATTRIB(stop-beep, false, bool)
ATTRIB(start-paused, false, bool)
@ -92,13 +115,10 @@ ELEMENT(RAYO_RECORD)
ELEMENT_END
/**
* <join> command validation
* <sendfax> command validation
*/
ELEMENT(RAYO_JOIN)
STRING_ATTRIB(direction, duplex, "send,recv,duplex")
STRING_ATTRIB(media, bridge, "bridge,direct")
ATTRIB(call-uri,, any)
ATTRIB(mixer-name,, any)
ELEMENT(RAYO_SENDFAX)
ATTRIB(xmlns,, any)
ELEMENT_END

View File

@ -32,11 +32,13 @@
#include "iks_helpers.h"
ELEMENT_DECL(RAYO_INPUT)
ELEMENT_DECL(RAYO_JOIN)
ELEMENT_DECL(RAYO_OUTPUT)
ELEMENT_DECL(RAYO_OUTPUT_SEEK)
ELEMENT_DECL(RAYO_PROMPT)
ELEMENT_DECL(RAYO_RECEIVEFAX)
ELEMENT_DECL(RAYO_RECORD)
ELEMENT_DECL(RAYO_JOIN)
ELEMENT_DECL(RAYO_SENDFAX)
#endif

View File

@ -0,0 +1,561 @@
/*
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2013, Grasshopper
*
* 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 mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is Grasshopper
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Rienzo <chris.rienzo@grasshopper.com>
*
* rayo_fax_components.c -- Rayo receivefax and sendfax components implementation
*
*/
#include "rayo_components.h"
#include "rayo_elements.h"
/**
* settings
*/
static struct {
const char *file_prefix;
} globals;
struct fax_component {
/** component base class */
struct rayo_component base;
/** Flag to stop fax */
int stop;
};
#define FAX_COMPONENT(x) ((struct fax_component *)x)
struct receivefax_component {
/** fax component base class */
struct fax_component base;
/** true if HTTP PUT needs to be done after fax is received */
int http_put_after_receive;
/** fax stored on local filesystem */
const char *local_filename;
/** fax final target (may be same as local filename) */
const char *filename;
};
#define RECEIVEFAX_COMPONENT(x) ((struct receivefax_component *)x)
#define FAX_FINISH "finish", RAYO_FAX_COMPLETE_NS
/**
* Start execution of call sendfax component
* @param call the call to send fax to
* @param msg the original request
* @param session_data the call's session
*/
static iks *start_sendfax_component(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
{
iks *iq = msg->payload;
switch_core_session_t *session = (switch_core_session_t *)session_data;
struct fax_component *sendfax_component = NULL;
iks *sendfax = iks_find(iq, "sendfax");
iks *response = NULL;
switch_event_t *execute_event = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_memory_pool_t *pool;
iks *document;
const char *fax_document;
const char *fax_header;
const char *fax_identity;
const char *pages;
/* validate attributes */
if (!VALIDATE_RAYO_SENDFAX(sendfax)) {
return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
}
/* fax is only allowed if the call is not currently joined */
if (rayo_call_is_joined(RAYO_CALL(call))) {
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "can't send fax on a joined call");
}
if (!rayo_call_set_faxing(RAYO_CALL(call), 1)) {
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "fax already in progress");
}
/* get fax document */
document = iks_find(sendfax, "document");
if (!document) {
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document");
}
fax_document = iks_find_attrib_soft(document, "url");
if (zstr(fax_document)) {
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document url");
}
/* is valid URL type? */
if (!strncasecmp(fax_document, "http://", 7) || !strncasecmp(fax_document, "https://", 8)) {
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
/* need to fetch document from server... */
switch_api_execute("http_get", fax_document, session, &stream);
if (!zstr(stream.data) && !strncmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) {
fax_document = switch_core_session_strdup(session, stream.data);
} else {
switch_safe_free(stream.data);
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to fetch document");
}
switch_safe_free(stream.data);
} else if (!strncasecmp(fax_document, "file://", 7)) {
fax_document = fax_document + 7;
if (zstr(fax_document)) {
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid file:// url");
}
} else if (strncasecmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) {
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "unsupported url type");
}
/* does document exist? */
if (switch_file_exists(fax_document, pool) != SWITCH_STATUS_SUCCESS) {
return iks_new_error_detailed_printf(iq, STANZA_ERROR_BAD_REQUEST, "file not found: %s", fax_document);
}
/* get fax identity and header */
fax_identity = iks_find_attrib_soft(document, "identity");
if (!zstr(fax_identity)) {
switch_channel_set_variable(channel, "fax_ident", fax_identity);
} else {
switch_channel_set_variable(channel, "fax_ident", NULL);
}
fax_header = iks_find_attrib_soft(document, "header");
if (!zstr(fax_header)) {
switch_channel_set_variable(channel, "fax_header", fax_header);
} else {
switch_channel_set_variable(channel, "fax_header", NULL);
}
/* get pages to send */
pages = iks_find_attrib_soft(document, "pages");
if (!zstr(pages)) {
if (switch_regex_match(pages, "[1-9][0-9]*(-[1-9][0-9]*)?") == SWITCH_STATUS_FALSE) {
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value");
} else {
int start = 0;
int end = 0;
char *pages_dup = switch_core_session_strdup(session, pages);
char *sep = strchr(pages_dup, '-');
if (sep) {
*sep = '\0';
sep++;
end = atoi(sep);
}
start = atoi(pages_dup);
if (end && end < start) {
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value");
}
switch_channel_set_variable(channel, "fax_start_page", pages_dup);
switch_channel_set_variable(channel, "fax_end_page", sep);
}
} else {
switch_channel_set_variable(channel, "fax_start_page", NULL);
switch_channel_set_variable(channel, "fax_end_page", NULL);
}
/* create sendfax component */
switch_core_new_memory_pool(&pool);
sendfax_component = switch_core_alloc(pool, sizeof(*sendfax_component));
rayo_component_init((struct rayo_component *)sendfax_component, pool, RAT_CALL_COMPONENT, "sendfax", NULL, call, iks_find_attrib(iq, "from"));
/* add channel variable so that fax component can be located from fax events */
switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(sendfax_component));
/* clear fax result variables */
switch_channel_set_variable(channel, "fax_success", NULL);
switch_channel_set_variable(channel, "fax_result_code", NULL);
switch_channel_set_variable(channel, "fax_result_text", NULL);
switch_channel_set_variable(channel, "fax_document_transferred_pages", NULL);
switch_channel_set_variable(channel, "fax_document_total_pages", NULL);
switch_channel_set_variable(channel, "fax_image_resolution", NULL);
switch_channel_set_variable(channel, "fax_image_size", NULL);
switch_channel_set_variable(channel, "fax_bad_rows", NULL);
switch_channel_set_variable(channel, "fax_transfer_rate", NULL);
switch_channel_set_variable(channel, "fax_ecm_used", NULL);
switch_channel_set_variable(channel, "fax_local_station_id", NULL);
switch_channel_set_variable(channel, "fax_remote_station_id", NULL);
/* clear fax interrupt variable */
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
/* execute txfax APP */
if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "txfax");
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", fax_document);
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
}
if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to txfax (queue event failed)");
if (execute_event) {
switch_event_destroy(&execute_event);
}
RAYO_UNLOCK(sendfax_component);
} else {
/* component starting... */
rayo_component_send_start(RAYO_COMPONENT(sendfax_component), iq);
}
} else {
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create txfax event");
RAYO_UNLOCK(sendfax_component);
}
return response;
}
/**
* Start execution of call receivefax component
* @param call the call to receive fax from
* @param msg the original request
* @param session_data the call's session
*/
static iks *start_receivefax_component(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
{
iks *iq = msg->payload;
switch_core_session_t *session = (switch_core_session_t *)session_data;
struct receivefax_component *receivefax_component = NULL;
iks *receivefax = iks_find(iq, "receivefax");
iks *response = NULL;
switch_event_t *execute_event = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_memory_pool_t *pool;
int file_no;
/* validate attributes */
if (!VALIDATE_RAYO_RECEIVEFAX(receivefax)) {
return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
}
/* fax is only allowed if the call is not currently joined */
if (rayo_call_is_joined(RAYO_CALL(call))) {
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "can't receive fax on a joined call");
}
if (!rayo_call_set_faxing(RAYO_CALL(call), 1)) {
return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "fax already in progress");
}
/* create receivefax component */
switch_core_new_memory_pool(&pool);
receivefax_component = switch_core_alloc(pool, sizeof(*receivefax_component));
rayo_component_init((struct rayo_component *)receivefax_component, pool, RAT_CALL_COMPONENT, "receivefax", NULL, call, iks_find_attrib(iq, "from"));
file_no = rayo_actor_seq_next(call);
receivefax_component->filename = switch_core_sprintf(pool, "%s%s%s-%d",
globals.file_prefix, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(session), file_no);
if (!strncmp(receivefax_component->filename, "http://", 7) || !strncmp(receivefax_component->filename, "https://", 8)) {
/* This is an HTTP URL, need to PUT after fax is received */
receivefax_component->local_filename = switch_core_sprintf(pool, "%s%s%s-%d",
SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(session), file_no);
receivefax_component->http_put_after_receive = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s save fax to HTTP URL\n", RAYO_JID(receivefax_component));
} else {
/* assume file.. */
receivefax_component->local_filename = receivefax_component->filename;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s save fax to local file\n", RAYO_JID(receivefax_component));
}
/* add channel variable so that fax component can be located from fax events */
switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(receivefax_component));
/* clear fax result variables */
switch_channel_set_variable(channel, "fax_success", NULL);
switch_channel_set_variable(channel, "fax_result_code", NULL);
switch_channel_set_variable(channel, "fax_result_text", NULL);
switch_channel_set_variable(channel, "fax_document_transferred_pages", NULL);
switch_channel_set_variable(channel, "fax_document_total_pages", NULL);
switch_channel_set_variable(channel, "fax_image_resolution", NULL);
switch_channel_set_variable(channel, "fax_image_size", NULL);
switch_channel_set_variable(channel, "fax_bad_rows", NULL);
switch_channel_set_variable(channel, "fax_transfer_rate", NULL);
switch_channel_set_variable(channel, "fax_ecm_used", NULL);
switch_channel_set_variable(channel, "fax_local_station_id", NULL);
switch_channel_set_variable(channel, "fax_remote_station_id", NULL);
/* clear fax interrupt variable */
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
/* execute rxfax APP */
if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "rxfax");
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", receivefax_component->local_filename);
switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true");
if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
}
if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to rxfax (queue event failed)");
if (execute_event) {
switch_event_destroy(&execute_event);
}
RAYO_UNLOCK(receivefax_component);
} else {
/* component starting... */
rayo_component_send_start(RAYO_COMPONENT(receivefax_component), iq);
}
} else {
response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create rxfax event");
RAYO_UNLOCK(receivefax_component);
}
return response;
}
/**
* Stop execution of fax component
*/
static iks *stop_fax_component(struct rayo_actor *component, struct rayo_message *msg, void *data)
{
iks *iq = msg->payload;
switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id);
if (session) {
/* fail on read frame until component is destroyed */
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", RAYO_JID(component));
switch_core_session_rwunlock(session);
}
FAX_COMPONENT(component)->stop = 1;
return iks_new_iq_result(iq);
}
/**
* Add fax metadata to result
* @param event source of metadata
* @param name of metadata
* @param result to add metadata to
*/
static void insert_fax_metadata(switch_event_t *event, const char *name, iks *result)
{
char actual_name[256];
const char *value;
snprintf(actual_name, sizeof(actual_name), "variable_%s", name);
actual_name[sizeof(actual_name) - 1] = '\0';
value = switch_event_get_header(event, actual_name);
if (!zstr(value)) {
iks *metadata = iks_insert(result, "metadata");
iks_insert_attrib(metadata, "xmlns", RAYO_FAX_COMPLETE_NS);
iks_insert_attrib(metadata, "name", name);
iks_insert_attrib(metadata, "value", value);
}
}
/**
* Handle fax completion event from FreeSWITCH core
* @param event received from FreeSWITCH core. It will be destroyed by the core after this function returns.
*/
static void on_execute_complete_event(switch_event_t *event)
{
const char *application = switch_event_get_header(event, "Application");
if (!zstr(application) && (!strcmp(application, "rxfax") || !strcmp(application, "txfax"))) {
int is_rxfax = !strcmp(application, "rxfax");
const char *uuid = switch_event_get_header(event, "Unique-ID");
const char *fax_jid = switch_event_get_header(event, "variable_rayo_fax_jid");
struct rayo_actor *component;
if (!zstr(fax_jid) && (component = RAYO_LOCATE(fax_jid))) {
iks *result;
iks *complete;
iks *fax;
int have_fax_document = 1;
switch_core_session_t *session;
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Got result for %s\n", fax_jid);
/* clean up channel */
session = switch_core_session_locate(uuid);
if (session) {
switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
switch_core_session_rwunlock(session);
}
/* RX only: transfer HTTP document and delete local copy */
if (is_rxfax && RECEIVEFAX_COMPONENT(component)->http_put_after_receive && switch_file_exists(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component)) == SWITCH_STATUS_SUCCESS) {
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename);
switch_api_execute("http_put", RECEIVEFAX_COMPONENT(component)->filename, NULL, &stream);
/* check if successful */
if (!zstr(stream.data) && strncmp(stream.data, "+OK", 3)) {
/* PUT failed */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s failed: %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename, (char *)stream.data);
have_fax_document = 0;
}
switch_safe_free(stream.data)
switch_file_remove(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component));
}
/* successful fax? */
if (have_fax_document && switch_true(switch_event_get_header(event, "variable_fax_success"))) {
result = rayo_component_create_complete_event(RAYO_COMPONENT(component), FAX_FINISH);
} else if (have_fax_document && FAX_COMPONENT(component)->stop) {
result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
} else {
result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
}
complete = iks_find(result, "complete");
/* RX only: add fax document information */
if (is_rxfax && have_fax_document) {
const char *pages = switch_event_get_header(event, "variable_fax_document_transferred_pages");
if (!zstr(pages) && switch_is_number(pages) && atoi(pages) > 0) {
const char *resolution = switch_event_get_header(event, "variable_fax_file_image_resolution");
const char *size = switch_event_get_header(event, "variable_fax_image_size");
fax = iks_insert(complete, "fax");
iks_insert_attrib(fax, "xmlns", RAYO_FAX_COMPLETE_NS);
if (RECEIVEFAX_COMPONENT(component)->http_put_after_receive) {
iks_insert_attrib(fax, "url", RECEIVEFAX_COMPONENT(component)->filename);
} else {
/* convert absolute path to file:// URI */
iks_insert_attrib_printf(fax, "url", "file://%s", RECEIVEFAX_COMPONENT(component)->filename);
}
if (!zstr(resolution)) {
iks_insert_attrib(fax, "resolution", resolution);
}
if (!zstr(size)) {
iks_insert_attrib(fax, "size", size);
}
iks_insert_attrib(fax, "pages", pages);
}
}
/* add metadata from event */
insert_fax_metadata(event, "fax_success", complete);
insert_fax_metadata(event, "fax_result_code", complete);
insert_fax_metadata(event, "fax_result_text", complete);
insert_fax_metadata(event, "fax_document_transferred_pages", complete);
insert_fax_metadata(event, "fax_document_total_pages", complete);
insert_fax_metadata(event, "fax_image_resolution", complete);
insert_fax_metadata(event, "fax_image_size", complete);
insert_fax_metadata(event, "fax_bad_rows", complete);
insert_fax_metadata(event, "fax_transfer_rate", complete);
insert_fax_metadata(event, "fax_ecm_used", complete);
insert_fax_metadata(event, "fax_local_station_id", complete);
insert_fax_metadata(event, "fax_remote_station_id", complete);
/* flag faxing as done */
rayo_call_set_faxing(RAYO_CALL(RAYO_COMPONENT(component)->parent), 0);
rayo_component_send_complete_event(RAYO_COMPONENT(component), result);
RAYO_UNLOCK(component);
}
}
}
/**
* Process module XML configuration
* @param pool memory pool to allocate from
* @param config_file to use
* @return SWITCH_STATUS_SUCCESS on successful configuration
*/
static switch_status_t do_config(switch_memory_pool_t *pool, const char *config_file)
{
switch_xml_t cfg, xml;
/* set defaults */
globals.file_prefix = switch_core_sprintf(pool, "%s%s", SWITCH_GLOBAL_dirs.recordings_dir, SWITCH_PATH_SEPARATOR);
if (!(xml = switch_xml_open_cfg(config_file, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", config_file);
return SWITCH_STATUS_TERM;
}
/* get params */
{
switch_xml_t settings = switch_xml_child(cfg, "fax");
if (settings) {
switch_xml_t param;
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
const char *var = switch_xml_attr_soft(param, "name");
const char *val = switch_xml_attr_soft(param, "value");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "param: %s = %s\n", var, val);
if (!strcasecmp(var, "receivefax-file-prefix")) {
if (!zstr(val)) {
globals.file_prefix = switch_core_strdup(pool, val);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unsupported param: %s\n", var);
}
}
}
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "receivefax-file-prefix = %s\n", globals.file_prefix);
switch_xml_free(xml);
return SWITCH_STATUS_SUCCESS;
}
/**
* Initialize fax components
* @param module_interface
* @param pool memory pool to allocate from
* @param config_file to use
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_fax_components_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool, const char *config_file)
{
if (do_config(pool, config_file) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_TERM;
}
switch_event_bind("rayo_fax_components", SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE, NULL, on_execute_complete_event, NULL);
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_FAX_NS":receivefax", start_receivefax_component);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "receivefax", "set:"RAYO_EXT_NS":stop", stop_fax_component);
rayo_actor_command_handler_add(RAT_CALL, "", "set:"RAYO_FAX_NS":sendfax", start_sendfax_component);
rayo_actor_command_handler_add(RAT_CALL_COMPONENT, "sendfax", "set:"RAYO_EXT_NS":stop", stop_fax_component);
return SWITCH_STATUS_SUCCESS;
}
/**
* Shutdown fax components
* @return SWITCH_STATUS_SUCCESS if successful
*/
switch_status_t rayo_fax_components_shutdown(void)
{
switch_event_unbind_callback(on_execute_complete_event);
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 noet
*/

View File

@ -311,16 +311,17 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) {
used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2);
if (source->total) {
uint32_t bused = 0;
switch_mutex_lock(source->mutex);
for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
continue;
}
switch_mutex_lock(cp->audio_mutex);
if (switch_buffer_inuse(cp->audio_buffer) > source->samples * 768) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d]\n", cp->func, cp->file,
cp->line);
bused = switch_buffer_inuse(cp->audio_buffer);
if (bused > source->samples * 768) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n",
cp->func, cp->file, cp->line, bused, (long)source->samples);
switch_buffer_zero(cp->audio_buffer);
} else {
switch_buffer_write(cp->audio_buffer, dist_buf, used);

View File

@ -45,7 +45,6 @@ SWITCH_MODULE_DEFINITION_EX(mod_lua, mod_lua_load, mod_lua_shutdown, NULL, SMODF
static struct {
switch_memory_pool_t *pool;
char *xml_handler;
switch_event_node_t *node;
} globals;
int luaopen_freeswitch(lua_State * L);
@ -339,18 +338,22 @@ static switch_status_t do_config(void)
char *script = (char *) switch_xml_attr_soft(hook, "script");
switch_event_types_t evtype;
if (!zstr(script)) {
script = switch_core_strdup(globals.pool, script);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "hook params: '%s' | '%s' | '%s'\n", event, subclass, script);
if (switch_name_event(event,&evtype) == SWITCH_STATUS_SUCCESS) {
if (!zstr(script)) {
if (switch_event_bind_removable(modname, evtype, !zstr(subclass) ? subclass : SWITCH_EVENT_SUBCLASS_ANY,
lua_event_handler, script, &globals.node) == SWITCH_STATUS_SUCCESS) {
if (switch_event_bind(modname, evtype, !zstr(subclass) ? subclass : SWITCH_EVENT_SUBCLASS_ANY,
lua_event_handler, script) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "event handler for '%s' set to '%s'\n", switch_event_name(evtype), script);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: unsuccessful bind\n");
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: no script name\n", event);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: no script name for event type '%s'\n", event);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot set event handler: unknown event type '%s'\n", event);
@ -691,7 +694,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_lua_load)
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_lua_shutdown)
{
switch_event_unbind(&globals.node);
switch_event_unbind_callback(lua_event_handler);
return SWITCH_STATUS_SUCCESS;
}

View File

@ -139,6 +139,7 @@ typedef enum {
struct switch_channel {
char *name;
switch_call_direction_t direction;
switch_call_direction_t logical_direction;
switch_queue_t *dtmf_queue;
switch_queue_t *dtmf_log_queue;
switch_mutex_t*dtmf_mutex;
@ -240,6 +241,7 @@ static struct switch_callstate_table CALLSTATE_CHART[] = {
{"EARLY", CCS_EARLY},
{"ACTIVE", CCS_ACTIVE},
{"HELD", CCS_HELD},
{"RING_WAIT", CCS_RING_WAIT},
{"HANGUP", CCS_HANGUP},
{"UNHOLD", CCS_UNHOLD},
{NULL, 0}
@ -389,11 +391,23 @@ SWITCH_DECLARE(switch_channel_timetable_t *) switch_channel_get_timetable(switch
return times;
}
SWITCH_DECLARE(void) switch_channel_set_direction(switch_channel_t *channel, switch_call_direction_t direction)
{
if (!switch_core_session_in_thread(channel->session)) {
channel->direction = channel->logical_direction = direction;
}
}
SWITCH_DECLARE(switch_call_direction_t) switch_channel_direction(switch_channel_t *channel)
{
return channel->direction;
}
SWITCH_DECLARE(switch_call_direction_t) switch_channel_logical_direction(switch_channel_t *channel)
{
return channel->logical_direction;
}
SWITCH_DECLARE(switch_status_t) switch_channel_alloc(switch_channel_t **channel, switch_call_direction_t direction, switch_memory_pool_t *pool)
{
switch_assert(pool != NULL);
@ -415,7 +429,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_alloc(switch_channel_t **channel,
switch_mutex_init(&(*channel)->profile_mutex, SWITCH_MUTEX_NESTED, pool);
(*channel)->hangup_cause = SWITCH_CAUSE_NONE;
(*channel)->name = "";
(*channel)->direction = direction;
(*channel)->direction = (*channel)->logical_direction = direction;
switch_channel_set_variable(*channel, "direction", switch_channel_direction(*channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound");
return SWITCH_STATUS_SUCCESS;
@ -1747,6 +1761,24 @@ SWITCH_DECLARE(void) switch_channel_set_flag_value(switch_channel_t *channel, sw
channel->flags[flag] = value;
switch_mutex_unlock(channel->flag_mutex);
if (flag == CF_ORIGINATOR && switch_channel_test_flag(channel, CF_ANSWERED) && switch_channel_up_nosig(channel)) {
switch_channel_set_callstate(channel, CCS_RING_WAIT);
}
if (flag == CF_DIALPLAN) {
if (channel->direction == SWITCH_CALL_DIRECTION_INBOUND) {
channel->logical_direction = SWITCH_CALL_DIRECTION_OUTBOUND;
if (channel->device_node) {
channel->device_node->direction = SWITCH_CALL_DIRECTION_INBOUND;
}
} else {
channel->logical_direction = SWITCH_CALL_DIRECTION_INBOUND;
if (channel->device_node) {
channel->device_node->direction = SWITCH_CALL_DIRECTION_OUTBOUND;
}
}
}
if (HELD) {
switch_hold_record_t *hr;
const char *brto = switch_channel_get_partner_uuid(channel);
@ -1909,6 +1941,15 @@ SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch
channel->flags[flag] = 0;
switch_mutex_unlock(channel->flag_mutex);
if (flag == CF_DIALPLAN) {
if (channel->direction == SWITCH_CALL_DIRECTION_OUTBOUND) {
channel->logical_direction = SWITCH_CALL_DIRECTION_OUTBOUND;
if (channel->device_node) {
channel->device_node->direction = SWITCH_CALL_DIRECTION_INBOUND;
}
}
}
if (ACTIVE) {
switch_channel_set_callstate(channel, CCS_UNHOLD);
switch_mutex_lock(channel->profile_mutex);
@ -1923,6 +1964,10 @@ SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch
switch_mutex_unlock(channel->profile_mutex);
}
if (flag == CF_ORIGINATOR && switch_channel_test_flag(channel, CF_ANSWERED) && switch_channel_up_nosig(channel)) {
switch_channel_set_callstate(channel, CCS_ACTIVE);
}
if (flag == CF_OUTBOUND) {
switch_channel_set_variable(channel, "is_outbound", NULL);
}
@ -2585,6 +2630,7 @@ SWITCH_DECLARE(void) switch_channel_set_caller_profile(switch_channel_t *channel
switch_assert(caller_profile != NULL);
caller_profile->direction = channel->direction;
caller_profile->logical_direction = channel->logical_direction;
uuid = switch_core_session_get_uuid(channel->session);
if (!caller_profile->uuid || strcasecmp(caller_profile->uuid, uuid)) {
@ -2667,6 +2713,7 @@ SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *ch
channel->caller_profile->hunt_caller_profile = NULL;
if (channel->caller_profile && caller_profile) {
caller_profile->direction = channel->direction;
caller_profile->logical_direction = channel->logical_direction;
channel->caller_profile->hunt_caller_profile = caller_profile;
}
switch_mutex_unlock(channel->profile_mutex);
@ -4658,6 +4705,8 @@ static void fetch_device_stats(switch_device_record_t *drec)
} else {
drec->stats.ringing_out++;
}
} else if (np->callstate == CCS_RING_WAIT) {
drec->stats.ring_wait++;
} else if (np->callstate == CCS_HANGUP) {
drec->stats.hup++;
if (np->direction == SWITCH_CALL_DIRECTION_INBOUND) {
@ -4821,7 +4870,7 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_
drec->state = SDS_HANGUP;
} else {
if (drec->stats.active == 0) {
if ((drec->stats.ringing_out + drec->stats.early_out) > 0) {
if ((drec->stats.ringing_out + drec->stats.early_out) > 0 || drec->stats.ring_wait > 0) {
drec->state = SDS_RINGING;
} else {
if (drec->stats.held > 0) {
@ -4849,25 +4898,30 @@ static void switch_channel_check_device_state(switch_channel_t *channel, switch_
switch(drec->state) {
case SDS_RINGING:
drec->ring_start = switch_micro_time_now();
drec->ring_stop = 0;
if (!drec->ring_start) {
drec->ring_start = switch_micro_time_now();
drec->ring_stop = 0;
}
break;
case SDS_ACTIVE:
case SDS_ACTIVE_MULTI:
if (drec->active_start && drec->last_state != SDS_HELD) {
drec->active_stop = switch_micro_time_now();
} else if (!drec->active_start) {
if (!drec->active_start) {
drec->active_start = switch_micro_time_now();
drec->active_stop = 0;
}
break;
case SDS_HELD:
drec->hold_start = switch_micro_time_now();
drec->hold_stop = 0;
default:
if (drec->active_start && drec->last_state != SDS_HELD) {
drec->active_stop = switch_micro_time_now();
if (!drec->hold_start) {
drec->hold_start = switch_micro_time_now();
drec->hold_stop = 0;
}
break;
default:
break;
}
if (drec->active_start && drec->state != SDS_ACTIVE && drec->state != SDS_ACTIVE_MULTI) {
drec->active_stop = switch_micro_time_now();
}
if (drec->ring_start && !drec->ring_stop && drec->state != SDS_RINGING) {
@ -4972,7 +5026,7 @@ static void add_uuid(switch_device_record_t *drec, switch_channel_t *channel)
node->uuid = switch_core_strdup(drec->pool, switch_core_session_get_uuid(channel->session));
node->parent = drec;
node->callstate = channel->callstate;
node->direction = channel->direction == SWITCH_CALL_DIRECTION_INBOUND ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND;
node->direction = channel->logical_direction == SWITCH_CALL_DIRECTION_INBOUND ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND;
channel->device_node = node;

View File

@ -283,6 +283,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
ok = SWITCH_TRUE;
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
@ -345,6 +347,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
if (session->bugs && switch_test_flag((*frame), SFF_CNG)) {
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
ok = SWITCH_TRUE;
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
@ -639,6 +643,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
ok = SWITCH_TRUE;
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
@ -688,6 +694,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
ok = SWITCH_TRUE;
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
@ -854,6 +862,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
int prune = 0;
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
ok = SWITCH_TRUE;
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
@ -924,6 +934,8 @@ static switch_status_t perform_write(switch_core_session_t *session, switch_fram
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
ok = SWITCH_TRUE;
if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) {
continue;
}
@ -1225,6 +1237,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
switch_thread_rwlock_rdlock(session->bug_rwlock);
for (bp = session->bugs; bp; bp = bp->next) {
switch_bool_t ok = SWITCH_TRUE;
if (!bp->ready) {
continue;
}

View File

@ -1681,6 +1681,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu
}
}
if (switch_channel_direction(originatee_channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(originatee_channel, CF_DIALPLAN)) {
switch_channel_clear_flag(originatee_channel, CF_DIALPLAN);
}
cleanup_proxy_mode_a(originator_session);
cleanup_proxy_mode_a(originatee_session);