mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-05-30 02:20:11 +00:00
Merge branch 'v1.2.stable' into v1.2.stable-em_management
Conflicts: libs/freetdm/mod_freetdm/mod_freetdm.c
This commit is contained in:
commit
2f6ccf659c
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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"])
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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))) {
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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 \
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
561
src/mod/event_handlers/mod_rayo/rayo_fax_components.c
Normal file
561
src/mod/event_handlers/mod_rayo/rayo_fax_components.c
Normal 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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user