diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c
index a6972e847c..07f28a36e8 100644
--- a/src/switch_ivr_async.c
+++ b/src/switch_ivr_async.c
@@ -2184,6 +2184,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_update_display(switch_core_
return status;
}
+/*Greatest Common Divisor*/
+static uint32_t switch_gcd(uint32_t x, uint32_t y)
+{
+ if (y == 0) {
+ return x;
+ }
+
+ return switch_gcd(y, x % y);
+}
+
+/*Least Common Multiple*/
+static uint32_t switch_lcm(uint32_t x, uint32_t y)
+{
+ uint32_t gcd = switch_gcd(x, y);
+
+ if (gcd) return (x * y) / gcd;
+
+ return 0;
+}
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)
@@ -2213,11 +2232,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
const char *vval;
int buf_size = 0;
int channels;
+ int lcm, buff_min_len, buffered = 1;
if (!switch_channel_media_up(channel)) {
goto end;
}
+ if (tsession == session) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Eavesdrop target invalid.\n");
+ goto end;
+ }
+
while(switch_channel_state_change_pending(tchannel) || !switch_channel_media_up(tchannel)) {
switch_yield(10000);
if (!--sanity) break;
@@ -2286,8 +2311,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
goto end;
}
-
- if (switch_core_codec_init(&codec,
+ if (tread_impl.decoded_bytes_per_packet < read_impl.decoded_bytes_per_packet) {
+ if (switch_core_codec_init(&codec,
+ "L16",
+ NULL,
+ NULL,
+ read_impl.actual_samples_per_second,
+ read_impl.microseconds_per_packet / 1000,
+ read_impl.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_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
+ goto end;
+ }
+ } else {
+ if (switch_core_codec_init(&codec,
"L16",
NULL,
NULL,
@@ -2298,10 +2336,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
goto end;
+ }
+ buffered = 0;
}
- switch_core_session_get_read_impl(session, &read_impl);
-
ep->read_impl = read_impl;
ep->tread_impl = tread_impl;
@@ -2440,6 +2478,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
switch_core_session_receive_message(tsession, &msg);
}
+ lcm = switch_lcm(tread_impl.decoded_bytes_per_packet, read_impl.decoded_bytes_per_packet);
+
while (switch_channel_up_nosig(tchannel) && switch_channel_ready(channel)) {
uint32_t len = sizeof(buf);
switch_event_t *event = NULL;
@@ -2569,15 +2609,24 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
channels = 1;
}
- tlen = tread_impl.decoded_bytes_per_packet * channels;
+ tlen = ep->read_impl.decoded_bytes_per_packet * channels;
if (len > tlen) {
len = tlen;
}
+ if (buffered) {
+ buff_min_len = lcm * 2;
+ if (switch_buffer_inuse(ep->buffer) < buff_min_len) {
+ continue;
+ }
+ } else {
+ buff_min_len = len;
+ }
+
if (ep->buffer) {
switch_buffer_lock(ep->buffer);
- while (switch_buffer_inuse(ep->buffer) >= len) {
+ while (switch_buffer_inuse(ep->buffer) >= buff_min_len) {
int tchanged = 0, changed = 0;
write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
@@ -2592,7 +2641,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
tchanged = 1;
}
- if (read_impl.number_of_channels != ep->tread_impl.number_of_channels ||
+ if (read_impl.number_of_channels != ep->read_impl.number_of_channels ||
read_impl.actual_samples_per_second != ep->read_impl.actual_samples_per_second) {
changed = 1;
}
@@ -2606,6 +2655,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
ep->read_impl.number_of_channels,
read_impl.actual_samples_per_second,
read_impl.number_of_channels);
+
+ tlen = read_impl.decoded_bytes_per_packet * channels;
+
+ if (len > tlen) {
+ len = tlen;
+ }
+
}
if (tchanged) {
@@ -2615,28 +2671,44 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
ep->tread_impl.number_of_channels,
tread_impl.actual_samples_per_second,
tread_impl.number_of_channels);
+ }
+
- tlen = tread_impl.decoded_bytes_per_packet * channels;
-
- if (len > tlen) {
- len = tlen;
- }
-
- switch_core_codec_destroy(&codec);
+ switch_core_codec_destroy(&codec);
+ if (tread_impl.decoded_bytes_per_packet < read_impl.decoded_bytes_per_packet) {
if (switch_core_codec_init(&codec,
"L16",
NULL,
NULL,
- tread_impl.actual_samples_per_second,
- tread_impl.microseconds_per_packet / 1000,
- tread_impl.number_of_channels,
+ read_impl.actual_samples_per_second,
+ read_impl.microseconds_per_packet / 1000,
+ read_impl.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_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
+ switch_buffer_unlock(ep->buffer);
+ goto end;
+ }
+ buffered = 1;
+ lcm = switch_lcm(tread_impl.decoded_bytes_per_packet, read_impl.decoded_bytes_per_packet);
+ } else {
+ if (switch_core_codec_init(&codec,
+ "L16",
+ NULL,
+ NULL,
+ tread_impl.actual_samples_per_second,
+ tread_impl.microseconds_per_packet / 1000,
+ tread_impl.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_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
switch_buffer_unlock(ep->buffer);
goto end;
}
+ if (buffered == 1) {
+ buffered = 0;
+ }
}
ep->read_impl = read_impl;
@@ -2658,11 +2730,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
switch_buffer_unlock(ep->buffer);
switch_buffer_lock(ep->buffer);
- }
+ if (ep->tread_impl.decoded_bytes_per_packet == ep->read_impl.decoded_bytes_per_packet) {
+ /* push just the number of samples worth of a packet. */
+ break;
+ }
+ }
switch_buffer_unlock(ep->buffer);
}
-
}
end_loop:
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index 6e7e128d62..2511a143c2 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -7,8 +7,13 @@ noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_core_asr
AM_LDFLAGS += -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS) $(openssl_LIBS)
AM_LDFLAGS += $(FREESWITCH_LIBS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS)
+# "make check" will not run these.
+examples = switch_eavesdrop
+
if HAVE_FVAD
AM_CFLAGS += -DSWITCH_HAVE_FVAD
endif
TESTS = $(noinst_PROGRAMS)
+
+bin_PROGRAMS = $(examples)
diff --git a/tests/unit/conf_eavesdrop/freeswitch.xml b/tests/unit/conf_eavesdrop/freeswitch.xml
new file mode 100644
index 0000000000..4a65caf6d8
--- /dev/null
+++ b/tests/unit/conf_eavesdrop/freeswitch.xml
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/conf_eavesdrop/gw/eavestest.xml b/tests/unit/conf_eavesdrop/gw/eavestest.xml
new file mode 100644
index 0000000000..a2f268424e
--- /dev/null
+++ b/tests/unit/conf_eavesdrop/gw/eavestest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/switch_eavesdrop.c b/tests/unit/switch_eavesdrop.c
new file mode 100644
index 0000000000..867ad7a6bc
--- /dev/null
+++ b/tests/unit/switch_eavesdrop.c
@@ -0,0 +1,392 @@
+#include
+#include
+#include
+
+static switch_memory_pool_t *pool = NULL;
+
+static switch_status_t test_detect_long_tone_in_file(const char *filepath, int rate, int freq, int ptime) {
+ teletone_multi_tone_t mt;
+ teletone_tone_map_t map;
+ int16_t data[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
+ size_t len = (rate * ptime / 1000) /*packet len in samples */ * 8; /*length of chunk that must contain tone*/
+ size_t fin = 0;
+ switch_status_t status;
+ switch_file_handle_t fh = { 0 };
+ uint8_t fail = 0, gaps = 0, audio = 0;
+ uint32_t pos = 0;
+ size_t full_len = 0;
+
+ status = switch_core_file_open(&fh, filepath, 1, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL);
+ if (status != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open file [%s]\n", filepath);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ mt.sample_rate = rate;
+ map.freqs[0] = (teletone_process_t)freq;
+
+ teletone_multi_tone_init(&mt, &map);
+
+ len = (rate * 2 / 100) /*packet len in samples */ * 8;
+
+ while (switch_core_file_read(&fh, &data, &len) == SWITCH_STATUS_SUCCESS) {
+ fin += len;
+ /*skip silence at the beginning of the file, 1 second max. */
+ if (!teletone_multi_tone_detect(&mt, data, len)) {
+ if ((fin > rate && !audio) || gaps > 30) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many gaps in audio or no tone detected 1st second. [%u][%d]\n", fin, gaps);
+ fail = 1;
+ break;
+ }
+ gaps++;
+ continue;
+ } else {
+ audio++;
+ }
+ }
+
+ switch_core_file_close(&fh);
+
+ if (fail) {
+ return SWITCH_STATUS_FALSE;
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+FST_CORE_BEGIN("./conf_eavesdrop")
+
+{
+FST_SUITE_BEGIN(switch_eavesdrop)
+{
+ FST_SETUP_BEGIN()
+ {
+ fst_requires_module("mod_loopback");
+ fst_requires_module("mod_sofia");
+ switch_core_set_variable("link_ip", switch_core_get_variable("local_ip_v4"));
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_same_ptime_20ms)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 20 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332220", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332230", rec_uuid);
+
+ /*eavesdropper 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332226", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(5); // it will record ~ 5 secs
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 20) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_ptime_mismatch_20ms_30ms)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 20 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332220", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332230", rec_uuid);
+
+ /*eavesdropper 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 30 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332222", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(5); // it will record ~ 5 secs
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 20) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_ptime_mismatch_30ms_20ms)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 30 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332231", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332240", rec_uuid);
+
+ /*eavesdropper 30 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332226", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(5); // it will record ~ 5 secs
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 30) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_ptime_mismatch_reneg)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 30 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332231", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332240", rec_uuid);
+
+ /*eavesdropper 30 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332226", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+
+ sleep(2);
+
+ // codec reneg for eavesdropper
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_media_reneg %s = PCMU@20i", switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+
+ sleep(1);
+
+ // codec reneg for eavesdroppee
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_media_reneg %s = PCMU@30i", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(2);
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 30) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+}
+FST_SUITE_END()
+}
+FST_CORE_END()
+