SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session_t *session, const char *uuid, switch_eavesdrop_flag_t flags) { switch_core_session_t *tsession; switch_status_t status = SWITCH_STATUS_FALSE; switch_channel_t *channel = switch_core_session_get_channel(session); switch_codec_t *read_codec = switch_core_session_get_read_codec(session); if ((tsession = switch_core_session_locate(uuid))) { struct eavesdrop_pvt *ep; switch_media_bug_t *bug = NULL; switch_channel_t *tchannel = switch_core_session_get_channel(tsession); switch_frame_t *read_frame, write_frame = { 0 }; switch_codec_t codec = {0}; int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE/2]; switch_codec_t *tread_codec = switch_core_session_get_read_codec(tsession); uint32_t tlen = tread_codec->implementation->bytes_per_frame; ep = switch_core_session_alloc(session, sizeof(*ep)); switch_channel_pre_answer(channel); if (switch_core_codec_init(&codec, "L16", NULL, tread_codec->implementation->actual_samples_per_second, tread_codec->implementation->microseconds_per_frame / 1000, tread_codec->implementation->number_of_channels, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot init codec\n"); switch_core_session_rwunlock(tsession); return status; } switch_core_session_set_read_codec(session, &codec); write_frame.codec = &codec; write_frame.data = buf; write_frame.buflen = sizeof(buf); write_frame.rate = read_codec->implementation->actual_samples_per_second; 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); switch_buffer_add_mutex(ep->buffer, ep->mutex); switch_mutex_init(&ep->w_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession)); switch_buffer_create_dynamic(&ep->w_buffer, 2048, 2048, 8192); switch_buffer_add_mutex(ep->w_buffer, ep->w_mutex); switch_mutex_init(&ep->r_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession)); switch_buffer_create_dynamic(&ep->r_buffer, 2048, 2048, 8192); switch_buffer_add_mutex(ep->r_buffer, ep->r_mutex); if (switch_core_media_bug_add(tsession, eavesdrop_callback, ep, 0, SMBF_READ_STREAM | SMBF_WRITE_STREAM | SMBF_READ_REPLACE | SMBF_WRITE_REPLACE | SMBF_READ_PING | SMBF_THREAD_LOCK, &bug) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot attach bug\n"); goto end; } while(switch_channel_ready(tchannel) && switch_channel_ready(channel)) { uint32_t len = sizeof(buf); switch_event_t *event = NULL; char *fcommand = NULL; char db[2] = ""; status = switch_core_session_read_frame(session, &read_frame, 1000, 0); if (!SWITCH_READ_ACCEPTABLE(status)) { goto end; } if (switch_core_session_dequeue_event(session, &event) == SWITCH_STATUS_SUCCESS) { char *command = switch_event_get_header(event, "eavesdrop-command"); if (command) { fcommand = command; } switch_event_destroy(&event); } if ((flags & ED_DTMF) && switch_channel_has_dtmf(channel)) { switch_dtmf_t dtmf = {0}; switch_channel_dequeue_dtmf(channel, &dtmf); db[0] = dtmf.digit; fcommand = db; } if (fcommand) { char *d; for(d = fcommand; *d; d++) { int z = 1; switch (*d) { case '1': switch_set_flag(ep, ED_MUX_READ); switch_clear_flag(ep, ED_MUX_WRITE); break; case '2': switch_set_flag(ep, ED_MUX_WRITE); switch_clear_flag(ep, ED_MUX_READ); break; case '3': switch_set_flag(ep, ED_MUX_READ); switch_set_flag(ep, ED_MUX_WRITE); break; case '*': switch_core_codec_destroy(&codec); return status; case '0': switch_clear_flag(ep, ED_MUX_READ); switch_clear_flag(ep, ED_MUX_WRITE); break; default: z = 0; break; } if (z) { if (ep->r_buffer) { switch_buffer_lock(ep->r_buffer); switch_buffer_zero(ep->r_buffer); switch_buffer_unlock(ep->r_buffer); } if (ep->w_buffer) { switch_buffer_lock(ep->w_buffer); switch_buffer_zero(ep->w_buffer); switch_buffer_unlock(ep->w_buffer); } } } } if (!switch_test_flag(read_frame, SFF_CNG)) { switch_buffer_lock(ep->r_buffer); switch_buffer_zwrite(ep->r_buffer, read_frame->data, read_frame->datalen); switch_buffer_unlock(ep->r_buffer); switch_buffer_lock(ep->w_buffer); switch_buffer_zwrite(ep->w_buffer, read_frame->data, read_frame->datalen); switch_buffer_unlock(ep->w_buffer); } if (len > tlen) { len = tlen; } if (switch_buffer_inuse(ep->buffer) >= len) { switch_buffer_lock(ep->buffer); while (switch_buffer_inuse(ep->buffer) >= len) { write_frame.datalen = (uint32_t)switch_buffer_read(ep->buffer, buf, len); write_frame.samples = write_frame.datalen / 2; if ((status = switch_core_session_write_frame(session, &write_frame, 1000, 0)) != SWITCH_STATUS_SUCCESS) { break; } } switch_buffer_unlock(ep->buffer); } } end: switch_core_codec_destroy(&codec); if (bug) { switch_core_media_bug_remove(tsession, &bug); } if (ep->buffer) { switch_buffer_destroy(&ep->buffer); } if (ep->r_buffer) { switch_buffer_destroy(&ep->r_buffer); } if (ep->w_buffer) { switch_buffer_destroy(&ep->w_buffer); } switch_core_session_rwunlock(tsession); status = SWITCH_STATUS_SUCCESS; switch_core_session_set_read_codec(session, read_codec); switch_core_session_reset(session, SWITCH_TRUE); } return status; }