]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
re-implement sla barge using eavesdrop backend
authorAnthony Minessale <anthm@freeswitch.org>
Mon, 7 May 2012 18:44:10 +0000 (13:44 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Mon, 7 May 2012 18:44:16 +0000 (13:44 -0500)
13 files changed:
src/include/private/switch_core_pvt.h
src/include/switch_core.h
src/include/switch_ivr.h
src/include/switch_resample.h
src/include/switch_types.h
src/mod/endpoints/mod_sofia/mod_sofia.c
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_presence.c
src/switch_core_io.c
src/switch_core_media_bug.c
src/switch_ivr_async.c
src/switch_resample.c

index 781f0e4d068c2e297ef6340c97edb622f5a5fa47..95e66f2f6dc2f387b3298954cfde6b764d2ac964 100644 (file)
@@ -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;
 };
 
index 001165247543fd68a613d9dfafe84ebd08e62f29..91cff21d6749f6eafe1ae383990251ce12b8c7dc 100644 (file)
@@ -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);
index 8f553b957e9255d3c2177efa5d5e464ed61b8f55..ef5155512c8376c8fd090e41d7e381750d9f7bb4 100644 (file)
@@ -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
index 7ae37669c74df42ee6363567eac8988888a54d16..f85a61f0652ba3cfe7a472abe91a537177ff9ac0 100644 (file)
@@ -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
index 93a2e48ced9eb69e826866c439b2707eaf7a1078..5fda9c369e775a79c0e8eca14cac6108b2e7cc44 100644 (file)
@@ -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);
index ea2ba7ce4d0ffe3e318017a3e1fe57e88e78fa5c..a71dc4c7141614c580afa7aa9c2c0cfae11dd65e 100644 (file)
@@ -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: <uuid>\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, "<uuid>", SAF_NONE);
+
        SWITCH_ADD_API(api_interface, "sofia", "Sofia Controls", sofia_function, "<cmd> <args>");
        SWITCH_ADD_API(api_interface, "sofia_gateway_data", "Get data from a sofia gateway", sofia_gateway_data_function,
                                   "<gateway_name> [ivar|ovar|var] <name>");
index 5a51f68a2d40cd6ffe59307237fe505988a86f2d..b66b29fb44caf2dd4b0e89f12a2c1f11156de0ee 100644 (file)
@@ -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;
index 7ae868ef627bb81c969b94e103ca96a173c3e3bd..26815b6f5eb84890a96754e20fb418557e1a35cb 100644 (file)
@@ -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";
                                        }
index 6befca3439decea0cafa580e094d2c1854aec492..c4eb565f859ed60539372d67d81da8a884ddccc4 100644 (file)
@@ -1167,6 +1167,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
                                        }
                                }
 #endif
+                               
 
                                if (hup && dh.hits > 0) {
                                        goto done;
index 020556a490bd7386f7f96084c63734b1f4f0a0fa..f20fa7bff9d48af8279dd0e804c4402d87ca65bc 100644 (file)
@@ -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;
                }
index f5d14137b70a950c6639b71c3fd4a5b7a156caff..a320d9a345d0a431dc224f6ff458a9e47c313961 100644 (file)
@@ -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) {
index ecddfdbbb67813a7681f0fb32abf17a2e6a2d243..5d6127d054d6090a2be93bb6e800635be03f2e5c 100644 (file)
@@ -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);
index 136adc9694b39e1c8fd8c429a3853722c7f8d960..6722d6f448365a98456c0473e2de5e6909d344ba 100644 (file)
@@ -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;