TT#65052 support queuing up multiple DTMF events

Change-Id: I489194212a46d12761b3fdc1e212c78254b91427
changes/65/33765/3
Richard Fuchs 6 years ago
parent 068bdb224f
commit 3bf3982de1

@ -1521,12 +1521,14 @@ is the one generating the DTMF event, not the one receiving it.
The dictionary key `code` must be present in the message, indicating the DTMF event to be generated. It can
be either an integer with values 0-15, or a string containing a single character
(`0` - `9`, `*`, `#`, `A` - `D`). Additional optional dictionary keys are: `duration` indicating the duration
of the event in milliseconds (defaults to 250 ms, with a minimum of 100 and a maximum of 5000); and
of the event in milliseconds (defaults to 250 ms, with a minimum of 100 and a maximum of 5000);
`volume` indicating the volume in absolute decibels (defaults to -8 dB, with 0 being the maximum volume and
positive integers being interpreted as negative).
positive integers being interpreted as negative); and `pause` indicating the pause in between consecutive
DTMF events in milliseconds (defaults to 100 ms, with a minimum of 100 and a maximum of 5000).
This message can be used to implement `application/dtmf-relay` or `application/dtmf` payloads carried
in SIP INFO messages.
in SIP INFO messages. Multiple DTMF events can be queued up by issuing multiple consecutive
`play DTMF` messages.
If the destination participant supports the `telephone-event` RTP payload type, then it will be used to
send the DTMF event. Otherwise a PCM DTMF tone will be inserted into the audio stream. Audio samples

@ -1299,6 +1299,13 @@ void codec_add_dtmf_event(struct codec_ssrc_handler *ch, int code, int level, ui
g_queue_push_tail(&ch->dtmf_events, ev);
}
uint64_t codec_last_dtmf_event(struct codec_ssrc_handler *ch) {
struct dtmf_event *ev = g_queue_peek_tail(&ch->dtmf_events);
if (!ev)
return 0;
return ev->ts;
}
uint64_t codec_encoder_pts(struct codec_ssrc_handler *ch) {
return ch->encoder->fifo_pts;
}
@ -1308,6 +1315,13 @@ void codec_decoder_skip_pts(struct codec_ssrc_handler *ch, uint64_t pts) {
ch->skip_pts += pts;
}
uint64_t codec_decoder_unskip_pts(struct codec_ssrc_handler *ch) {
uint64_t prev = ch->skip_pts;
ilog(LOG_DEBUG, "Un-skipping next %" PRIu64 " samples", prev);
ch->skip_pts = 0;
return prev;
}
static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
struct codec_handler *h = p;

