[core] eavesdrop: init L16 codec at right ptime in certain conditions.
[core] eavesdrop: avoid eavesdropping on itself and return error. [core] eavesdrop: adjust buffer operations for ptime mismatch and for when ptimes are the same. [core] eavesdrop: add buffering based on LCM (Least Common Multiple) when ptime mismatch, and have audio write thread enabled when ptime eavesdropee < ptime eavesdropper. [unit-tests] add unit-tests for eavesdrop.
This commit is contained in:
parent
3509ae537e
commit
5aabb54f68
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
<?xml version="1.0"?>
|
||||
<document type="freeswitch/xml">
|
||||
<X-PRE-PROCESS cmd="exec-set" data="test=echo 1234"/>
|
||||
<X-PRE-PROCESS cmd="set" data="default_password=$${test}"/>
|
||||
<X-PRE-PROCESS cmd="set" data="core_video_blank_image=$${conf_dir}/freeswitch-logo.png"/>
|
||||
<section name="configuration" description="Various Configuration">
|
||||
<configuration name="modules.conf" description="Modules">
|
||||
<modules>
|
||||
<load module="mod_sofia"/>
|
||||
<load module="mod_console"/>
|
||||
<load module="mod_loopback"/>
|
||||
<load module="mod_commands"/>
|
||||
<load module="mod_dptools"/>
|
||||
<load module="mod_dialplan_xml"/>
|
||||
<load module="mod_tone_stream"/>
|
||||
<load module="mod_commands"/>
|
||||
<load module="mod_sndfile"/>
|
||||
</modules>
|
||||
</configuration>
|
||||
|
||||
<configuration name="console.conf" description="Console Logger">
|
||||
<mappings>
|
||||
<map name="all" value="console,debug,info,notice,warning,err,crit,alert"/>
|
||||
</mappings>
|
||||
<settings>
|
||||
<param name="colorize" value="true"/>
|
||||
<param name="loglevel" value="debug"/>
|
||||
</settings>
|
||||
</configuration>
|
||||
|
||||
<configuration name="timezones.conf" description="Timezones">
|
||||
<timezones>
|
||||
<zone name="GMT" value="GMT0" />
|
||||
</timezones>
|
||||
</configuration>
|
||||
|
||||
<configuration name="sofia.conf" description="SofiaSIP">
|
||||
<profiles>
|
||||
<profile name="external">
|
||||
<gateways>
|
||||
|
||||
<gateway name="eavestest">
|
||||
<param name="username" value="not-used"/>
|
||||
<param name="password" value="not-used"/>
|
||||
<param name="proxy" value="$${local_ip_v4}:61068"/>
|
||||
<param name="register" value="false"/>
|
||||
<param name="retry-seconds" value="30"/>
|
||||
<param name="dtmf-type" value="rfc2833"/>
|
||||
<variables>
|
||||
<variable name="rtp_secure_media" value="false" direction="outbound"/>
|
||||
</variables>
|
||||
</gateway>
|
||||
</gateways>
|
||||
|
||||
<domains>
|
||||
<domain name="all" alias="false" parse="true"/>
|
||||
</domains>
|
||||
|
||||
<settings>
|
||||
<param name="debug" value="1"/>
|
||||
<param name="shutdown-on-fail" value="true"/>
|
||||
<param name="p-asserted-id-parse" value="verbatim"/>
|
||||
<param name="username" value="SignalWire-STACK"/>
|
||||
<param name="user-agent-string" value="SignalWire STACK Unit Test"/>
|
||||
<param name="sip-trace" value="yes"/>
|
||||
<param name="sip-capture" value="no"/>
|
||||
<param name="rfc2833-pt" value="101"/>
|
||||
<param name="sip-port" value="61068"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dtmf-duration" value="2000"/>
|
||||
<param name="inbound-codec-prefs" value="PCMU"/>
|
||||
<param name="outbound-codec-prefs" value="PCMU"/>
|
||||
<param name="rtp-timer-name" value="soft"/>
|
||||
<param name="local-network-acl" value="localnet.auto"/>
|
||||
<param name="manage-presence" value="false"/>
|
||||
<param name="inbound-codec-negotiation" value="generous"/>
|
||||
<param name="nonce-ttl" value="60"/>
|
||||
<param name="inbound-late-negotiation" value="true"/>
|
||||
<param name="inbound-zrtp-passthru" value="false"/>
|
||||
<param name="rtp-ip" value="$${local_ip_v4}"/>
|
||||
<param name="sip-ip" value="$${local_ip_v4}"/>
|
||||
<param name="ext-rtp-ip" value="$${local_ip_v4}"/>
|
||||
<param name="ext-sip-ip" value="$${local_ip_v4}"/>
|
||||
<param name="rtp-timeout-sec" value="300"/>
|
||||
<param name="rtp-hold-timeout-sec" value="1800"/>
|
||||
<param name="session-timeout" value="600"/>
|
||||
<param name="minimum-session-expires" value="90"/>
|
||||
<param name="tls" value="false"/>
|
||||
</settings>
|
||||
</profile>
|
||||
|
||||
<profile name="internal">
|
||||
<gateways>
|
||||
</gateways>
|
||||
|
||||
<domains>
|
||||
<domain name="all" alias="false" parse="true"/>
|
||||
</domains>
|
||||
|
||||
<settings>
|
||||
<param name="debug" value="1"/>
|
||||
<param name="shutdown-on-fail" value="true"/>
|
||||
<param name="p-asserted-id-parse" value="verbatim"/>
|
||||
<param name="username" value="SignalWire-STACK"/>
|
||||
<param name="user-agent-string" value="SignalWire STACK Unit Test"/>
|
||||
<param name="sip-trace" value="yes"/>
|
||||
<param name="sip-capture" value="no"/>
|
||||
<param name="rfc2833-pt" value="101"/>
|
||||
<param name="sip-port" value="61069"/>
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="context" value="default"/>
|
||||
<param name="dtmf-duration" value="2000"/>
|
||||
<param name="inbound-codec-prefs" value="PCMU"/>
|
||||
<param name="outbound-codec-prefs" value="PCMU"/>
|
||||
<param name="rtp-timer-name" value="soft"/>
|
||||
<param name="local-network-acl" value="localnet.auto"/>
|
||||
<param name="manage-presence" value="false"/>
|
||||
<param name="inbound-codec-negotiation" value="generous"/>
|
||||
<param name="nonce-ttl" value="60"/>
|
||||
<param name="inbound-late-negotiation" value="true"/>
|
||||
<param name="inbound-zrtp-passthru" value="false"/>
|
||||
<param name="rtp-ip" value="$${local_ip_v4}"/>
|
||||
<param name="sip-ip" value="$${local_ip_v4}"/>
|
||||
<param name="ext-rtp-ip" value="$${local_ip_v4}"/>
|
||||
<param name="ext-sip-ip" value="$${local_ip_v4}"/>
|
||||
<param name="rtp-timeout-sec" value="300"/>
|
||||
<param name="rtp-hold-timeout-sec" value="1800"/>
|
||||
<param name="session-timeout" value="600"/>
|
||||
<param name="minimum-session-expires" value="90"/>
|
||||
<param name="tls" value="false"/>
|
||||
</settings>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
</configuration>
|
||||
|
||||
<configuration name="switch.conf" description="Switch">
|
||||
<param name="rtp-start-port" value="20000"/>
|
||||
<param name="rtp-end-port" value="30000"/>
|
||||
<param name="threaded-system-exec" value="true"/>
|
||||
</configuration>
|
||||
</section>
|
||||
|
||||
<section name="dialplan" description="Regex/XML Dialplan">
|
||||
<context name="default">
|
||||
<extension name="one">
|
||||
<condition field="destination_number" expression="^\+15553332220$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@20i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="park""/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="two">
|
||||
<condition field="destination_number" expression="^\+15553332221$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@10i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="three">
|
||||
<condition field="destination_number" expression="^\+15553332222$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@30i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="four">
|
||||
<condition field="destination_number" expression="^\+15553332223$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@40i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="five">
|
||||
<condition field="destination_number" expression="^\+15553332224$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@80i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="six">
|
||||
<condition field="destination_number" expression="^\+15553332225$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@10i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="seven">
|
||||
<condition field="destination_number" expression="^\+15553332226$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@20i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="record_session" data="/tmp/eaves-${uuid}.wav"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="eavesdropper_20ms">
|
||||
<condition field="destination_number" expression="^\+15553332230$">
|
||||
<action application="answer"/>
|
||||
<action application="record_session" data="/tmp/eaves-${sip_h_X-UnitTestRecfile}.wav"/>
|
||||
<action application="playback" data="silence_stream://-1,1400"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="eight">
|
||||
<condition field="destination_number" expression="^\+15553332231$">
|
||||
<action application="answer"/>
|
||||
<action application="park"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
<extension name="eavesdropper_30ms">
|
||||
<condition field="destination_number" expression="^\+15553332240$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@30i"/>
|
||||
<action application="answer"/>
|
||||
<action application="record_session" data="/tmp/eaves-${sip_h_X-UnitTestRecfile}.wav"/>
|
||||
<action application="playback" data="silence_stream://-1,1400"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
<extension name="ten">
|
||||
<condition field="destination_number" expression="^\+15553332241$">
|
||||
<action application="set" data="absolute_codec_string=PCMU@30i"/>
|
||||
<action application="info"/>
|
||||
<action application="answer"/>
|
||||
<action application="playback" data="{loops=-1}tone_stream://%(251,0,300)"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
</context>
|
||||
</section>
|
||||
</document>
|
|
@ -0,0 +1,14 @@
|
|||
<include/>
|
||||
<gateway name="eavestest">
|
||||
<param name="username" value="not-used"/>
|
||||
<param name="password" value="not-used"/>
|
||||
<param name="proxy" value="127.0.0.1"/>
|
||||
<param name="register" value="false"/>
|
||||
<param name="retry-seconds" value="30"/>
|
||||
<param name="dtmf-type" value="rfc2833"/>
|
||||
<variables>
|
||||
<variable name="rtp_secure_media" value="false" direction="outbound"/>
|
||||
</variables>
|
||||
</gateway>
|
||||
</include>
|
||||
|
|
@ -0,0 +1,392 @@
|
|||
#include <strings.h>
|
||||
#include <switch.h>
|
||||
#include <test/switch_test.h>
|
||||
|
||||
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()
|
||||
|
Loading…
Reference in New Issue