diff --git a/conf/rayo/autoload_configs/rayo.conf.xml b/conf/rayo/autoload_configs/rayo.conf.xml index 35419319bc..c8171569af 100644 --- a/conf/rayo/autoload_configs/rayo.conf.xml +++ b/conf/rayo/autoload_configs/rayo.conf.xml @@ -16,6 +16,12 @@ + + + + + + @@ -65,6 +71,7 @@ ]]> ]]> ]]> + ]]> ]]> ]]> ]]> diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 59370e742a..05eb175f22 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -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; } diff --git a/src/include/switch_caller.h b/src/include/switch_caller.h index f0dc1c76fe..1fd5ecbd29 100644 --- a/src/include/switch_caller.h +++ b/src/include/switch_caller.h @@ -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; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 2e53ef6107..dd3870f8ae 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -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); diff --git a/src/include/switch_core.h b/src/include/switch_core.h index db3e67c5a8..8e41a882a6 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -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; diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 758fe54c5b..e43db7be08 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -27,6 +27,7 @@ * Bret McDanel * Joseph Sullivan * Raymond Chandler + * Emmanuel Schmidbauer * * 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; diff --git a/src/include/switch_version.h.template b/src/include/switch_version.h.template index 2e253dc69f..06169d603f 100644 --- a/src/include/switch_version.h.template +++ b/src/include/switch_version.h.template @@ -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 diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 265effdb2e..bc04e21d65 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -32,6 +32,8 @@ * David Weekly * Joao Mesquita * Raymond Chandler + * Seven Du + * Emmanuel Schmidbauer * * 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); diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 8d7b5c6f37..b5b7718231 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -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); diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index d3c7a87aa7..9f99b2df7b 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -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)); diff --git a/src/mod/applications/mod_mongo/Makefile b/src/mod/applications/mod_mongo/Makefile index 9ce16b1171..7a6e1058ab 100644 --- a/src/mod/applications/mod_mongo/Makefile +++ b/src/mod/applications/mod_mongo/Makefile @@ -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) diff --git a/src/mod/applications/mod_mongo/fpic_hack.diff b/src/mod/applications/mod_mongo/fpic_hack.diff index 882f3c899a..1f85f85c97 100644 --- a/src/mod/applications/mod_mongo/fpic_hack.diff +++ b/src/mod/applications/mod_mongo/fpic_hack.diff @@ -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"]) + diff --git a/src/mod/applications/mod_mongo/mod_mongo.cpp b/src/mod/applications/mod_mongo/mod_mongo.cpp index 83b31c7546..8c3536def2 100644 --- a/src/mod/applications/mod_mongo/mod_mongo.cpp +++ b/src/mod/applications/mod_mongo/mod_mongo.cpp @@ -1,6 +1,6 @@ -/* +/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2005-2012, Anthony Minessale II + * Copyright (C) 2005-2013, Anthony Minessale II * * Version: MPL 1.1 * @@ -22,7 +22,7 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * + * * Tamas Cseke * * 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) diff --git a/src/mod/applications/mod_mongo/mod_mongo.h b/src/mod/applications/mod_mongo/mod_mongo.h index 00e927f3a1..822dacaf63 100644 --- a/src/mod/applications/mod_mongo/mod_mongo.h +++ b/src/mod/applications/mod_mongo/mod_mongo.h @@ -1,6 +1,6 @@ -/* +/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2005-2012, Anthony Minessale II + * Copyright (C) 2005-2013, Anthony Minessale II * * Version: MPL 1.1 * @@ -32,22 +32,19 @@ #ifndef MOD_MONGO_H #define MOD_MONGO_H -#include -#include -#include -#include +#include 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); diff --git a/src/mod/applications/mod_mongo/mongo_conn.cpp b/src/mod/applications/mod_mongo/mongo_conn.cpp index 8c7687b860..fd095fe54a 100644 --- a/src/mod/applications/mod_mongo/mongo_conn.cpp +++ b/src/mod/applications/mod_mongo/mongo_conn.cpp @@ -1,6 +1,6 @@ /* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * Copyright (C) 2005-2012, Anthony Minessale II + * Copyright (C) 2005-2013, Anthony Minessale II * * 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: diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index b283cb2c01..f3d5585fdf 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -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; } diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c index f943933248..cb34325f07 100644 --- a/src/mod/endpoints/mod_sofia/rtp.c +++ b/src/mod/endpoints/mod_sofia/rtp.c @@ -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))) { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 9230944a43..ee03d68876 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -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"); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 9839688ca0..92e018acce 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -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, diff --git a/src/mod/event_handlers/mod_rayo/Makefile b/src/mod/event_handlers/mod_rayo/Makefile index 6fccfdf318..a3bfc45d47 100644 --- a/src/mod/event_handlers/mod_rayo/Makefile +++ b/src/mod/event_handlers/mod_rayo/Makefile @@ -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 \ diff --git a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml index 35419319bc..3fdc772daf 100644 --- a/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml +++ b/src/mod/event_handlers/mod_rayo/conf/autoload_configs/rayo.conf.xml @@ -16,6 +16,12 @@ + + + + + + @@ -65,6 +71,7 @@ ]]> ]]> ]]> + ]]> ]]> ]]> ]]> diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 6dd58d29c6..f852d2c5f8 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -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; } diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.h b/src/mod/event_handlers/mod_rayo/mod_rayo.h index dd0adb3192..c65236b64a 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.h +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.h @@ -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) diff --git a/src/mod/event_handlers/mod_rayo/rayo_components.c b/src/mod/event_handlers/mod_rayo/rayo_components.c index b5137d9459..7ad96d2a7d 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_components.c +++ b/src/mod/event_handlers/mod_rayo/rayo_components.c @@ -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; } diff --git a/src/mod/event_handlers/mod_rayo/rayo_components.h b/src/mod/event_handlers/mod_rayo/rayo_components.h index 6e93dfbc43..5d1367d645 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_components.h +++ b/src/mod/event_handlers/mod_rayo/rayo_components.h @@ -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); diff --git a/src/mod/event_handlers/mod_rayo/rayo_elements.c b/src/mod/event_handlers/mod_rayo/rayo_elements.c index 34577a9492..78209c3bd6 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_elements.c +++ b/src/mod/event_handlers/mod_rayo/rayo_elements.c @@ -32,6 +32,7 @@ * 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 +/** + * 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 + /** * 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 * 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 * component validation */ ELEMENT(RAYO_PROMPT) + ATTRIB(xmlns,, any) ATTRIB(barge-in, true, bool) ELEMENT_END +/** + * command validation + */ +ELEMENT(RAYO_RECEIVEFAX) + ATTRIB(xmlns,, any) +ELEMENT_END + /** * 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 /** - * command validation + * 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 diff --git a/src/mod/event_handlers/mod_rayo/rayo_elements.h b/src/mod/event_handlers/mod_rayo/rayo_elements.h index c780f160cf..e76809cc9e 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_elements.h +++ b/src/mod/event_handlers/mod_rayo/rayo_elements.h @@ -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 diff --git a/src/mod/event_handlers/mod_rayo/rayo_fax_components.c b/src/mod/event_handlers/mod_rayo/rayo_fax_components.c new file mode 100644 index 0000000000..420853104a --- /dev/null +++ b/src/mod/event_handlers/mod_rayo/rayo_fax_components.c @@ -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 + * + * 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 + */ + diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index 6d91f9b653..c94958ea87 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -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); diff --git a/src/mod/languages/mod_lua/mod_lua.cpp b/src/mod/languages/mod_lua/mod_lua.cpp index 3d79dd8d0e..9715f0dc74 100644 --- a/src/mod/languages/mod_lua/mod_lua.cpp +++ b/src/mod/languages/mod_lua/mod_lua.cpp @@ -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; } diff --git a/src/switch_channel.c b/src/switch_channel.c index 5f53b22a7a..69442f3f60 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -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; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index aa3e78c911..4b7a0a885e 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -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; } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index ef7067cec7..958b16fd67 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -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);