re-implement sla barge using eavesdrop backend

This commit is contained in:
Anthony Minessale 2012-05-07 13:44:10 -05:00
parent cc1c47b6fe
commit a511ff3026
13 changed files with 378 additions and 80 deletions

View 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;
};

View 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);

View 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

View 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

View 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);

View 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>");

View 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;

View 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);
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);
}
}
"answer,sofia_sla:%s", b_private->uuid);
tech_pvt->caller_profile->dialplan = "inline";
}

View File

@ -1168,6 +1168,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
}
#endif
if (hup && dh.hits > 0) {
goto done;
}

View 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;
}

View 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,11 +655,16 @@ 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;
}
@ -638,6 +711,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) {
for (bp = session->bugs; bp; bp = bp->next) {

View 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);

View 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;