forked from Mirrors/freeswitch
re-implement sla barge using eavesdrop backend
This commit is contained in:
parent
cc1c47b6fe
commit
a511ff3026
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -1167,6 +1167,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (hup && dh.hits > 0) {
|
||||
goto done;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue