TT#136957 support multiple frequencies for `tone`

Support multiple tone frequencies for DTMF-security=tone to enable
audibly distinguishing multiple consecutive DTMF events from one
another.

Change-Id: I6fa33a5768aae198220d0b0cc4c53308c5661a52
pull/1577/head
Richard Fuchs 2 years ago
parent f95495d4f0
commit 25e2640145

@ -1627,10 +1627,14 @@ Optionally included keys are:
digits has been detected, the blocking mode is switched to the
`trigger-end` mode.
* `frequency`
Sets the tone frequency for `DTMF-security=tone` in Hertz. The default
is 400 Hz.
* `frequency` or `frequencies`
Sets the tone frequency or frequencies for `DTMF-security=tone` in Hertz.
The default is a single frequency of 400 Hz. A list of frequencies can be
given either as a list object, or as a string containing a comma-separated
list of integers. The given frequencies will be picked from the list in
order, one for each DTMF event detected, and will be repeated once the end
of the list is reached.
* `volume`

@ -3451,6 +3451,8 @@ static void __call_cleanup(struct call *c) {
struct call_monologue *ml = l->data;
__monologue_stop(ml);
media_player_put(&ml->player);
if (ml->tone_freqs)
g_array_free(ml->tone_freqs, true);
}
while (c->stream_fds.head) {

@ -979,6 +979,7 @@ void call_ng_flags_init(struct sdp_ng_flags *out, enum call_opmode opmode) {
out->delay_buffer = -1;
out->volume = 9999;
out->digit = -1;
out->frequencies = g_array_new(false, false, sizeof(int));
}
static void call_ng_dict_iter(struct sdp_ng_flags *out, bencode_item_t *input,
@ -1079,6 +1080,30 @@ static void call_ng_parse_block_mode(str *s, enum block_dtmf_mode *output) {
}
}
#endif
static void call_ng_flags_freqs(struct sdp_ng_flags *out, bencode_item_t *value) {
switch (value->type) {
case BENCODE_INTEGER:;
unsigned int val = value->value;
g_array_append_val(out->frequencies, val);
break;
case BENCODE_LIST:
for (bencode_item_t *it = value->child; it; it = it->sibling)
call_ng_flags_freqs(out, it);
break;
case BENCODE_STRING:;
str s, token;
bencode_get_str(value, &s);
while (str_token_sep(&token, &s, ',') == 0) {
unsigned int val = str_to_i(&token, 0);
g_array_append_val(out->frequencies, val);
}
break;
default:
ilog(LOG_WARN, "Invalid content type in `frequencies` list");
}
}
static void call_ng_main_flags(struct sdp_ng_flags *out, str *key, bencode_item_t *value) {
str s = STR_NULL;
bencode_item_t *it;
@ -1384,7 +1409,8 @@ static void call_ng_main_flags(struct sdp_ng_flags *out, str *key, bencode_item_
}
break;
case CSH_LOOKUP("frequency"):
out->frequency = bencode_get_integer_str(value, out->frequency);
case CSH_LOOKUP("frequencies"):
call_ng_flags_freqs(out, value);
break;
case CSH_LOOKUP("volume"):
out->volume = bencode_get_integer_str(value, out->volume);
@ -1515,6 +1541,8 @@ void call_ng_free_flags(struct sdp_ng_flags *flags) {
g_hash_table_destroy(flags->codec_set);
if (flags->sdes_no)
g_hash_table_destroy(flags->sdes_no);
if (flags->frequencies)
g_array_free(flags->frequencies, true);
g_queue_clear_full(&flags->from_tags, free);
g_queue_clear_full(&flags->codec_offer, free);
g_queue_clear_full(&flags->codec_transcode, free);
@ -2556,8 +2584,12 @@ static void call_monologue_set_block_mode(struct call_monologue *ml, struct sdp_
else if (flags->volume < 0 && flags->volume >= -63)
ml->tone_vol = -1 * flags->volume;
if (flags->frequency > 0)
ml->tone_freq = flags->frequency;
if (flags->frequencies && flags->frequencies->len > 0) {
if (ml->tone_freqs)
g_array_free(ml->tone_freqs, true);
ml->tone_freqs = flags->frequencies;
flags->frequencies = NULL;
}
if (flags->block_dtmf_mode == BLOCK_DTMF_ZERO)
ml->dtmf_digit = '0';

@ -2682,9 +2682,13 @@ static void delay_frame_manipulate(struct delay_frame *dframe) {
case BLOCK_DTMF_SILENCE:
memset(frame->extended_data[0], 0, frame->linesize[0]);
break;
case BLOCK_DTMF_TONE:
case BLOCK_DTMF_TONE:;
unsigned int freq = 0;
if (ml->tone_freqs && ml->tone_freqs->len)
freq = g_array_index(ml->tone_freqs, unsigned int,
dtmf_recv->index % ml->tone_freqs->len);
frame_fill_tone_samples(frame->format, frame->extended_data[0], dframe->ts,
frame->nb_samples, ml->tone_freq ? : 400,
frame->nb_samples, freq ?: 400,
ml->tone_vol ? : 10, frame->sample_rate, GET_CHANNELS(frame));
break;
case BLOCK_DTMF_ZERO:

@ -282,7 +282,7 @@ static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, i
ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = event, .ts = ts, .volume = volume,
.rand_code = '0' + (ssl_random() % 10) };
.rand_code = '0' + (ssl_random() % 10), .index = media->dtmf_count };
g_queue_push_tail(&media->dtmf_recv, ev);
ev = g_slice_alloc0(sizeof(*ev));
@ -290,6 +290,8 @@ static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, i
.volume = volume,
.block_dtmf = media->monologue->block_dtmf };
g_queue_push_tail(&media->dtmf_send, ev);
media->dtmf_count++;
}

@ -430,6 +430,7 @@ struct call_media {
mutex_t dtmf_lock;
unsigned long dtmf_ts; /* TS of last processed end event */
unsigned int dtmf_count;
// lists are append-only
GQueue dtmf_recv;
GQueue dtmf_send;
@ -508,7 +509,7 @@ struct call_monologue {
// DTMF blocking/replacement stuff:
enum block_dtmf_mode block_dtmf;
unsigned int tone_freq;
GArray *tone_freqs;
unsigned int tone_vol;
char dtmf_digit;
str dtmf_trigger;

@ -86,7 +86,7 @@ struct sdp_ng_flags {
enum endpoint_learning el_option;
enum block_dtmf_mode block_dtmf_mode;
int delay_buffer;
int frequency;
GArray *frequencies;
int volume;
char digit;
str trigger;

@ -21,6 +21,7 @@ struct dtmf_event {
int volume;
uint64_t ts;
int rand_code; // state for random replace mode
unsigned int index; // running counter of events
enum block_dtmf_mode block_dtmf; // block mode at the time of the event
};

@ -3255,5 +3255,306 @@ SDP
($sock_a, $sock_b) = new_call([qw(198.51.100.1 2020)], [qw(198.51.100.1 3020)]);
($port_a) = offer('PCM DTMF block', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 2020 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('PCM DTMF block', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 3020 RTP/AVP 0
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
$seq = 0;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# control
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xff\xb0\xac\xbc\x4c\x39\x3f\x63\xee\x55\x4a\xf6\xba\xaf\xbc\x45\x2c\x2d\x4b\xba\xaf\xbb\x6e\x48\x53\xf3\x5f\x3f\x3a\x52\xba\xac\xb3\x5e\x2f\x2d\x3e\xc8\xb8\xc0\xe8\x6b\xd7\xcc\x66\x39\x30\x3f\xbf\xac\xae\xd2\x37\x2f\x3c\xe1\xc6\xd2\x77\xdd\xbf\xbb\xdc\x38\x2c\x35\xd1\xae\xad\xc2\x43\x37\x40\x6e\xe7\x58\x4e\xdd\xb8\xb1\xc3\x3d\x2b\x2f\x5e\xb5\xaf\xbe\x59\x44\x51\xfb\x5b\x3f\x3d\x6b\xb6\xac\xb8\x4a\x2d\x2d\x47\xbf\xb6\xc1\xfa\x63\xda\xd1\x57\x37\x32\x49\xba\xab\xb0\xfe\x33\x2f\x40\xd2\xc2\xd1\x7e\xda\xbf\xbe\x73\x35\x2d\x3a\xc4\xac\xae\xcd\x3d\x36\x43\xf6\xdf\x5c\x55\xd2\xb7\xb4\xce\x37\x2b\x32\xdf\xb1\xaf\xc3\x4d\x41\x50\x7e\x59\x40"));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xff\xb0\xac\xbc\x4c\x39\x3f\x63\xee\x55\x4a\xf6\xba\xaf\xbc\x45\x2c\x2d\x4b\xba\xaf\xbb\x6e\x48\x53\xf3\x5f\x3f\x3a\x52\xba\xac\xb3\x5e\x2f\x2d\x3e\xc8\xb8\xc0\xe8\x6b\xd7\xcc\x66\x39\x30\x3f\xbf\xac\xae\xd2\x37\x2f\x3c\xe1\xc6\xd2\x77\xdd\xbf\xbb\xdc\x38\x2c\x35\xd1\xae\xad\xc2\x43\x37\x40\x6e\xe7\x58\x4e\xdd\xb8\xb1\xc3\x3d\x2b\x2f\x5e\xb5\xaf\xbe\x59\x44\x51\xfb\x5b\x3f\x3d\x6b\xb6\xac\xb8\x4a\x2d\x2d\x47\xbf\xb6\xc1\xfa\x63\xda\xd1\x57\x37\x32\x49\xba\xab\xb0\xfe\x33\x2f\x40\xd2\xc2\xd1\x7e\xda\xbf\xbe\x73\x35\x2d\x3a\xc4\xac\xae\xcd\x3d\x36\x43\xf6\xdf\x5c\x55\xd2\xb7\xb4\xce\x37\x2b\x32\xdf\xb1\xaf\xc3\x4d\x41\x50\x7e\x59\x40"));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x40\xe0\xb3\xad\xbd\x3f\x2c\x2f\x54\xbb\xb5\xc4\x6b\x5d\xde\xd9\x4e\x37\x35\x58\xb5\xab\xb4\x52\x2f\x2f\x47\xca\xbf\xd0\xfe\xd8\xc1\xc3\x57\x32\x2e\x40\xbc\xab\xb0\xe0\x39\x35\x46\xe3\xdb\x61\x5d\xcc\xb7\xb7\xe8\x33\x2b\x37\xcb\xae\xb0\xcb\x46\x3f\x50\x7e\x58\x41\x46\xcf\xb1\xae\xc6\x39\x2b\x31\x7d\xb7\xb5\xc8\x5d\x58\xe5\xe1\x4a\x37\x38\xf2\xb1\xab\xba\x44\x2e\x30\x4f\xc3\xbe\xd1\x7d\xd8\xc3\xc9\x4b\x30\x2f\x4c\xb6\xab\xb3\x61\x35\x35\x4b\xd8\xd6\x68\x68\xc8\xb7\xba\x5d\x30\x2c\x3c\xbf\xad\xb1\xd8\x40\x3e\x52\xfb\x58\x44\x4c\xc8\xb0\xb0\xd6\x34\x2b\x35\xd5\xb3\xb5\xcd\x54\x54\xec\xef\x47\x37\x3c\xd3\xaf\xac\xc0\x3c\x2d\x33\x63\xbe"));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x40\xe0\xb3\xad\xbd\x3f\x2c\x2f\x54\xbb\xb5\xc4\x6b\x5d\xde\xd9\x4e\x37\x35\x58\xb5\xab\xb4\x52\x2f\x2f\x47\xca\xbf\xd0\xfe\xd8\xc1\xc3\x57\x32\x2e\x40\xbc\xab\xb0\xe0\x39\x35\x46\xe3\xdb\x61\x5d\xcc\xb7\xb7\xe8\x33\x2b\x37\xcb\xae\xb0\xcb\x46\x3f\x50\x7e\x58\x41\x46\xcf\xb1\xae\xc6\x39\x2b\x31\x7d\xb7\xb5\xc8\x5d\x58\xe5\xe1\x4a\x37\x38\xf2\xb1\xab\xba\x44\x2e\x30\x4f\xc3\xbe\xd1\x7d\xd8\xc3\xc9\x4b\x30\x2f\x4c\xb6\xab\xb3\x61\x35\x35\x4b\xd8\xd6\x68\x68\xc8\xb7\xba\x5d\x30\x2c\x3c\xbf\xad\xb1\xd8\x40\x3e\x52\xfb\x58\x44\x4c\xc8\xb0\xb0\xd6\x34\x2b\x35\xd5\xb3\xb5\xcd\x54\x54\xec\xef\x47\x37\x3c\xd3\xaf\xac\xc0\x3c\x2d\x33\x63\xbe"));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xbd\xd3\x77\xd9\xc5\xd0\x44\x30\x32\x65\xb2\xab\xb8\x4c\x32\x35\x50\xcf\xd2\x70\x7a\xc6\xb8\xbe\x4c\x2e\x2d\x45\xb9\xac\xb4\xfd\x3c\x3d\x55\xf2\x5a\x47\x56\xc1\xb0\xb4\x71\x30\x2b\x3a\xc7\xb0\xb6\xd7\x4d\x50\xf6\x78\x45\x38\x41\xc7\xae\xae\xcc\x37\x2c\x36\xe5\xbb\xbd\xd7\x6d\xdb\xc9\xdd\x3f\x30\x36\xdc\xae\xab\xbd\x41\x2f\x37\x5d\xcb\xcf\x7b\xef\xc4\xb9\xc6\x42\x2d\x2e\x55\xb4\xac\xb8\x58\x39\x3d\x59\xea\x5c\x4a\x66\xbd\xb0\xb8\x50\x2e\x2c\x40\xbd\xaf\xb8\xe8\x48\x4e\x7d\x6b\x43\x3a\x4a\xbf\xad\xaf\xe4\x32\x2c\x3a\xcf\xb8\xbd\xdc\x66\xde\xcc\xf5\x3c\x30\x3b\xca\xad\xac\xc6\x3b\x2e\x39\x7c\xc6\xcd\xfa\xe7\xc3\xbb\xce\x3c\x2d\x31\xf2"));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xbd\xd3\x77\xd9\xc5\xd0\x44\x30\x32\x65\xb2\xab\xb8\x4c\x32\x35\x50\xcf\xd2\x70\x7a\xc6\xb8\xbe\x4c\x2e\x2d\x45\xb9\xac\xb4\xfd\x3c\x3d\x55\xf2\x5a\x47\x56\xc1\xb0\xb4\x71\x30\x2b\x3a\xc7\xb0\xb6\xd7\x4d\x50\xf6\x78\x45\x38\x41\xc7\xae\xae\xcc\x37\x2c\x36\xe5\xbb\xbd\xd7\x6d\xdb\xc9\xdd\x3f\x30\x36\xdc\xae\xab\xbd\x41\x2f\x37\x5d\xcb\xcf\x7b\xef\xc4\xb9\xc6\x42\x2d\x2e\x55\xb4\xac\xb8\x58\x39\x3d\x59\xea\x5c\x4a\x66\xbd\xb0\xb8\x50\x2e\x2c\x40\xbd\xaf\xb8\xe8\x48\x4e\x7d\x6b\x43\x3a\x4a\xbf\xad\xaf\xe4\x32\x2c\x3a\xcf\xb8\xbd\xdc\x66\xde\xcc\xf5\x3c\x30\x3b\xca\xad\xac\xc6\x3b\x2e\x39\x7c\xc6\xcd\xfa\xe7\xc3\xbb\xce\x3c\x2d\x31\xf2"));
Time::HiRes::usleep(18000); $seq++;
# gap
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# enable blocking
rtpe_req('block DTMF', 'PCM DTMF block',
{ 'from-tag' => ft(), 'DTMF-security' => 'tone', 'delay-buffer' => 1, frequencies => [250,350,450] });
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xff\xb0\xac\xbc\x4c\x39\x3f\x63\xee\x55\x4a\xf6\xba\xaf\xbc\x45\x2c\x2d\x4b\xba\xaf\xbb\x6e\x48\x53\xf3\x5f\x3f\x3a\x52\xba\xac\xb3\x5e\x2f\x2d\x3e\xc8\xb8\xc0\xe8\x6b\xd7\xcc\x66\x39\x30\x3f\xbf\xac\xae\xd2\x37\x2f\x3c\xe1\xc6\xd2\x77\xdd\xbf\xbb\xdc\x38\x2c\x35\xd1\xae\xad\xc2\x43\x37\x40\x6e\xe7\x58\x4e\xdd\xb8\xb1\xc3\x3d\x2b\x2f\x5e\xb5\xaf\xbe\x59\x44\x51\xfb\x5b\x3f\x3d\x6b\xb6\xac\xb8\x4a\x2d\x2d\x47\xbf\xb6\xc1\xfa\x63\xda\xd1\x57\x37\x32\x49\xba\xab\xb0\xfe\x33\x2f\x40\xd2\xc2\xd1\x7e\xda\xbf\xbe\x73\x35\x2d\x3a\xc4\xac\xae\xcd\x3d\x36\x43\xf6\xdf\x5c\x55\xd2\xb7\xb4\xce\x37\x2b\x32\xdf\xb1\xaf\xc3\x4d\x41\x50\x7e\x59\x40"));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xff\xb0\xac\xbc\x4c\x39\x3f\x63\xee\x55\x4a\xf6\xba\xaf\xbc\x45\x2c\x2d\x4b\xba\xaf\xbb\x6e\x48\x53\xf3\x5f\x3f\x3a\x52\xba\xac\xb3\x5e\x2f\x2d\x3e\xc8\xb8\xc0\xe8\x6b\xd7\xcc\x66\x39\x30\x3f\xbf\xac\xae\xd2\x37\x2f\x3c\xe1\xc6\xd2\x77\xdd\xbf\xbb\xdc\x38\x2c\x35\xd1\xae\xad\xc2\x43\x37\x40\x6e\xe7\x58\x4e\xdd\xb8\xb1\xc3\x3d\x2b\x2f\x5e\xb5\xaf\xbe\x59\x44\x51\xfb\x5b\x3f\x3d\x6b\xb6\xac\xb8\x4a\x2d\x2d\x47\xbf\xb6\xc1\xfa\x63\xda\xd1\x57\x37\x32\x49\xba\xab\xb0\xfe\x33\x2f\x40\xd2\xc2\xd1\x7e\xda\xbf\xbe\x73\x35\x2d\x3a\xc4\xac\xae\xcd\x3d\x36\x43\xf6\xdf\x5c\x55\xd2\xb7\xb4\xce\x37\x2b\x32\xdf\xb1\xaf\xc3\x4d\x41\x50\x7e\x59\x40"));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x40\xe0\xb3\xad\xbd\x3f\x2c\x2f\x54\xbb\xb5\xc4\x6b\x5d\xde\xd9\x4e\x37\x35\x58\xb5\xab\xb4\x52\x2f\x2f\x47\xca\xbf\xd0\xfe\xd8\xc1\xc3\x57\x32\x2e\x40\xbc\xab\xb0\xe0\x39\x35\x46\xe3\xdb\x61\x5d\xcc\xb7\xb7\xe8\x33\x2b\x37\xcb\xae\xb0\xcb\x46\x3f\x50\x7e\x58\x41\x46\xcf\xb1\xae\xc6\x39\x2b\x31\x7d\xb7\xb5\xc8\x5d\x58\xe5\xe1\x4a\x37\x38\xf2\xb1\xab\xba\x44\x2e\x30\x4f\xc3\xbe\xd1\x7d\xd8\xc3\xc9\x4b\x30\x2f\x4c\xb6\xab\xb3\x61\x35\x35\x4b\xd8\xd6\x68\x68\xc8\xb7\xba\x5d\x30\x2c\x3c\xbf\xad\xb1\xd8\x40\x3e\x52\xfb\x58\x44\x4c\xc8\xb0\xb0\xd6\x34\x2b\x35\xd5\xb3\xb5\xcd\x54\x54\xec\xef\x47\x37\x3c\xd3\xaf\xac\xc0\x3c\x2d\x33\x63\xbe"));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x40\xe0\xb3\xad\xbd\x3f\x2c\x2f\x54\xbb\xb5\xc4\x6b\x5d\xde\xd9\x4e\x37\x35\x58\xb5\xab\xb4\x52\x2f\x2f\x47\xca\xbf\xd0\xfe\xd8\xc1\xc3\x57\x32\x2e\x40\xbc\xab\xb0\xe0\x39\x35\x46\xe3\xdb\x61\x5d\xcc\xb7\xb7\xe8\x33\x2b\x37\xcb\xae\xb0\xcb\x46\x3f\x50\x7e\x58\x41\x46\xcf\xb1\xae\xc6\x39\x2b\x31\x7d\xb7\xb5\xc8\x5d\x58\xe5\xe1\x4a\x37\x38\xf2\xb1\xab\xba\x44\x2e\x30\x4f\xc3\xbe\xd1\x7d\xd8\xc3\xc9\x4b\x30\x2f\x4c\xb6\xab\xb3\x61\x35\x35\x4b\xd8\xd6\x68\x68\xc8\xb7\xba\x5d\x30\x2c\x3c\xbf\xad\xb1\xd8\x40\x3e\x52\xfb\x58\x44\x4c\xc8\xb0\xb0\xd6\x34\x2b\x35\xd5\xb3\xb5\xcd\x54\x54\xec\xef\x47\x37\x3c\xd3\xaf\xac\xc0\x3c\x2d\x33\x63\xbe"));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xbd\xd3\x77\xd9\xc5\xd0\x44\x30\x32\x65\xb2\xab\xb8\x4c\x32\x35\x50\xcf\xd2\x70\x7a\xc6\xb8\xbe\x4c\x2e\x2d\x45\xb9\xac\xb4\xfd\x3c\x3d\x55\xf2\x5a\x47\x56\xc1\xb0\xb4\x71\x30\x2b\x3a\xc7\xb0\xb6\xd7\x4d\x50\xf6\x78\x45\x38\x41\xc7\xae\xae\xcc\x37\x2c\x36\xe5\xbb\xbd\xd7\x6d\xdb\xc9\xdd\x3f\x30\x36\xdc\xae\xab\xbd\x41\x2f\x37\x5d\xcb\xcf\x7b\xef\xc4\xb9\xc6\x42\x2d\x2e\x55\xb4\xac\xb8\x58\x39\x3d\x59\xea\x5c\x4a\x66\xbd\xb0\xb8\x50\x2e\x2c\x40\xbd\xaf\xb8\xe8\x48\x4e\x7d\x6b\x43\x3a\x4a\xbf\xad\xaf\xe4\x32\x2c\x3a\xcf\xb8\xbd\xdc\x66\xde\xcc\xf5\x3c\x30\x3b\xca\xad\xac\xc6\x3b\x2e\x39\x7c\xc6\xcd\xfa\xe7\xc3\xbb\xce\x3c\x2d\x31\xf2"));
# replaced by tone
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b"));
Time::HiRes::usleep(18000); $seq++;
# gap
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
# still tone
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b\x1b\x1b\x1d\x1e\x22\x28\x30\x3f\xff\xbf\xb0\xa8\xa2\x9e\x9d\x9b\x9b\x9b\x9d\x9e\xa2\xa8\xb0\xbf\xff\x3f\x30\x28\x22\x1e\x1d\x1b"));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# disable blocking
rtpe_req('unblock DTMF', 'PCM DTMF block',
{ 'from-tag' => ft() });
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# enable blocking
rtpe_req('block DTMF', 'PCM DTMF block',
{ 'from-tag' => ft(), 'DTMF-security' => 'tone', 'delay-buffer' => 100, frequencies => [250,350,450] });
# pre-send 100 ms worth of audio
$rseq = $seq;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# start receiving
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
# start DTMF, interleaved with receiving older audio
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xff\xb0\xac\xbc\x4c\x39\x3f\x63\xee\x55\x4a\xf6\xba\xaf\xbc\x45\x2c\x2d\x4b\xba\xaf\xbb\x6e\x48\x53\xf3\x5f\x3f\x3a\x52\xba\xac\xb3\x5e\x2f\x2d\x3e\xc8\xb8\xc0\xe8\x6b\xd7\xcc\x66\x39\x30\x3f\xbf\xac\xae\xd2\x37\x2f\x3c\xe1\xc6\xd2\x77\xdd\xbf\xbb\xdc\x38\x2c\x35\xd1\xae\xad\xc2\x43\x37\x40\x6e\xe7\x58\x4e\xdd\xb8\xb1\xc3\x3d\x2b\x2f\x5e\xb5\xaf\xbe\x59\x44\x51\xfb\x5b\x3f\x3d\x6b\xb6\xac\xb8\x4a\x2d\x2d\x47\xbf\xb6\xc1\xfa\x63\xda\xd1\x57\x37\x32\x49\xba\xab\xb0\xfe\x33\x2f\x40\xd2\xc2\xd1\x7e\xda\xbf\xbe\x73\x35\x2d\x3a\xc4\xac\xae\xcd\x3d\x36\x43\xf6\xdf\x5c\x55\xd2\xb7\xb4\xce\x37\x2b\x32\xdf\xb1\xaf\xc3\x4d\x41\x50\x7e\x59\x40"));
Time::HiRes::usleep(18000); $seq++;
# still buffered silence
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x40\xe0\xb3\xad\xbd\x3f\x2c\x2f\x54\xbb\xb5\xc4\x6b\x5d\xde\xd9\x4e\x37\x35\x58\xb5\xab\xb4\x52\x2f\x2f\x47\xca\xbf\xd0\xfe\xd8\xc1\xc3\x57\x32\x2e\x40\xbc\xab\xb0\xe0\x39\x35\x46\xe3\xdb\x61\x5d\xcc\xb7\xb7\xe8\x33\x2b\x37\xcb\xae\xb0\xcb\x46\x3f\x50\x7e\x58\x41\x46\xcf\xb1\xae\xc6\x39\x2b\x31\x7d\xb7\xb5\xc8\x5d\x58\xe5\xe1\x4a\x37\x38\xf2\xb1\xab\xba\x44\x2e\x30\x4f\xc3\xbe\xd1\x7d\xd8\xc3\xc9\x4b\x30\x2f\x4c\xb6\xab\xb3\x61\x35\x35\x4b\xd8\xd6\x68\x68\xc8\xb7\xba\x5d\x30\x2c\x3c\xbf\xad\xb1\xd8\x40\x3e\x52\xfb\x58\x44\x4c\xc8\xb0\xb0\xd6\x34\x2b\x35\xd5\xb3\xb5\xcd\x54\x54\xec\xef\x47\x37\x3c\xd3\xaf\xac\xc0\x3c\x2d\x33\x63\xbe"));
Time::HiRes::usleep(18000); $seq++;
# now replaced by tone
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\xbd\xd3\x77\xd9\xc5\xd0\x44\x30\x32\x65\xb2\xab\xb8\x4c\x32\x35\x50\xcf\xd2\x70\x7a\xc6\xb8\xbe\x4c\x2e\x2d\x45\xb9\xac\xb4\xfd\x3c\x3d\x55\xf2\x5a\x47\x56\xc1\xb0\xb4\x71\x30\x2b\x3a\xc7\xb0\xb6\xd7\x4d\x50\xf6\x78\x45\x38\x41\xc7\xae\xae\xcc\x37\x2c\x36\xe5\xbb\xbd\xd7\x6d\xdb\xc9\xdd\x3f\x30\x36\xdc\xae\xab\xbd\x41\x2f\x37\x5d\xcb\xcf\x7b\xef\xc4\xb9\xc6\x42\x2d\x2e\x55\xb4\xac\xb8\x58\x39\x3d\x59\xea\x5c\x4a\x66\xbd\xb0\xb8\x50\x2e\x2c\x40\xbd\xaf\xb8\xe8\x48\x4e\x7d\x6b\x43\x3a\x4a\xbf\xad\xaf\xe4\x32\x2c\x3a\xcf\xb8\xbd\xdc\x66\xde\xcc\xf5\x3c\x30\x3b\xca\xad\xac\xc6\x3b\x2e\x39\x7c\xc6\xcd\xfa\xe7\xc3\xbb\xce\x3c\x2d\x31\xf2"));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
# back to silence
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# still tone
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x9b\x9c\x9e\xa4\xad\xbf\x52\x32\x27\x1f\x1d\x1b\x1b\x1d\x20\x28\x35\x5f\xbc\xab\xa2\x9e\x9c\x9b\x9c\x9e\xa5\xae\xc4\x4a\x30\x26\x1f\x1c\x1b\x1b\x1d\x21\x2a\x38\xff\xb8\xaa\xa1\x9d\x9b\x9b\x9c\x9f\xa6\xb0\xca\x44\x2e\x25\x1e\x1c\x1b\x1c\x1e\x22\x2b\x3c\xdf\xb5\xa8\xa0\x9d\x9b\x9b\x9d\x9f\xa7\xb2\xd2\x3f\x2d\x23\x1e\x1c\x1b\x1c\x1e\x23\x2d\x3f\xd2\xb2\xa7\x9f\x9d\x9b\x9b\x9d\xa0\xa8\xb5\xdf\x3c\x2b\x22\x1e\x1c\x1b\x1c\x1e\x25\x2e\x44\xca\xb0\xa6\x9f\x9c\x9b\x9b\x9d\xa1\xaa\xb8\xff\x38\x2a\x21\x1d\x1b\x1b\x1c\x1f\x26\x30\x4a\xc4\xae\xa5\x9e\x9c\x9b\x9c\x9e\xa2\xab\xbc\x5f\x35\x28\x20\x1d\x1b\x1b\x1d\x1f\x27\x32\x52\xbf\xad\xa4\x9e\x9c"));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
# finally back to silence
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
# disable blocking
rtpe_req('unblock DTMF', 'PCM DTMF block',
{ 'from-tag' => ft(), 'delay-buffer' => 0 });
# buffer flushing
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
rcv($sock_b, $port_a, rtpm(0, 1000 + $rseq, 3000 + 160 * $rseq, 0x1234, "\x00" x 160));
$rseq++;
# sync forwarding
snd($sock_a, $port_b, rtp(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000 + $seq, 3000 + 160 * $seq, 0x1234, "\x00" x 160));
Time::HiRes::usleep(18000); $seq++;
done_testing();
#done_testing;NGCP::Rtpengine::AutoTest::terminate('f00');exit;

