Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some DTMF injection fixes #1809

Closed
wants to merge 7 commits into from
13 changes: 11 additions & 2 deletions daemon/codec.c
Expand Up @@ -2295,10 +2295,12 @@ static tc_code packet_dtmf(struct codec_ssrc_handler *ch, struct codec_ssrc_hand
ret = TCC_CONSUMED;
else
ret = packet_dtmf_fwd(ch, input_ch, dup, mp);
mp->ssrc_out->parent->seq_diff++;

if (ret != TCC_CONSUMED)
__transcode_packet_free(dup);
}
mp->ssrc_out->parent->seq_diff--;

// discard the received event
do_blocking = true;
Expand Down Expand Up @@ -2664,7 +2666,7 @@ void codec_add_dtmf_event(struct codec_ssrc_handler *ch, int code, int level, ui
uint64_t codec_last_dtmf_event(struct codec_ssrc_handler *ch) {
struct dtmf_event *ev = t_queue_peek_tail(&ch->dtmf_events);
if (!ev)
return 0;
ev = &ch->dtmf_state;
return ev->ts;
}

Expand Down Expand Up @@ -3979,6 +3981,7 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru
// check special payloads

unsigned int repeats = 0;
unsigned long ts_delay = 0;
int payload_type = -1;
int dtmf_pt = ch->handler->dtmf_payload_type;
if (dtmf_pt == -1)
Expand All @@ -3994,6 +3997,12 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru
ch->rtp_mark = 1; // DTMF start event
else if (is_dtmf == 3)
repeats = 2; // DTMF end event
// we need to pass a ts_delay to codec_output_rtp to ensure the calculated time
// to send the packet is offset by the event duration of the DTMF packets
// but we need to reduce it by one packet duration so that the delay is offset
// from the first event packet
struct telephone_event_payload *ev_pt = (void *) inout->s;
ts_delay = ntohs(ev_pt->duration) - (ch->handler->dest_pt.ptime * ch->handler->dest_pt.clock_rate / 1000);
}
else {
if (is_silence_event(inout, &ch->silence_events, pkt->pts, pkt->duration))
Expand All @@ -4012,7 +4021,7 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru
codec_output_rtp(mp, &ch->csch, ch->handler, send_buf, inout->len, ch->csch.first_ts
+ fraction_divl(pkt->pts, cr_fact),
ch->rtp_mark ? 1 : 0, -1, 0,
payload_type, 0);
payload_type, ts_delay);
mp->ssrc_out->parent->seq_diff++;
ch->rtp_mark = 0;
} while (repeats--);
Expand Down
76 changes: 53 additions & 23 deletions daemon/dtmf.c
Expand Up @@ -207,14 +207,21 @@ static void dtmf_end_event(struct call_media *media, unsigned int event, unsigne
if (!clockrate)
clockrate = 8000;

struct dtmf_event *ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = 0, .ts = ts, .volume = 0 };
t_queue_push_tail(&media->dtmf_recv, ev);
// don't add to recv list when it's injected, it can cause the list TS's to be out
// of order breaking the dtmf-security and letting the generated PCM frames through
if (!injected) {
struct dtmf_event *ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = 0, .ts = ts, .volume = 0 };
t_queue_push_tail(&media->dtmf_recv, ev);
}

ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = 0, .ts = ts + media->monologue->dtmf_delay * clockrate / 1000,
.volume = 0, .block_dtmf = media->monologue->block_dtmf };
t_queue_push_tail(&media->dtmf_send, ev);
// only add to send list if injected, a delayed send, or not being blocked
if (injected || !media->monologue->block_dtmf || media->monologue->dtmf_delay) {
struct dtmf_event *ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = 0, .ts = ts + media->monologue->dtmf_delay * clockrate / 1000,
.volume = 0, .block_dtmf = media->monologue->block_dtmf };
t_queue_push_tail(&media->dtmf_send, ev);
}

if (!dtmf_do_logging(media->call, injected))
return;
Expand Down Expand Up @@ -477,7 +484,7 @@ static void dtmf_check_trigger(struct call_media *media, char event, uint64_t ts
}

// media->dtmf_lock must be held
static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, int clockrate, int volume) {
static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, int clockrate, int volume, bool injected) {
struct dtmf_event *ev = t_queue_peek_tail(&media->dtmf_recv);
if (ev && ev->code == event)
return;
Expand All @@ -487,16 +494,23 @@ static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, i
// check trigger before setting new dtmf_start
dtmf_check_trigger(media, event, ts, clockrate);

ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = event, .ts = ts, .volume = volume,
.rand_code = '0' + (ssl_random() % 10), .index = media->dtmf_count };
t_queue_push_tail(&media->dtmf_recv, ev);
// don't add to recv list when it's injected, it can cause the list TS's to be out
// of order breaking the dtmf-security and letting the generated PCM frames through
if (!injected) {
ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = event, .ts = ts, .volume = volume,
.rand_code = '0' + (ssl_random() % 10), .index = media->dtmf_count };
t_queue_push_tail(&media->dtmf_recv, ev);
}

ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = event, .ts = ts + media->monologue->dtmf_delay * clockrate / 1000,
.volume = volume,
.block_dtmf = media->monologue->block_dtmf };
t_queue_push_tail(&media->dtmf_send, ev);
// only add to send list if injected, a delayed send, or not being blocked
if (injected || !media->monologue->block_dtmf || media->monologue->dtmf_delay) {
ev = g_slice_alloc0(sizeof(*ev));
*ev = (struct dtmf_event) { .code = event, .ts = ts + media->monologue->dtmf_delay * clockrate / 1000,
.volume = volume,
.block_dtmf = media->monologue->block_dtmf };
t_queue_push_tail(&media->dtmf_send, ev);
}

media->dtmf_count++;
}
Expand Down Expand Up @@ -561,7 +575,7 @@ int dtmf_event_packet(struct media_packet *mp, str *payload, int clockrate, uint
dtmf->event, dtmf->volume, dtmf->end, duration);

if (!dtmf->end) {
dtmf_code_event(mp->media, dtmf_code_to_char(dtmf->event), ts, clockrate, dtmf->volume);
dtmf_code_event(mp->media, dtmf_code_to_char(dtmf->event), ts, clockrate, dtmf->volume, false);
return 0;
}

Expand Down Expand Up @@ -613,7 +627,7 @@ void dtmf_dsp_event(const struct dtmf_event *new_event, struct dtmf_event *cur_e
int code = dtmf_code_from_char(new_event->code); // for validation
if (code != -1)
dtmf_code_event(media, (char) new_event->code, ts, clockrate,
dtmf_volume_from_dsp(new_event->volume));
dtmf_volume_from_dsp(new_event->volume), injected);
}
}