@ -217,6 +217,7 @@ static const char *dtmf_inject_pcm(struct call_media *media, struct call_monolog
// keep track of how much PCM we've generated
uint64_t encoder_pts = codec_encoder_pts(csh);
uint64_t skip_pts = codec_decoder_unskip_pts(csh); // reset to zero to take up our new samples
media->dtmf_injector->func(media->dtmf_injector, &packet);
@ -229,7 +230,8 @@ static const char *dtmf_inject_pcm(struct call_media *media, struct call_monolog
// skip generated samples
uint64_t pts_offset = codec_encoder_pts(csh) - encoder_pts;
codec_decoder_skip_pts(csh, av_rescale(pts_offset, ch->dest_pt.clock_rate, ch->source_pt.clock_rate));
skip_pts += av_rescale(pts_offset, ch->dest_pt.clock_rate, ch->source_pt.clock_rate);
codec_decoder_skip_pts(csh, skip_pts);
// ready packets for send
// XXX handle encryption?
@ -281,8 +283,14 @@ const char *dtmf_inject(struct call_media *media, int code, int volume, int dura
// synthesise start and stop events
uint64_t num_samples = duration * ch->dest_pt.clock_rate / 1000;
codec_add_dtmf_event(csh, dtmf_code_to_char(code), volume, codec_encoder_pts(csh));
codec_add_dtmf_event(csh, 0, 0, codec_encoder_pts(csh) + num_samples);
uint64_t start_pts = codec_encoder_pts(csh);
uint64_t last_end_pts = codec_last_dtmf_event(csh);
if (last_end_pts) {
// shift this new event past the end of the last event plus a pause
start_pts = last_end_pts + pause * ch->dest_pt.clock_rate / 1000;
}
codec_add_dtmf_event(csh, dtmf_code_to_char(code), volume, start_pts);
codec_add_dtmf_event(csh, 0, 0, start_pts + num_samples);
obj_put_o((struct obj *) csh);
return NULL;

@ -75,8 +75,10 @@ void __rtp_payload_type_add_send(struct call_media *other_media, struct rtp_payl
void codec_handlers_update(struct call_media *receiver, struct call_media *sink, const struct sdp_ng_flags *);
void codec_add_dtmf_event(struct codec_ssrc_handler *ch, int code, int level, uint64_t ts);
uint64_t codec_last_dtmf_event(struct codec_ssrc_handler *ch);
uint64_t codec_encoder_pts(struct codec_ssrc_handler *ch);
void codec_decoder_skip_pts(struct codec_ssrc_handler *ch, uint64_t);
uint64_t codec_decoder_unskip_pts(struct codec_ssrc_handler *ch);
#else

@ -809,6 +809,219 @@ rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x00" x 80));
# multiple consecutive DTMF events
($sock_a, $sock_b) = new_call([qw(198.51.100.1 6024)], [qw(198.51.100.3 6026)]);
($port_a) = offer('multiple consecutive DTMF events',
{ ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 6024 RTP/AVP 0 8
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0 8
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('multiple consecutive DTMF events',
{ ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 6026 RTP/AVP 0 8
c=IN IP4 198.51.100.3
a=sendrecv
--------------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0 8
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160));
($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 160));
snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1001, 3160, $ssrc, "\x00" x 160));
$resp = rtpe_req('play DTMF', 'inject DTMF towards B',
{ 'from-tag' => $ft, code => 'C', volume => 5, duration => 100 });
$resp = rtpe_req('play DTMF', 'inject DTMF towards B',
{ 'from-tag' => $ft, code => '4', volume => 5, duration => 100 });
snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1002, 3320, $ssrc, "\xff\x93\x94\xbc\x2e\x56\xbf\x2b\x13\x1b\xa7\x8e\x98\x47\x25\x41\xe2\x24\x16\x2b\x99\x8e\x9f\x28\x1e\x3d\x5b\x23\x1c\xdf\x92\x8f\xb6\x1c\x1c\x40\x5d\x26\x25\xaa\x8f\x95\x3b\x15\x1d\x5e\xde\x2c\x38\x9d\x8f\x9e\x1f\x11\x20\xc0\xc1\x37\xdd\x99\x92\xb7\x15\x10\x2c\xac\xb5\x49\xb8\x97\x99\x37\x0f\x13\x58\xa0\xae\x67\xae\x99\xa4\x1f\x0d\x1a\xae\x9b\xad\x7b\xad\x9d\xbf\x16\x0e\x27\x9d\x98\xb0\x55\xb1\xa6\x3a\x11\x11\x63\x95\x98\xbf\x3e\xbb\xb4\x26\x10\x1a\xa9\x90\x9a\x4e\x30\xce\xd4\x1e\x12\x29\x99\x8e\xa1\x2d\x29\x6d\x4b\x1c\x18\xef\x91\x8f\xb6\x1f\x24\x57\x3e\x1d\x20\xa9\x8e\x95\x3e\x19\x23\x67\x3e\x21\x31\x9c\x8e\x9e\x22\x14\x26\xcd\x4a"));
snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1003, 3480, $ssrc, "\x2a\xdf\x96\x90\xb5\x17\x13\x2f\xb6\xf5\x36\xb1\x93\x96\x39\x10\x15\x55\xaa\xc8\x4c\xa7\x95\xa0\x1f\x0e\x1b\xb4\xa1\xbd\xed\xa4\x99\xbb\x15\x0e\x27\xa0\x9d\xbd\xda\xa4\x9f\x39\x10\x11\x58\x98\x9c\xc8\xf9\xa9\xac\x23\x0e\x19\xab\x92\x9e\x59\x4c\xb0\xca\x1b\x10\x27\x9a\x90\xa5\x35\x3a\xbe\x43\x18\x15\x6c\x92\x91\xb7\x26\x30\xd6\x32\x18\x1d\xa9\x8e\x96\x44\x1d\x2d\xfc\x2e\x1b\x2d\x9a\x8d\x9e\x25\x19\x2d\xe7\x2f\x20\xea\x94\x8f\xb3\x19\x17\x36\xc8\x36\x2c\xae\x90\x95\x3b\x12\x18\x55\xb7\x43\x3e\xa1\x91\x9e\x1f\x0f\x1d\xba\xac\x64\xe8\x9d\x95\xb7\x15\x0e\x29\xa6\xa6\xda\xc3\x9d\x9b\x39\x0f\x11\x51\x9c\xa2\xd8\xbe\x9f\xa7\x21\x0e\x18\xad"));
snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1004, 3640, $ssrc, "\x96\xa3\x68\xc4\xa5\xc2\x19\x0e\x26\x9c\x93\xa9\x3f\xdb\xae\x3e\x14\x12\x5b\x93\x93\xb9\x2e\x51\xbe\x2c\x14\x1b\xa9\x8f\x97\x4c\x25\x3f\xde\x25\x16\x2a\x9a\x8e\x9e\x29\x1e\x3b\x5e\x24\x1b\x7b\x92\x8f\xb2\x1c\x1c\x3e\x61\x27\x25\xac\x8f\x94\x3e\x15\x1c\x59\xdb\x2d\x37\x9e\x8f\x9d\x20\x11\x1f\xc2\xbf\x38\xea\x99\x92\xb4\x16\x10\x2b\xad\xb4\x49\xba\x98\x98\x3a\x0f\x12\x4e\xa1\xad\x68\xaf\x99\xa3\x20\x0d\x19\xb0\x9b\xac\x7b\xae\x9d\xbc\x17\x0e\x25\x9e\x98\xaf\x55\xb2\xa6\x3d\x12\x11\x52\x96\x97\xbd\x3e\xbc\xb3\x28\x10\x19\xab\x90\x9a\x54\x2f\xd0\xcf\x1f\x12\x27\x9a\x8e\xa0\x2e\x28\x66\x4e\x1d\x18\x62\x92\x8f\xb2\x20\x23\x53\x3f\x1d\x1f"));
snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1005, 3800, $ssrc, "\xab\x8e\x94\x44\x19\x22\x61\x40\x21\x2f\x9c\x8e\x9d\x23\x14\x25\xce\x4d\x2a\xf7\x96\x8f\xb1\x18\x13\x2e\xb7\xe8\x36\xb3\x94\x96\x3c\x10\x15\x4d\xaa\xc5\x4b\xa8\x95\x9f\x20\x0e\x1a\xb6\xa0\xbc\xf5\xa4\x99\xb8\x16\x0e\x26\xa1\x9d\xbb\xdd\xa5\x9f\x3c\x10\x10\x4c\x99\x9b\xc5\x78\xaa\xac\x24\x0f\x18\xac\x93\x9d\x5f\x4a\xb1\xc7\x1c\x0f\x25\x9b\x90\xa3\x36\x39\xbf\x47\x18\x14\x56\x92\x90\xb4\x27\x2f\xd7\x34\x18\x1c\xab\x8e\x95\x4b\x1d\x2c\xfe\x2f\x1b\x2c\x9b\x8d\x9d\x27\x19\x2c\xe7\x30\x20\x6d\x94\x8f\xaf\x1a\x17\x34\xc8\x37\x2b\xaf\x91\x94\x3f\x12\x18\x4e\xb6\x45\x3d\xa3\x91\x9e\x20\x0f\x1c\xbc\xab\x6c\xf5\x9e\x95\xb3\x16\x0e\x27\xa7\xa5"));
snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1006, 3960, $ssrc, "\xd6\xc6\x9d\x9b\x3d\x0f\x11\x49\x9c\xa1\xd4\xbf\x9f\xa6\x22\x0e\x18\xaf\x96\xa2\x6e\xc6\xa5\xbe\x19\x0e\x24\x9d\x93\xa8\x40\xe1\xae\x42\x15\x12\x4e\x94\x93\xb7\x2e\x4e\xbe\x2d\x14\x1a\xab\x8f\x97\x52\x25\x3e\xdc\x26\x16\x28\x9b\x8e\x9e\x2b\x1e\x3a\x61\x25\x1b\x5d\x93\x8f\xaf\x1d\x1c\x3d\x67\x27\x24\xad\x8f\x93\x45\x15\x1c\x53\xd7\x2d\x35\x9f\x8f\x9c\x22\x11\x1f\xc5\xbe\x38\x7a\x9a\x91\xb0\x17\x10\x29\xad\xb3\x4a\xbc\x98\x98\x3e\x10\x12\x48\xa1\xad\x6a\xb1\x9a\xa1\x21\x0e\x18\xb3\x9b\xab\x7d\xaf\x9d\xb9\x18\x0e\x23\x9f\x97\xae\x55\xb4\xa5\x40\x12\x10\x49\x96\x97\xbb\x3d\xbd\xb2\x29\x10\x18\xac\x90\x99\x5d\x2f\xd4\xcd\x1f\x12\x25\x9b"));
# pause
snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1007, 4120, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1008, 4280, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1009, 4440, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1010, 4600, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1011, 4760, $ssrc, "\xff" x 160));
# next event
snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1012, 4920, $ssrc, "\xff\x96\x8e\x99\xdd\x1f\x1d\x2c\x69\xe9\x39\x2d\x50\xa3\x95\x97\xbd\x1a\x0e\x12\x38\x9d\x93\x9b\xbf\x30\x2f\x4f\xdc\x39\x20\x1d\x33\xa2\x90\x91\xaa\x1f\x0f\x12\x2c\xa9\x9c\xa3\xc2\x55\xc9\xaf\xb8\x30\x18\x14\x24\xa7\x8f\x8e\xa0\x2a\x14\x16\x2a\xbc\xac\xbc\x61\xcf\xa8\x9d\xa6\x36\x15\x0f\x1b\xb4\x92\x8f\x9d\x3e\x1d\x1e\x31\xe0\xfe\x36\x30\xd3\x9e\x94\x9b\x50\x15\x0d\x17\xe3\x99\x93\x9e\xee\x2c\x30\x5b\xf0\x32\x1f\x1f\x4c\x9c\x8f\x94\xbe\x19\x0e\x15\x3d\xa2\x9b\xa7\xd2\x52\xc3\xaf\xc4\x29\x16\x16\x2f\x9e\x8e\x90\xac\x20\x13\x18\x34\xb2\xac\xc0\x61\xc2\xa5\x9d\xad\x29\x12\x10\x23\xa5\x8f\x90\xa5\x2d\x1b\x1f\x39\xd1\x65\x34\x36\xbb\x9b"));
snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1013, 5080, $ssrc, "\x94\x9f\x2f\x11\x0e\x1c\xb3\x95\x94\xa4\x45\x2a\x33\x69\x60\x2d\x1e\x23\xc7\x98\x8f\x98\x49\x15\x0e\x1a\xda\x9d\x9c\xab\x7d\x53\xbe\xb1\xe8\x22\x15\x19\x4d\x98\x8d\x94\xc3\x1b\x12\x1b\x48\xac\xac\xc7\x69\xba\xa2\x9f\xbb\x1f\x10\x12\x2f\x9c\x8e\x93\xb0\x25\x1a\x22\x44\xcb\x57\x34\x3d\xae\x99\x96\xa9\x23\x0f\x0f\x24\xa6\x93\x96\xac\x36\x29\x37\x7c\x4e\x29\x1e\x29\xb0\x94\x8f\x9e\x2d\x11\x0f\x1f\xb6\x9b\x9d\xb0\x55\x58\xbc\xb5\x49\x1e\x15\x1d\xbe\x94\x8e\x99\x45\x17\x12\x1f\xd9\xa9\xad\xce\xfa\xb3\xa0\xa2\xef\x1b\x0f\x16\x52\x97\x8e\x96\xcb\x1e\x1a\x26\x59\xc8\x4e\x35\x4d\xa8\x97\x98\xb8\x1c\x0e\x11\x31\x9d\x91\x98\xb9\x2d\x29\x3b\xf5"));
snd($sock_a, $port_b, rtp(0, 1014, 5240, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1014, 5240, $ssrc, "\x43\x27\x1f\x32\xa6\x92\x91\xa7\x21\x0f\x10\x28\xa9\x99\x9e\xba\x49\x60\xba\xbb\x38\x1b\x16\x23\xab\x90\x8e\x9e\x2d\x14\x13\x26\xbc\xa7\xaf\xd8\xde\xae\xa0\xa7\x3d\x17\x0f\x1a\xba\x93\x8e\x9b\x44\x1b\x1b\x2b\xe0\xc8\x48\x37\xe4\xa2\x96\x9b\x6f\x17\x0e\x15\x5d\x99\x91\x9c\xd7\x29\x29\x3f\xf8\x3c\x24\x21\x46\x9e\x90\x94\xb8\x1a\x0e\x14\x37\xa1\x99\xa1\xc8\x43\x76\xba\xc5\x2d\x19\x17\x2d\xa0\x8f\x8f\xa8\x21\x11\x16\x2e\xaf\xa6\xb2\xe5\xcf\xab\xa0\xad\x2d\x14\x10\x20\xa8\x90\x8f\xa1\x2e\x19\x1c\x31\xcb\xc9\x44\x3b\xc2\x9e\x96\x9f\x36\x13\x0e\x1a\xb8\x95\x92\xa0\x48\x26\x2a\x48\x73\x36\x23\x25\xd4\x9a\x90\x98\x5c\x15\x0e\x18\x72\x9c\x99"));
snd($sock_a, $port_b, rtp(0, 1015, 5400, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1015, 5400, $ssrc, "\xa6\xe8\x3f\xe7\xba\xdd\x27\x18\x1a\x43\x9a\x8e\x93\xbb\x1b\x10\x19\x3e\xaa\xa5\xb7\xf4\xc6\xa9\xa2\xba\x23\x12\x12\x2c\x9e\x8e\x91\xac\x25\x18\x1e\x3c\xc1\xcd\x41\x40\xb5\x9c\x97\xa8\x27\x10\x0f\x21\xa8\x92\x93\xa8\x35\x24\x2c\x50\x61\x30\x23\x2b\xb7\x97\x90\x9d\x31\x11\x0e\x1c\xb9\x9a\x9a\xab\x52\x3f\xd9\xbc\x54\x22\x18\x1d\xca\x96\x8e\x97\x52\x17\x10\x1c\xef\xa5\xa6\xbc\xff\xbe\xa7\xa5\xd8\x1d\x10\x16\x45\x98\x8e\x95\xbf\x1e\x17\x20\x4d\xbc\xd2\x3f\x4e\xad\x9a\x99\xb4\x1e\x0e\x10\x2d\x9e\x90\x96\xb2\x2c\x22\x2f\x5c\x54\x2d\x24\x32\xaa\x94\x91\xa5\x24\x0f\x0f\x24\xaa\x98\x9b\xb2\x43\x3f\xcf\xc0\x3e\x1e\x18\x23\xaf\x92\x8e\x9c\x2f"));
snd($sock_a, $port_b, rtp(0, 1016, 5560, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1016, 5560, $ssrc, "\x13\x11\x21\xbd\xa2\xa8\xc3\xfa\xb9\xa6\xa9\x45\x19\x10\x1a\xc2\x94\x8e\x99\x4e\x1a\x18\x26\xeb\xba\xdd\x40\x7d\xa7\x99\x9c\xda\x19\x0e\x14\x4a\x99\x90\x99\xc9\x26\x23\x34\x6d\x4b\x2b\x25\x41\xa1\x92\x94\xb3\x1c\x0e\x12\x30\xa0\x96\x9d\xbe\x3b\x41\xcc\xc9\x34\x1c\x19\x2c\xa3\x8f\x8f\xa5\x23\x10\x13\x2a\xaf\xa0\xaa\xcd\xeb\xb4\xa6\xae\x31\x16\x11\x1f\xab\x90\x8e\x9e\x30\x18\x19\x2c\xc8\xb9\xf0\x43\xcc\xa2\x99\x9f\x3c\x14\x0e\x19\xbe\x95\x90\x9d\x4e\x22\x24\x3a\xfa\x43\x2a\x28\xec\x9d\x91\x98\xe4\x16\x0d\x16\x51\x9c\x96\xa0\xd7\x37\x45\xca\xda\x2c\x1b\x1b\x3d\x9c\x8e\x92\xb4\x1c\x0f\x16\x38\xa8\xa0\xad\xda\xdd\xb0\xa7\xb9\x28\x14\x13"));
# pause
snd($sock_a, $port_b, rtp(0, 1017, 5720, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1017, 5720, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1018, 5880, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1018, 5880, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1019, 6040, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1019, 6040, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1020, 6200, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1020, 6200, $ssrc, "\xff" x 160));
snd($sock_a, $port_b, rtp(0, 1021, 6360, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1021, 6360, $ssrc, "\xff" x 160));
# resume
snd($sock_a, $port_b, rtp(0, 1022, 6520, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1022, 6520, $ssrc, "\x00" x 160));
# RFC payload type present
($sock_a, $sock_b) = new_call([qw(198.51.100.1 6010)], [qw(198.51.100.3 6012)]);
($port_a) = offer('multi- no transcoding, RFC payload type present',
{ ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 6010 RTP/AVP 0 8 96
c=IN IP4 198.51.100.1
a=rtpmap:96 telephone-event/8000
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0 8 96
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('multi- no transcoding, RFC payload type present',
{ ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 6012 RTP/AVP 0 8 96
c=IN IP4 198.51.100.3
a=rtpmap:96 telephone-event/8000
a=sendrecv
--------------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0 8 96
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=sendrecv
a=rtcp:PORT
SDP
snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160));
($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 160));
snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1001, 3160, $ssrc, "\x00" x 160));
$resp = rtpe_req('play DTMF', 'inject DTMF towards B',
{ 'from-tag' => $ft, code => '0', volume => 10, duration => 100 });
$resp = rtpe_req('play DTMF', 'inject DTMF towards B',
{ 'from-tag' => $ft, code => '1', volume => 6, duration => 100 });
snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0"));
snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40"));
snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0"));
snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80"));
snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20"));
snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0"));
snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1010, 4280, $ssrc, "\x00" x 160));
snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1011, 4440, $ssrc, "\x00" x 160));
snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1012, 4600, $ssrc, "\x00" x 160));
snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1013, 4760, $ssrc, "\x00" x 160));
snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96 | 0x80, 1014, 4920, $ssrc, "\x01\x06\x00\xa0"));
snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1015, 4920, $ssrc, "\x01\x06\x01\x40"));
snd($sock_a, $port_b, rtp(0, 1014, 5240, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1016, 4920, $ssrc, "\x01\x06\x01\xe0"));
snd($sock_a, $port_b, rtp(0, 1015, 5400, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1017, 4920, $ssrc, "\x01\x06\x02\x80"));
snd($sock_a, $port_b, rtp(0, 1016, 5560, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1018, 4920, $ssrc, "\x01\x06\x03\x20"));
snd($sock_a, $port_b, rtp(0, 1017, 5720, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(96, 1019, 4920, $ssrc, "\x01\x86\x03\xc0"));
rcv($sock_b, $port_a, rtpm(96, 1020, 4920, $ssrc, "\x01\x86\x03\xc0"));
rcv($sock_b, $port_a, rtpm(96, 1021, 4920, $ssrc, "\x01\x86\x03\xc0"));
snd($sock_a, $port_b, rtp(0, 1018, 5880, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1022, 5880, $ssrc, "\x00" x 160));
# SDP in/out tests, various ICE options
new_call;

Loading…
Cancel
Save