@ -111,7 +111,8 @@ GetOptions(
'DTMF-security-trigger=s' => \$options{'DTMF-security-trigger'},
'DTMF-security-trigger-end=s' => \$options{'DTMF-security-trigger-end'},
'delay-buffer=i' => \$options{'delay-buffer'},
'frequency=i' => \$options{'frequency'},
'frequency=s' => \$options{'frequency'},
'frequencies=i@' => \$options{'frequencies'},
'volume=i' => \$options{'volume'},
'digit=s' => \$options{'digit'},
'trigger=s' => \$options{'trigger'},
@ -125,7 +126,7 @@ my $cmd = shift(@ARGV) or die;
my %packet = (command => $cmd);
for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code,DTLS-fingerprint,ICE-lite,media echo,label,set-label,from-label,to-label,DTMF-security,digit,DTMF-security-trigger,DTMF-security-trigger-end,trigger,trigger-end,all')) {
for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code,DTLS-fingerprint,ICE-lite,media echo,label,set-label,from-label,to-label,DTMF-security,digit,DTMF-security-trigger,DTMF-security-trigger-end,trigger,trigger-end,all,frequency')) {
if (defined($options{$x})) {
if (!$options{json}) {
$packet{$x} = \$options{$x};
@ -135,7 +136,7 @@ for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,
}
}
}
for my $x (split(/,/, 'TOS,delete-delay,delay-buffer,volume,frequency,trigger-end-time,trigger-end-digits,DTMF-delay')) {
for my $x (split(/,/, 'TOS,delete-delay,delay-buffer,volume,trigger-end-time,trigger-end-digits,DTMF-delay')) {
defined($options{$x}) and $packet{$x} = $options{$x};
}
for my $x (split(/,/, 'trust address,symmetric,asymmetric,unidirectional,force,strict source,media handover,sip source address,reset,port latching,no rtcp attribute,full rtcp attribute,loop protect,record call,always transcode,SIPREC,pad crypto,generate mid,fragment,original sendrecv,symmetric codecs,asymmetric codecs,inject DTMF,detect DTMF,generate RTCP,single codec,no codec renegotiation,pierce NAT,SIP-source-address,allow transcoding,trickle ICE,reject ICE,egress')) {
@ -144,7 +145,7 @@ for my $x (split(/,/, 'trust address,symmetric,asymmetric,unidirectional,force,s
for my $x (split(/,/, 'origin,session connection,sdp version,username,session-name,zero-address')) {
defined($options{'replace-' . $x}) and push(@{$packet{replace}}, $x);
}
for my $x (split(/,/, 'rtcp-mux,SDES,supports,T.38,OSRTP,received-from,from-tags')) {
for my $x (split(/,/, 'rtcp-mux,SDES,supports,T.38,OSRTP,received-from,from-tags,frequencies')) {
$packet{$x} = $options{$x}
if defined($options{$x}) && ref($options{$x}) eq 'ARRAY';
}

Loading…
Cancel
Save