Expand All @@ -627,8 +641,8 @@ int dtmf_event_payload(str *buf, uint64_t *pts, uint64_t duration, struct dtmf_e
{
// do we have a relevant state change?
struct dtmf_event prev_event = *cur_event;
struct dtmf_event *ev = t_queue_peek_head(events);
while (events->length) {
struct dtmf_event *ev = t_queue_peek_head(events);
ilog(LOG_DEBUG, "Next DTMF event starts at %" PRIu64 ". PTS now %" PRIu64, ev->ts, *pts);
if (ev->ts > *pts)
break; // future event
Expand All @@ -638,6 +652,14 @@ int dtmf_event_payload(str *buf, uint64_t *pts, uint64_t duration, struct dtmf_e
t_queue_pop_head(events);
*cur_event = *ev;
dtmf_event_free(ev);
ev = t_queue_peek_head(events);
if (ev && ev->code == 0 && cur_event->ts < *pts) {
// if the start event ts was before *pts we need
// to adjust the end event_ts to ensure we're not shortening
// the event
ilog(LOG_DEBUG, "Delayed send of DTMF, adjusting end event_ts by %lu - %lu = %lu", *pts, cur_event->ts, *pts - cur_event->ts);
ev->ts += *pts - cur_event->ts;
}
cur_event->ts = *pts; // canonicalise start TS
}

Expand Down Expand Up @@ -841,13 +863,21 @@ const char *dtmf_inject(struct call_media *media, int code, int volume, int dura
ssrc_in->parent->h.ssrc);

// synthesise start and stop events
uint64_t num_samples = (uint64_t) duration * ch->dest_pt.clock_rate / 1000;
// the num_samples needs to be based on the the previous packet timestamp so we need to
// reduce it by one packets worth or we'll generate one too many packets than requested
uint64_t num_samples = (uint64_t) (duration - ch->dest_pt.ptime) * ch->dest_pt.clock_rate / 1000;
uint64_t start_pts = codec_encoder_pts(csh, ssrc_in);
// get the last event end time, and increase by the required pause
// conversely to the above, we need to add the last packet num samples to its TS before adding
// a pause so we dont generate one packet too few
// if that's later than start_pts, we need to adjust it
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;
last_end_pts += (pause + ch->dest_pt.ptime) * ch->dest_pt.clock_rate / 1000;
if (last_end_pts > start_pts)
start_pts = last_end_pts;
}

codec_add_dtmf_event(csh, dtmf_code_to_char(code), volume, start_pts, true);
codec_add_dtmf_event(csh, 0, 0, start_pts + num_samples, true);

Expand Down
105 changes: 46 additions & 59 deletions t/auto-daemon-tests.pl
Expand Up @@ -1658,15 +1658,13 @@ sub stun_succ {
snd($sock_a, $port_b, rtp(8, 1006, 3960, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(101, 1006, 3480, 0x1234, "\x00\x0a\x02\x80"));
snd($sock_a, $port_b, rtp(8, 1007, 4120, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(101, 1007, 3480, 0x1234, "\x00\x0a\x03\x20"));
snd($sock_a, $port_b, rtp(8, 1008, 4280, 0x1234, "\x00" x 160));
# end event
rcv($sock_b, $port_a, rtpm(101, 1008, 3480, 0x1234, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1009, 3480, 0x1234, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1010, 3480, 0x1234, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1007, 3480, 0x1234, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1008, 3480, 0x1234, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1009, 3480, 0x1234, "\x00\x8a\x03\x20"));

snd($sock_a, $port_b, rtp(8, 1009, 4440, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, 1011, 4440, 0x1234, "\x00" x 160));
snd($sock_a, $port_b, rtp(8, 1008, 4280, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, 1010, 4280, 0x1234, "\x00" x 160));



Expand Down Expand Up @@ -1774,15 +1772,13 @@ sub stun_succ {
snd($sock_a, $port_b, rtp(8, 1017, 5400, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(101, 1017, 4920, 0x1234, "\x00\x0a\x02\x80"));
snd($sock_a, $port_b, rtp(8, 1018, 5560, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(101, 1018, 4920, 0x1234, "\x00\x0a\x03\x20"));
snd($sock_a, $port_b, rtp(8, 1019, 5720, 0x1234, "\x00" x 160));
# end event
rcv($sock_b, $port_a, rtpm(101, 1019, 4920, 0x1234, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1020, 4920, 0x1234, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1021, 4920, 0x1234, "\x00\x8a\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1018, 4920, 0x1234, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1019, 4920, 0x1234, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1020, 4920, 0x1234, "\x00\x8a\x03\x20"));

snd($sock_a, $port_b, rtp(8, 1020, 5880, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, 1022, 5880, 0x1234, "\x00" x 160));
snd($sock_a, $port_b, rtp(8, 1019, 5720, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, 1021, 5720, 0x1234, "\x00" x 160));

snd($sock_a, $port_b, rtp(101 | 0x80, 1021, 6040, 0x1234, "\x03\x26\x00\xa0"));
rcv_no($sock_b);
Expand All @@ -1791,28 +1787,29 @@ sub stun_succ {
{ 'from-tag' => ft(), code => '1', volume => 12, duration => 100 });

snd($sock_a, $port_b, rtp(101, 1022, 6040, 0x1234, "\x03\x26\x01\x40"));
rcv($sock_b, $port_a, rtpm(101 | 0x80, 1024, 6200, 0x1234, "\x01\x0c\x00\xa0"));
rcv_no($sock_b);
snd($sock_a, $port_b, rtp(101, 1023, 6040, 0x1234, "\x03\x26\x01\xe0"));
rcv($sock_b, $port_a, rtpm(101, 1025, 6200, 0x1234, "\x01\x0c\x01\x40"));
rcv_no($sock_b);
snd($sock_a, $port_b, rtp(101, 1024, 6040, 0x1234, "\x03\x26\x02\x80"));
rcv($sock_b, $port_a, rtpm(101, 1026, 6200, 0x1234, "\x01\x0c\x01\xe0"));
rcv($sock_b, $port_a, rtpm(101 | 0x80, 1026, 6520, 0x1234, "\x01\x0c\x00\xa0"));
snd($sock_a, $port_b, rtp(101, 1025, 6040, 0x1234, "\x03\x26\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1027, 6200, 0x1234, "\x01\x0c\x02\x80"));
rcv($sock_b, $port_a, rtpm(101, 1027, 6520, 0x1234, "\x01\x0c\x01\x40"));
# send end event
snd($sock_a, $port_b, rtp(101, 1026, 6040, 0x1234, "\x03\xa6\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1028, 6200, 0x1234, "\x01\x0c\x03\x20"));
snd($sock_a, $port_b, rtp(101, 1027, 6040, 0x1234, "\x03\xa6\x03\xc0"));
rcv_no($sock_b);
snd($sock_a, $port_b, rtp(101, 1028, 6040, 0x1234, "\x03\xa6\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1028, 6520, 0x1234, "\x01\x0c\x01\xe0"));
rcv_no($sock_b);
# send audio, receive end event
snd($sock_a, $port_b, rtp(8, 1029, 7000, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(101, 1031, 6200, 0x1234, "\x01\x8c\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1032, 6200, 0x1234, "\x01\x8c\x03\xc0"));
rcv($sock_b, $port_a, rtpm(101, 1033, 6200, 0x1234, "\x01\x8c\x03\xc0"));

rcv($sock_b, $port_a, rtpm(101, 1029, 6520, 0x1234, "\x01\x0c\x02\x80"));
snd($sock_a, $port_b, rtp(8, 1030, 7160, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, 1034, 7160, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(101, 1030, 6520, 0x1234, "\x01\x8c\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1031, 6520, 0x1234, "\x01\x8c\x03\x20"));
rcv($sock_b, $port_a, rtpm(101, 1032, 6520, 0x1234, "\x01\x8c\x03\x20"));

snd($sock_a, $port_b, rtp(8, 1031, 7320, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, 1033, 7320, 0x1234, "\x00" x 160));



Expand Down Expand Up @@ -14563,13 +14560,11 @@ sub stun_succ {
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"));
rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\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));
rcv($sock_b, $port_a, rtpm(0, 1009, 4120, $ssrc, "\x00" x 160));



Expand All @@ -14590,13 +14585,11 @@ sub stun_succ {
snd($sock_b, $port_a, rtp(0, 4005, 8800, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(96, 4005, 8320, $ssrc, "\x0a\x0a\x02\x80"));
snd($sock_b, $port_a, rtp(0, 4006, 8960, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0a\x0a\x03\x20"));
rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0a\x8a\x03\x20"));
rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0a\x8a\x03\x20"));
rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0a\x8a\x03\x20"));
snd($sock_b, $port_a, rtp(0, 4007, 9120, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0a\x8a\x03\xc0"));
rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0a\x8a\x03\xc0"));
rcv($sock_a, $port_b, rtpm(96, 4009, 8320, $ssrc, "\x0a\x8a\x03\xc0"));
snd($sock_b, $port_a, rtp(0, 4008, 9280, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4009, 9120, $ssrc, "\x00" x 160));



Expand Down Expand Up @@ -14670,13 +14663,11 @@ sub stun_succ {
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"));
rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\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(8, 1010, 4280, $ssrc, "\x2a" x 160));
rcv($sock_b, $port_a, rtpm(8, 1009, 4120, $ssrc, "\x2a" x 160));



Expand All @@ -14697,13 +14688,11 @@ sub stun_succ {
snd($sock_b, $port_a, rtp(8, 4005, 8800, 0x6543, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(96, 4005, 8320, $ssrc, "\x0b\x0a\x02\x80"));
snd($sock_b, $port_a, rtp(8, 4006, 8960, 0x6543, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0b\x0a\x03\x20"));
rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0b\x8a\x03\x20"));
rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0b\x8a\x03\x20"));
rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0b\x8a\x03\x20"));
snd($sock_b, $port_a, rtp(8, 4007, 9120, 0x6543, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0b\x8a\x03\xc0"));
rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0b\x8a\x03\xc0"));
rcv($sock_a, $port_b, rtpm(96, 4009, 8320, $ssrc, "\x0b\x8a\x03\xc0"));
snd($sock_b, $port_a, rtp(8, 4008, 9280, 0x6543, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4009, 9120, $ssrc, "\x00" x 160));



Expand Down Expand Up @@ -15133,11 +15122,11 @@ sub stun_succ {
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"));
rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\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"));
rcv($sock_b, $port_a, rtpm(0, 1009, 4120, $ssrc, "\x00" x 160));
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));
Expand All @@ -15155,13 +15144,11 @@ sub stun_succ {
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"));
rcv($sock_b, $port_a, rtpm(96, 1018, 4920, $ssrc, "\x01\x86\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1019, 4920, $ssrc, "\x01\x86\x03\x20"));
rcv($sock_b, $port_a, rtpm(96, 1020, 4920, $ssrc, "\x01\x86\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));
rcv($sock_b, $port_a, rtpm(0, 1021, 5720, $ssrc, "\x00" x 160));



Expand Down