From a511ff3026b8efdfc185723bf9d0728e0f8a86ca Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 7 May 2012 13:44:10 -0500 Subject: [PATCH] re-implement sla barge using eavesdrop backend --- src/include/private/switch_core_pvt.h | 3 + src/include/switch_core.h | 12 +- src/include/switch_ivr.h | 5 + src/include/switch_resample.h | 2 +- src/include/switch_types.h | 8 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 34 +++++ src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 98 ++++++-------- src/mod/endpoints/mod_sofia/sofia_presence.c | 1 + src/switch_core_io.c | 60 +++++++-- src/switch_core_media_bug.c | 83 +++++++++++- src/switch_ivr_async.c | 132 ++++++++++++++++++- src/switch_resample.c | 19 +++ 13 files changed, 378 insertions(+), 80 deletions(-) diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 781f0e4d06..95e66f2f6d 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -171,6 +171,8 @@ struct switch_core_session { uint32_t soft_lock; switch_ivr_dmachine_t *dmachine[2]; plc_state_t *plc; + uint8_t recur_buffer[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_size_t recur_buffer_len; }; struct switch_media_bug { @@ -199,6 +201,7 @@ struct switch_media_bug { uint32_t record_pre_buffer_count; uint32_t record_pre_buffer_max; switch_frame_t *ping_frame; + switch_frame_t *read_demux_frame; struct switch_media_bug *next; }; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 0011652475..91cff21d67 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -137,6 +137,11 @@ SWITCH_DECLARE(void) switch_core_session_disable_heartbeat(switch_core_session_t #define switch_core_session_get_name(_s) switch_channel_get_name(switch_core_session_get_channel(_s)) +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_pop(switch_core_session_t *orig_session, const char *function, switch_media_bug_t **pop); + +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_exec_all(switch_core_session_t *orig_session, + const char *function, switch_media_bug_exec_cb_t cb, void *user_data); + /*! \brief Add a media bug to the session \param session the session to add the bug to @@ -193,7 +198,7 @@ SWITCH_DECLARE(void) switch_core_media_bug_set_write_replace_frame(_In_ switch_m \param bug the bug to get the data from */ SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_read_replace_frame(_In_ switch_media_bug_t *bug); - +SWITCH_DECLARE(void) switch_core_media_bug_set_read_demux_frame(_In_ switch_media_bug_t *bug, _In_ switch_frame_t *frame); /*! \brief Obtain the session from a media bug \param bug the bug to get the data from @@ -225,6 +230,7 @@ SWITCH_DECLARE(uint32_t) switch_core_cpu_count(void); \param bug bug to remove \return SWITCH_STATUS_SUCCESS if the operation was a success */ + SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(_In_ switch_core_session_t *session, _Inout_ switch_media_bug_t **bug); SWITCH_DECLARE(uint32_t) switch_core_media_bug_prune(switch_core_session_t *session); @@ -247,7 +253,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(_Inout_ switch_media \param session the session to remove the bugs from \return SWITCH_STATUS_SUCCESS if the operation was a success */ -SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(_In_ switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all_function(_In_ switch_core_session_t *session, const char *function); + +#define switch_core_media_bug_remove_all(_s) switch_core_media_bug_remove_all_function(_s, NULL) SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream); SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session); diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 8f553b957e..ef5155512c 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -269,6 +269,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_start_input_timers(swit */ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, char *file, uint32_t limit, switch_file_handle_t *fh); + +SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_pop_eavesdropper(switch_core_session_t *session, switch_core_session_t **sessionp); +SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_exec_all(switch_core_session_t *session, const char *app, const char *arg); +SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_update_display(switch_core_session_t *session, const char *name, const char *number); + /*! \brief Eavesdrop on a another session \param session our session diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h index 7ae37669c7..f85a61f065 100644 --- a/src/include/switch_resample.h +++ b/src/include/switch_resample.h @@ -170,7 +170,7 @@ SWITCH_DECLARE(void) switch_change_sln_volume_granular(int16_t *data, uint32_t s ///\} SWITCH_DECLARE(uint32_t) switch_merge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples); - +SWITCH_DECLARE(uint32_t) switch_unmerge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples); SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t channels); SWITCH_END_EXTERN_C diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 93a2e48ced..5fda9c369e 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -288,7 +288,8 @@ typedef enum { ED_NONE = 0, ED_MUX_READ = (1 << 0), ED_MUX_WRITE = (1 << 1), - ED_DTMF = (1 << 2) + ED_DTMF = (1 << 2), + ED_COPY_DISPLAY = (1 << 3) } switch_eavesdrop_flag_enum_t; typedef uint32_t switch_eavesdrop_flag_t; @@ -1434,7 +1435,8 @@ typedef enum { SMBF_THREAD_LOCK = (1 << 7), SMBF_PRUNE = (1 << 8), SMBF_NO_PAUSE = (1 << 9), - SMBF_STEREO_SWAP = (1 << 10) + SMBF_STEREO_SWAP = (1 << 10), + SMBF_LOCK = (1 << 11) } switch_media_bug_flag_enum_t; typedef uint32_t switch_media_bug_flag_t; @@ -1821,6 +1823,8 @@ struct switch_console_callback_match { }; typedef struct switch_console_callback_match switch_console_callback_match_t; +typedef void (*switch_media_bug_exec_cb_t)(switch_media_bug_t *bug, void *user_data); + typedef void (*switch_cap_callback_t) (const char *var, const char *val, void *user_data); typedef switch_status_t (*switch_console_complete_callback_t) (const char *, const char *, switch_console_callback_match_t **matches); typedef switch_bool_t (*switch_media_bug_callback_t) (switch_media_bug_t *, void *, switch_abc_type_t); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index ea2ba7ce4d..a71dc4c714 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -2100,6 +2100,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi number = tech_pvt->caller_profile->destination_number; } + switch_ivr_eavesdrop_update_display(session, name, number); + if (!sofia_test_flag(tech_pvt, TFLAG_UPDATING_DISPLAY) && switch_channel_test_flag(channel, CF_ANSWERED)) { if (zstr(tech_pvt->last_sent_callee_id_name) || strcmp(tech_pvt->last_sent_callee_id_name, name) || zstr(tech_pvt->last_sent_callee_id_number) || strcmp(tech_pvt->last_sent_callee_id_number, number)) { @@ -5342,11 +5344,40 @@ static switch_status_t list_profile_gateway(const char *line, const char *cursor } +SWITCH_STANDARD_APP(sofia_sla_function) +{ + private_object_t *tech_pvt; + switch_core_session_t *bargee_session; + + if (zstr(data)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Usage: \n"); + return; + } + + if ((bargee_session = switch_core_session_locate((char *)data))) { + if (bargee_session == session) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BARGE: %s (cannot barge on myself)\n", (char *) data); + } else { + if (switch_core_session_check_interface(bargee_session, sofia_endpoint_interface)) { + tech_pvt = switch_core_session_get_private(bargee_session); + sofia_set_flag(tech_pvt, TFLAG_SLA_BARGE); + switch_ivr_transfer_variable(bargee_session, session, SWITCH_SIGNAL_BOND_VARIABLE); + } + } + + switch_core_session_rwunlock(bargee_session); + } + + switch_ivr_eavesdrop_session(session, data, NULL, ED_MUX_READ | ED_MUX_WRITE | ED_COPY_DISPLAY); +} + + SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) { switch_chat_interface_t *chat_interface; switch_api_interface_t *api_interface; switch_management_interface_t *management_interface; + switch_application_interface_t *app_interface; struct in_addr in; memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals)); @@ -5468,6 +5499,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) management_interface->relative_oid = "1001"; management_interface->management_function = sofia_manage; + SWITCH_ADD_APP(app_interface, "sofia_sla", "private sofia sla function", + "private sofia sla function", sofia_sla_function, "", SAF_NONE); + SWITCH_ADD_API(api_interface, "sofia", "Sofia Controls", sofia_function, " "); SWITCH_ADD_API(api_interface, "sofia_gateway_data", "Get data from a sofia gateway", sofia_gateway_data_function, " [ivar|ovar|var] "); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 5a51f68a2d..b66b29fb44 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -332,6 +332,7 @@ typedef enum { TFLAG_GOT_ACK, TFLAG_CAPTURE, TFLAG_REINVITED, + TFLAG_SLA_BARGE, /* No new flags below this line */ TFLAG_MAX } TFLAGS; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 7ae868ef62..26815b6f5e 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -599,6 +599,43 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, status = 200; phrase = "OK"; + if (sofia_test_flag(tech_pvt, TFLAG_SLA_BARGE)) { + switch_core_session_t *new_session, *other_session; + const char *other_uuid = switch_channel_get_variable(tech_pvt->channel, SWITCH_SIGNAL_BOND_VARIABLE); + char *cmd = NULL; + + if (!zstr(other_uuid) && (other_session = switch_core_session_locate(other_uuid))) { + switch_channel_t *other_channel = switch_core_session_get_channel(other_session); + + switch_mutex_lock(profile->ireg_mutex); + if (switch_ivr_eavesdrop_pop_eavesdropper(session, &new_session) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *new_channel = switch_core_session_get_channel(new_session); + const char *new_uuid = switch_core_session_get_uuid(new_session); + + + switch_channel_set_variable(new_channel, SWITCH_SIGNAL_BOND_VARIABLE, NULL); + + switch_channel_set_flag(other_channel, CF_REDIRECT); + + switch_channel_set_state(new_channel, CS_RESET); + + switch_ivr_uuid_bridge(new_uuid, other_uuid); + cmd = switch_core_session_sprintf(session, "sleep:500,sofia_sla:%s inline", new_uuid); + + switch_channel_clear_flag(other_channel, CF_REDIRECT); + + switch_core_session_rwunlock(new_session); + } + switch_mutex_unlock(profile->ireg_mutex); + + switch_core_session_rwunlock(other_session); + } + + if (!zstr(cmd)) { + switch_ivr_eavesdrop_exec_all(session, "transfer", cmd); + } + } + sofia_set_flag_locked(tech_pvt, TFLAG_BYE); call_info = switch_channel_get_variable(channel, "presence_call_info_full"); @@ -8354,8 +8391,6 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if ((b_session = switch_core_session_locate(b_private->uuid))) { switch_channel_t *b_channel = switch_core_session_get_channel(b_session); const char *uuid; - int one_leg = 1; - private_object_t *b_tech_pvt = NULL; const char *app = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_VARIABLE); const char *data = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_DATA_VARIABLE); switch_caller_profile_t *orig_cp; @@ -8387,68 +8422,15 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,conference:%s+flags{dist-dtmf}", data); tech_pvt->caller_profile->dialplan = "inline"; } else { - if (switch_core_session_check_interface(b_session, sofia_endpoint_interface)) { - b_tech_pvt = switch_core_session_get_private(b_session); - } - - if ((uuid = switch_channel_get_variable(b_channel, SWITCH_SIGNAL_BOND_VARIABLE))) { - one_leg = 0; - } else { + if (!(uuid = switch_channel_get_variable(b_channel, SWITCH_SIGNAL_BOND_VARIABLE))) { uuid = switch_core_session_get_uuid(b_session); } if (uuid) { - switch_core_session_t *c_session = NULL; - int do_conf = 0; - const char *c_app = NULL; - const char *c_data = NULL; - uuid = switch_core_session_strdup(b_session, uuid); + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, + "answer,sofia_sla:%s", b_private->uuid); - if (call_info && (c_session = switch_core_session_locate(uuid))) { - switch_channel_t *c_channel = switch_core_session_get_channel(c_session); - private_object_t *c_tech_pvt = NULL; - - c_app = switch_channel_get_variable(c_channel, SWITCH_CURRENT_APPLICATION_VARIABLE); - c_data = switch_channel_get_variable(c_channel, SWITCH_CURRENT_APPLICATION_DATA_VARIABLE); - - if (switch_core_session_check_interface(c_session, sofia_endpoint_interface)) { - c_tech_pvt = switch_core_session_get_private(c_session); - } - - - if (!one_leg && - (!b_tech_pvt || !sofia_test_flag(b_tech_pvt, TFLAG_SIP_HOLD)) && - (!c_tech_pvt || !sofia_test_flag(c_tech_pvt, TFLAG_SIP_HOLD))) { - char *ext = switch_core_session_sprintf(session, "answer,conference:%s@sla+flags{mintwo|dist-dtmf}", uuid); - - switch_channel_set_flag(c_channel, CF_REDIRECT); - switch_ivr_session_transfer(b_session, ext, "inline", NULL); - switch_ivr_session_transfer(c_session, ext, "inline", NULL); - switch_channel_clear_flag(c_channel, CF_REDIRECT); - do_conf = 1; - } - switch_core_session_rwunlock(c_session); - } - - if (do_conf) { - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, - "answer,conference:%s@sla+flags{mintwo|dist-dtmf}", uuid); - } else { - if (one_leg && c_app) { - if (c_data) { - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, - "answer,%s:%s", c_app, c_data); - } else { - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, - "answer,%s", c_app); - } - } else { - switch_channel_mark_hold(b_channel, SWITCH_FALSE); - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, - "answer,intercept:%s", uuid); - } - } tech_pvt->caller_profile->dialplan = "inline"; } diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 6befca3439..c4eb565f85 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -1167,6 +1167,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) } } #endif + if (hup && dh.hits > 0) { goto done; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 020556a490..f20fa7bff9 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -498,21 +498,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi continue; } - if (bp->ready && switch_test_flag(bp, SMBF_READ_STREAM)) { - switch_mutex_lock(bp->read_mutex); - switch_buffer_write(bp->raw_read_buffer, read_frame->data, read_frame->datalen); - - if (bp->callback) { - ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ); - } - switch_mutex_unlock(bp->read_mutex); - } - if (ok && switch_test_flag(bp, SMBF_READ_REPLACE)) { do_bugs = 0; if (bp->callback) { bp->read_replace_frame_in = read_frame; bp->read_replace_frame_out = read_frame; + bp->read_demux_frame = NULL; if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_REPLACE)) == SWITCH_TRUE) { read_frame = bp->read_replace_frame_out; } @@ -532,6 +523,55 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi } } + if (session->bugs) { + switch_media_bug_t *bp; + switch_bool_t ok = SWITCH_TRUE; + int prune = 0; + switch_thread_rwlock_rdlock(session->bug_rwlock); + + for (bp = session->bugs; bp; bp = bp->next) { + if (switch_channel_test_flag(session->channel, CF_PAUSE_BUGS) && !switch_core_media_bug_test_flag(bp, SMBF_NO_PAUSE)) { + continue; + } + + if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) { + continue; + } + if (switch_test_flag(bp, SMBF_PRUNE)) { + prune++; + continue; + } + + if (ok && bp->ready && switch_test_flag(bp, SMBF_READ_STREAM)) { + switch_mutex_lock(bp->read_mutex); + if (bp->read_demux_frame) { + uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; + int bytes = read_frame->datalen / 2; + + memcpy(data, read_frame->data, read_frame->datalen); + switch_unmerge_sln((int16_t *)data, bytes, bp->read_demux_frame->data, bytes); + switch_buffer_write(bp->raw_read_buffer, data, read_frame->datalen); + } else { + switch_buffer_write(bp->raw_read_buffer, read_frame->data, read_frame->datalen); + } + + if (bp->callback) { + ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ); + } + switch_mutex_unlock(bp->read_mutex); + } + + if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) { + switch_set_flag(bp, SMBF_PRUNE); + prune++; + } + } + switch_thread_rwlock_unlock(session->bug_rwlock); + if (prune) { + switch_core_media_bug_prune(session); + } + } + if (do_bugs) { goto done; } diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c index f5d14137b7..a320d9a345 100644 --- a/src/switch_core_media_bug.c +++ b/src/switch_core_media_bug.c @@ -72,6 +72,9 @@ SWITCH_DECLARE(uint32_t) switch_core_media_bug_test_flag(switch_media_bug_t *bug SWITCH_DECLARE(uint32_t) switch_core_media_bug_set_flag(switch_media_bug_t *bug, uint32_t flag) { + if ((flag & SMBF_PRUNE)) { + switch_clear_flag(bug, SMBF_LOCK); + } return switch_set_flag(bug, flag); } @@ -105,6 +108,11 @@ SWITCH_DECLARE(void) switch_core_media_bug_set_read_replace_frame(switch_media_b bug->read_replace_frame_out = frame; } +SWITCH_DECLARE(void) switch_core_media_bug_set_read_demux_frame(switch_media_bug_t *bug, switch_frame_t *frame) +{ + bug->read_demux_frame = frame; +} + SWITCH_DECLARE(void *) switch_core_media_bug_get_user_data(switch_media_bug_t *bug) { return bug->user_data; @@ -175,6 +183,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *b bytes = read_impl.decoded_bytes_per_packet; + if (0 && bug->session->recur_buffer_len) { + frame->datalen = bug->session->recur_buffer_len; + frame->samples = bug->session->recur_buffer_len / sizeof(int16_t); + frame->rate = read_impl.actual_samples_per_second; + frame->codec = NULL; + memcpy(frame->data, bug->session->recur_buffer, bug->session->recur_buffer_len); + return SWITCH_STATUS_SUCCESS; + } + + if (frame->buflen < bytes) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(bug)), SWITCH_LOG_ERROR, "%s frame buffer too small!\n", switch_channel_get_name(bug->session->channel)); @@ -363,6 +381,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_read(switch_media_bug_t *b return SWITCH_STATUS_BREAK; } + memcpy(bug->session->recur_buffer, frame->data, frame->datalen); + bug->session->recur_buffer_len = frame->datalen; + return SWITCH_STATUS_SUCCESS; } @@ -552,6 +573,53 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_recordings(switch return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_pop(switch_core_session_t *orig_session, const char *function, switch_media_bug_t **pop) +{ + switch_media_bug_t *bp; + + if (orig_session->bugs) { + switch_thread_rwlock_wrlock(orig_session->bug_rwlock); + for (bp = orig_session->bugs; bp; bp = bp->next) { + if (!strcmp(bp->function, function)) { + switch_set_flag(bp, SMBF_LOCK); + break; + } + } + switch_thread_rwlock_unlock(orig_session->bug_rwlock); + + if (bp) { + *pop = bp; + return SWITCH_STATUS_SUCCESS; + } else { + *pop = NULL; + } + } + + return SWITCH_STATUS_FALSE; +} + +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_exec_all(switch_core_session_t *orig_session, + const char *function, switch_media_bug_exec_cb_t cb, void *user_data) +{ + switch_media_bug_t *bp; + int x = 0; + + switch_assert(cb); + + if (orig_session->bugs) { + switch_thread_rwlock_wrlock(orig_session->bug_rwlock); + for (bp = orig_session->bugs; bp; bp = bp->next) { + if (!switch_test_flag(bp, SMBF_PRUNE) && !switch_test_flag(bp, SMBF_LOCK) && !strcmp(bp->function, function)) { + cb(bp, user_data); + x++; + } + } + switch_thread_rwlock_unlock(orig_session->bug_rwlock); + } + + return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; +} + SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_session_t *session, switch_stream_handle_t *stream) { switch_media_bug_t *bp; @@ -579,7 +647,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_enumerate(switch_core_sess return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(switch_core_session_t *session) +SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all_function(switch_core_session_t *session, const char *function) { switch_media_bug_t *bp; switch_status_t status = SWITCH_STATUS_FALSE; @@ -587,10 +655,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_all(switch_core_ses if (session->bugs) { switch_thread_rwlock_wrlock(session->bug_rwlock); for (bp = session->bugs; bp; bp = bp->next) { - if (bp->thread_id && bp->thread_id != switch_thread_self()) { + if ((bp->thread_id && bp->thread_id != switch_thread_self()) || switch_test_flag(bp, SMBF_LOCK)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "BUG is thread locked skipping.\n"); continue; } + + if (!zstr(function) && strcmp(bp->function, function)) { + continue; + } + if (bp->callback) { bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_CLOSE); @@ -614,7 +687,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_close(switch_media_bug_t * { switch_media_bug_t *bp = *bug; if (bp) { - if (bp->thread_id && bp->thread_id != switch_thread_self()) { + if ((bp->thread_id && bp->thread_id != switch_thread_self()) || switch_test_flag(bp, SMBF_LOCK)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(switch_core_media_bug_get_session(*bug)), SWITCH_LOG_DEBUG, "BUG is thread locked skipping.\n"); return SWITCH_STATUS_FALSE; } @@ -637,6 +710,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(switch_core_session { switch_media_bug_t *bp = NULL, *last = NULL; switch_status_t status = SWITCH_STATUS_FALSE; + + if (switch_core_media_bug_test_flag(*bug, SMBF_LOCK)) { + return status; + } switch_thread_rwlock_wrlock(session->bug_rwlock); if (session->bugs) { diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index ecddfdbbb6..5d6127d054 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1148,9 +1148,14 @@ struct eavesdrop_pvt { switch_mutex_t *r_mutex; switch_buffer_t *w_buffer; switch_mutex_t *w_mutex; + switch_core_session_t *eavesdropper; uint32_t flags; + switch_frame_t demux_frame; + uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; }; + + static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) user_data; @@ -1190,13 +1195,18 @@ static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data if (switch_buffer_inuse(ep->r_buffer) >= rframe->datalen) { uint32_t bytes; switch_buffer_lock(ep->r_buffer); - bytes = (uint32_t) switch_buffer_read(ep->r_buffer, data, rframe->datalen); + bytes = (uint32_t) switch_buffer_read(ep->r_buffer, ep->data, rframe->datalen); - rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) data, bytes / 2) * 2; + rframe->datalen = switch_merge_sln(rframe->data, rframe->samples, (int16_t *) ep->data, bytes / 2) * 2; rframe->samples = rframe->datalen / 2; + ep->demux_frame.data = ep->data; + ep->demux_frame.datalen = bytes; + ep->demux_frame.samples = bytes / 2; + switch_buffer_unlock(ep->r_buffer); switch_core_media_bug_set_read_replace_frame(bug, rframe); + switch_core_media_bug_set_read_demux_frame(bug, &ep->demux_frame); } } } @@ -1229,6 +1239,99 @@ static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data return SWITCH_TRUE; } +SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_pop_eavesdropper(switch_core_session_t *session, switch_core_session_t **sessionp) +{ + switch_media_bug_t *bug; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (switch_core_media_bug_pop(session, "eavesdrop", &bug) == SWITCH_STATUS_SUCCESS) { + struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) switch_core_media_bug_get_user_data(bug); + + if (ep && ep->eavesdropper && ep->eavesdropper != session) { + switch_core_session_read_lock(ep->eavesdropper); + *sessionp = ep->eavesdropper; + switch_core_media_bug_set_flag(bug, SMBF_PRUNE); + status = SWITCH_STATUS_SUCCESS; + } + } + + + return status; +} + +struct exec_cb_data { + switch_core_session_t *caller; + char *var; + char *val; +}; + +static void exec_cb(switch_media_bug_t *bug, void *user_data) +{ + struct exec_cb_data *data = (struct exec_cb_data *) user_data; + struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) switch_core_media_bug_get_user_data(bug); + + if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) { + switch_channel_t *a = switch_core_session_get_channel(ep->eavesdropper); + switch_channel_t *b = switch_core_session_get_channel(data->caller); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s telling %s to exec %s:%s\n", + switch_channel_get_name(b), switch_channel_get_name(a), data->var, data->val); + + switch_core_session_execute_application(ep->eavesdropper, data->var, data->val); + } +} + +static void display_exec_cb(switch_media_bug_t *bug, void *user_data) +{ + struct exec_cb_data *data = (struct exec_cb_data *) user_data; + struct eavesdrop_pvt *ep = (struct eavesdrop_pvt *) switch_core_media_bug_get_user_data(bug); + + if (ep && ep->eavesdropper && ep->eavesdropper != data->caller) { + switch_core_session_message_t msg = { 0 }; + + msg.from = __FILE__; + msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY; + msg.string_array_arg[0] = data->var; + msg.string_array_arg[1] = data->val; + + switch_core_session_receive_message(ep->eavesdropper, &msg); + } +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_exec_all(switch_core_session_t *session, const char *app, const char *arg) +{ + struct exec_cb_data *data = NULL; + + data = switch_core_session_alloc(session, sizeof(*data)); + data->var = switch_core_session_strdup(session, app); + data->val = switch_core_session_strdup(session, arg); + data->caller = session; + + return switch_core_media_bug_exec_all(session, "eavesdrop", exec_cb, data); +} + + +SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_update_display(switch_core_session_t *session, const char *name, const char *number) +{ + struct exec_cb_data *data = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_status_t status = SWITCH_STATUS_FALSE; + + data = switch_core_session_alloc(session, sizeof(*data)); + data->var = switch_core_session_strdup(session, name); + data->val = switch_core_session_strdup(session, number); + data->caller = session; + + if (!switch_channel_test_app_flag_key("EAVESDROP", channel, 1)) { + switch_channel_set_app_flag_key("EAVESDROP", channel, 1); + status = switch_core_media_bug_exec_all(session, "eavesdrop", display_exec_cb, data); + switch_channel_clear_app_flag_key("EAVESDROP", channel, 1); + } + + return status; +} + + SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session_t *session, const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags) { @@ -1236,6 +1339,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session switch_status_t status = SWITCH_STATUS_FALSE; switch_channel_t *channel = switch_core_session_get_channel(session); int codec_initialized = 0; + const char *name, *num; if ((tsession = switch_core_session_locate(uuid))) { struct eavesdrop_pvt *ep = NULL; @@ -1341,6 +1445,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session write_frame.buflen = sizeof(buf); write_frame.rate = codec.implementation->actual_samples_per_second; + ep->eavesdropper = session; ep->flags = flags; switch_mutex_init(&ep->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession)); switch_buffer_create_dynamic(&ep->buffer, 2048, 2048, 8192); @@ -1370,9 +1475,28 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session /* Tell the channel we are going to be in a bridge */ msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE; switch_core_session_receive_message(session, &msg); - cp = switch_channel_get_caller_profile(tchannel); - switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", cp->caller_id_number, cp->caller_id_name); + name = cp->caller_id_name; + num = cp->caller_id_number; + + if (flags & ED_COPY_DISPLAY) { + const char *tmp_name = NULL, *tmp_num = NULL; + name = cp->callee_id_name; + num = cp->callee_id_number; + + if (!((tmp_name = switch_channel_get_variable(tchannel, "last_sent_callee_id_name")) + && (tmp_num = switch_channel_get_variable(tchannel, "last_sent_callee_id_number")))) { + + tmp_name = switch_channel_get_variable(tchannel, "callee_id_name"); + tmp_num = switch_channel_get_variable(tchannel, "callee_id_number"); + } + + if (tmp_name) name = tmp_name; + if (tmp_num) num = tmp_num; + + } + + switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", name, num); msg.string_arg = cid_buf; msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY; switch_core_session_receive_message(session, &msg); diff --git a/src/switch_resample.c b/src/switch_resample.c index 136adc9694..6722d6f448 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -252,6 +252,25 @@ SWITCH_DECLARE(uint32_t) switch_merge_sln(int16_t *data, uint32_t samples, int16 return x; } + +SWITCH_DECLARE(uint32_t) switch_unmerge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples) +{ + int i; + int32_t x; + + if (samples > other_samples) { + x = other_samples; + } else { + x = samples; + } + + for (i = 0; i < x; i++) { + data[i] -= other_data[i]; + } + + return x; +} + SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t channels) { int16_t *buf;