TT#68100 set iLBC encoder and decoder options

required to distinguish between 20-ms and 30-ms modes, both for encoding
and decoding

add support for the iLBC mode= format parameter and dynamic mode
switching

closes #854

Change-Id: Icb6f0ec80df86d27681c689c168b24f163a2db06
changes/64/33864/8
Richard Fuchs 6 years ago
parent 7fbaf0aab9
commit 228d822a71

@ -993,6 +993,9 @@ Optionally included keys are:
e.g. `opus/48000/2/32000`. In this case, all format parameters (clock rate,
channels) must also be specified.
Additional options that can be appended to the codec string with additional slashes
are ptime and the `fmtp` string, for example `iLBC/8000/1///mode=30`.
As a special case, if the `strip=all` option has been used and the `transcode`
option is used on a codec that was originally present in the offer, then
*rtpengine* will treat this codec the same as if it had been used with the `offer`

@ -1159,13 +1159,14 @@ void codec_packet_free(void *pp) {
struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct call_media *media) {
str codec_fmt = *codec_str;
str codec, parms, chans, opts, extra_opts;
str codec, parms, chans, opts, extra_opts, fmt_params;
if (str_token_sep(&codec, &codec_fmt, '/'))
return NULL;
str_token_sep(&parms, &codec_fmt, '/');
str_token_sep(&chans, &codec_fmt, '/');
str_token_sep(&opts, &codec_fmt, '/');
str_token_sep(&extra_opts, &codec_fmt, '/');
str_token_sep(&fmt_params, &codec_fmt, '/');
int clockrate = str_to_i(&parms, 0);
int channels = str_to_i(&chans, 0);
@ -1182,7 +1183,7 @@ struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct ca
ret->channels = channels;
ret->bitrate = bitrate;
ret->ptime = ptime;
ret->format_parameters = STR_EMPTY;
ret->format_parameters = fmt_params;
const codec_def_t *def = codec_find(&ret->encoding, 0);
ret->codec_def = def;
@ -1370,6 +1371,7 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
}
ch->decoder = decoder_new_fmtp(h->source_pt.codec_def, h->source_pt.clock_rate, h->source_pt.channels,
h->source_pt.ptime,
&ch->encoder_format, &h->source_pt.format_parameters);
if (!ch->decoder)
goto err;

@ -783,6 +783,8 @@ static void setup_media_proc(struct call_media *media) {
if (!recording)
return;
append_meta_chunk_null(recording, "MEDIA %u PTIME %i", media->unique_id, media->ptime);
GList *pltypes = g_hash_table_get_values(media->codecs_recv);
for (GList *l = pltypes; l; l = l->next) {

@ -42,6 +42,9 @@ static packetizer_f packetizer_amr;
static format_init_f opus_init;
static set_enc_options_f opus_set_enc_options;
static set_enc_options_f ilbc_set_enc_options;
static set_dec_options_f ilbc_set_dec_options;
static set_enc_options_f amr_set_enc_options;
static set_dec_options_f amr_set_dec_options;
@ -54,6 +57,7 @@ static int avc_encoder_input(encoder_t *enc, AVFrame **frame);
static void avc_encoder_close(encoder_t *enc);
static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out);
static int ilbc_decoder_input(decoder_t *dec, const str *data, GQueue *out);
static const char *dtmf_decoder_init(decoder_t *, const str *);
static int dtmf_decoder_input(decoder_t *dec, const str *data, GQueue *out);
@ -70,6 +74,15 @@ static const codec_type_t codec_type_avcodec = {
.encoder_input = avc_encoder_input,
.encoder_close = avc_encoder_close,
};
static const codec_type_t codec_type_ilbc = {
.def_init = avc_def_init,
.decoder_init = avc_decoder_init,
.decoder_input = ilbc_decoder_input,
.decoder_close = avc_decoder_close,
.encoder_init = avc_encoder_init,
.encoder_input = avc_encoder_input,
.encoder_close = avc_encoder_close,
};
static const codec_type_t codec_type_amr = {
.def_init = avc_def_init,
.decoder_init = avc_decoder_init,
@ -242,11 +255,14 @@ static codec_def_t __codec_defs[] = {
.avcodec_id = AV_CODEC_ID_ILBC,
.default_clockrate = 8000,
.default_channels = 1,
.default_ptime = 20,
.default_ptime = 30,
.default_fmtp = "mode=30",
//.default_bitrate = 15200,
.packetizer = packetizer_passthrough,
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.codec_type = &codec_type_ilbc,
.set_enc_options = ilbc_set_enc_options,
.set_dec_options = ilbc_set_dec_options,
},
{
.rtpname = "opus",
@ -471,11 +487,11 @@ static const char *avc_decoder_init(decoder_t *dec, const str *fmtp) {
decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt) {
return decoder_new_fmtp(def, clockrate, channels, resample_fmt, NULL);
decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt) {
return decoder_new_fmtp(def, clockrate, channels, ptime, resample_fmt, NULL);
}
decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt,
decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt,
const str *fmtp)
{
const char *err;
@ -497,6 +513,10 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels,
ret->out_format = ret->in_format;
if (resample_fmt)
ret->out_format = *resample_fmt;
if (ptime > 0)
ret->ptime = ptime;
else
ret->ptime = def->default_ptime;
err = def->codec_type->decoder_init(ret, fmtp);
if (err)
@ -1358,6 +1378,101 @@ static void opus_set_enc_options(encoder_t *enc, const str *fmtp) {
// XXX additional opus options
}
static int ilbc_mode(int ptime, const str *fmtp, const char *direction) {
int mode = 0;
if (fmtp) {
if (!str_cmp(fmtp, "mode=20")) {
mode = 20;
ilog(LOG_DEBUG, "Setting iLBC %s mode to 20 ms based on fmtp", direction);
}
else if (!str_cmp(fmtp, "mode=30")) {
mode = 30;
ilog(LOG_DEBUG, "Setting iLBC %s mode to 30 ms based on fmtp", direction);
}
}
if (!mode) {
switch (ptime) {
case 20:
case 40:
case 60:
case 80:
case 100:
case 120:
mode = 20;
ilog(LOG_DEBUG, "Setting iLBC %s mode to 20 ms based on ptime %i",
direction, ptime);
break;
case 30:
case 90:
mode = 30;
ilog(LOG_DEBUG, "Setting iLBC %s mode to 30 ms based on ptime %i",
direction, ptime);
break;
}
}
if (!mode) {
mode = 20;
ilog(LOG_WARNING, "No iLBC %s mode specified, setting to 20 ms", direction);
}
return mode;
}
static void ilbc_set_enc_options(encoder_t *enc, const str *fmtp) {
int ret;
int mode = ilbc_mode(enc->ptime, fmtp, "encoder");
if ((ret = av_opt_set_int(enc->u.avc.avcctx, "mode", mode,
AV_OPT_SEARCH_CHILDREN)))
ilog(LOG_WARN, "Failed to set iLBC mode option to %i: %s",
mode, av_error(ret));
}
static void ilbc_set_dec_options(decoder_t *dec, const str *fmtp) {
int mode = ilbc_mode(dec->ptime, fmtp, "decoder");
if (mode == 20)
dec->u.avc.avcctx->block_align = 38;
else if (mode == 30)
dec->u.avc.avcctx->block_align = 50;
else
ilog(LOG_WARN, "Unsupported iLBC mode %i", mode);
}
static int ilbc_decoder_input(decoder_t *dec, const str *data, GQueue *out) {
int mode = 0, block_align = 0;
static const str mode_20 = STR_CONST_INIT("mode=20");
static const str mode_30 = STR_CONST_INIT("mode=30");
const str *fmtp;
if (data->len % 50 == 0) {
mode = 30;
block_align = 50;
fmtp = &mode_30;
}
else if (data->len % 38 == 0) {
mode = 20;
block_align = 38;
fmtp = &mode_20;
}
else
ilog(LOG_WARNING | LOG_FLAG_LIMIT, "iLBC received %i bytes packet, does not match "
"one of the block sizes", (int) data->len);
if (block_align && dec->u.avc.avcctx->block_align != block_align) {
ilog(LOG_INFO | LOG_FLAG_LIMIT, "iLBC decoder set to %i bytes blocks, but received packet "
"of %i bytes, therefore resetting decoder and switching to %i bytes "
"block mode (%i ms mode)",
(int) dec->u.avc.avcctx->block_align, (int) data->len, block_align, mode);
avc_decoder_close(dec);
avc_decoder_init(dec, fmtp);
}
return avc_decoder_input(dec, data, out);
}

@ -150,6 +150,7 @@ struct decoder_s {
unsigned long rtp_ts;
uint64_t pts;
int ptime;
};
struct encoder_s {
@ -200,8 +201,8 @@ const codec_def_t *codec_find_by_av(enum AVCodecID);
enum media_type codec_get_type(const str *type);
decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt);
decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt,
decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt);
decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, int ptime, const format_t *resample_fmt,
const str *fmtp);
void decoder_close(decoder_t *dec);
int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts,

@ -24,7 +24,7 @@ int resample_audio;
decode_t *decoder_new(const char *payload_str, output_t *outp) {
decode_t *decoder_new(const char *payload_str, int ptime, output_t *outp) {
str name;
char *slash = strchr(payload_str, '/');
if (!slash) {
@ -79,7 +79,7 @@ decode_t *decoder_new(const char *payload_str, output_t *outp) {
outp->encoder->requested_format.format = out_format.format;
}
decoder_t *dec = decoder_new_fmt(def, rtp_clockrate, channels, &out_format);
decoder_t *dec = decoder_new_fmt(def, rtp_clockrate, channels, ptime, &out_format);
if (!dec)
return NULL;
decode_t *deco = g_slice_alloc0(sizeof(decode_t));

@ -8,7 +8,7 @@
extern int resample_audio;
decode_t *decoder_new(const char *payload_str, output_t *);
decode_t *decoder_new(const char *payload_str, int ptime, output_t *);
int decoder_input(decode_t *, const str *, unsigned long ts, ssrc_t *);
void decoder_free(decode_t *);

@ -103,6 +103,12 @@ static void meta_rtp_payload_type(metafile_t *mf, unsigned long mnum, unsigned i
{
dbg("payload type in media %lu num %u is %s", mnum, payload_num, payload_type);
int ptime = 0;
mnum--;
if (mnum < G_N_ELEMENTS(mf->media_ptimes))
ptime = mf->media_ptimes[mnum];
if (payload_num >= 128) {
ilog(LOG_ERR, "Payload type number %u is invalid", payload_num);
return;
@ -111,11 +117,22 @@ static void meta_rtp_payload_type(metafile_t *mf, unsigned long mnum, unsigned i
pthread_mutex_lock(&mf->payloads_lock);
mf->payload_types[payload_num] = g_string_chunk_insert(mf->gsc,
payload_type);
mf->payload_ptimes[payload_num] = ptime;
pthread_mutex_unlock(&mf->payloads_lock);
}
}
// mf is locked
static void meta_ptime(metafile_t *mf, unsigned long mnum, int ptime)
{
mnum--;
if (mnum >= G_N_ELEMENTS(mf->media_ptimes))
return;
mf->media_ptimes[mnum] = ptime;
}
// mf is locked
static void meta_metadata(metafile_t *mf, char *content) {
mf->metadata = g_string_chunk_insert(mf->gsc, content);
@ -130,6 +147,7 @@ static void meta_metadata(metafile_t *mf, char *content) {
static void meta_section(metafile_t *mf, char *section, char *content, unsigned long len) {
unsigned long lu;
unsigned int u;
int i;
if (!strcmp(section, "CALL-ID"))
mf->call_id = g_string_chunk_insert(mf->gsc, content);
@ -143,6 +161,8 @@ static void meta_section(metafile_t *mf, char *section, char *content, unsigned
meta_stream_details(mf, lu, content);
else if (sscanf_match(section, "MEDIA %lu PAYLOAD TYPE %u", &lu, &u) == 2)
meta_rtp_payload_type(mf, lu, u, content);
else if (sscanf_match(section, "MEDIA %lu PTIME %i", &lu, &i) == 2)
meta_ptime(mf, lu, i);
else if (sscanf_match(section, "TAG %lu", &lu) == 1)
tag_name(mf, lu, content);
else if (sscanf_match(section, "LABEL %lu", &lu) == 1)

@ -245,6 +245,7 @@ static void packet_decode(ssrc_t *ssrc, packet_t *packet) {
metafile_t *mf = ssrc->metafile;
pthread_mutex_lock(&mf->payloads_lock);
char *payload_str = mf->payload_types[payload_type];
int ptime = mf->payload_ptimes[payload_type];
pthread_mutex_unlock(&mf->payloads_lock);
if (!payload_str) {
@ -264,7 +265,7 @@ static void packet_decode(ssrc_t *ssrc, packet_t *packet) {
outp = mf->mix_out;
else if (ssrc->output)
outp = ssrc->output;
ssrc->decoders[payload_type] = decoder_new(payload_str, outp);
ssrc->decoders[payload_type] = decoder_new(payload_str, ptime, outp);
pthread_mutex_unlock(&mf->mix_lock);
if (!ssrc->decoders[payload_type]) {
ilog(LOG_WARN, "Cannot decode RTP payload type %u (%s)",

@ -130,6 +130,8 @@ struct metafile_s {
pthread_mutex_t payloads_lock;
char *payload_types[128];
int payload_ptimes[128];
int media_ptimes[4];
int recording_on:1;
int forwarding_on:1;

@ -51,7 +51,7 @@ static void do_test_amr_xx(const char *file, int line,
str_init(&fmtp_str, fmtp_s);
fmtp = &fmtp_str;
}
decoder_t *d = decoder_new_fmtp(def, clockrate, 1, &fmt, fmtp);
decoder_t *d = decoder_new_fmtp(def, clockrate, 1, 0, &fmt, fmtp);
assert(d);
const str data = { data_s, data_len };
int ret = decoder_input_data(d, &data, 1, frame_cb, &expect_s, &expect_len);

@ -196,6 +196,142 @@ my ($sock_a, $sock_b, $port_a, $port_b, $ssrc, $resp, $srtp_ctx_a, $srtp_ctx_b);
if (0) {
# github issue 854
($sock_a, $sock_b) = new_call([qw(198.51.100.1 7326)], [qw(198.51.100.3 7328)]);
($port_a) = offer('gh854 inbound 30 ms',
{ ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 7326 RTP/AVP 96
c=IN IP4 198.51.100.1
a=rtpmap:96 iLBC/8000
a=fmtp:96 mode=30
a=ptime:30
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 96 8
c=IN IP4 203.0.113.1
a=rtpmap:96 iLBC/8000
a=rtpmap:8 PCMA/8000
a=fmtp:96 mode=30
a=sendrecv
a=rtcp:PORT
a=ptime:30
SDP
($port_b) = answer('gh854 inbound 30 ms',
{ ICE => 'remove', replace => ['origin'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 7328 RTP/AVP 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 96
c=IN IP4 203.0.113.1
a=rtpmap:96 iLBC/8000
a=fmtp:96 mode=30
a=sendrecv
a=rtcp:PORT
a=ptime:30
SDP
snd($sock_a, $port_b, rtp(96, 1000, 3000, 0x6543, "\xa2\xff\x30\x0e\x5b\x3e\xa0\xac\x40\x40\x00\x57\xff\xff\xfd\xa4\x58\x8b\x62\x10\xcf\xff\xb9\xaa\xbb\xff\xcc\xc0\x00\x00\x00\x00\x00\x0c\x31\x1c\xc1\x74\xaf\x85\x85\x9a\x32\x33\x63\x60\x21\x61\x58\x76"));
($ssrc) = rcv($sock_b, $port_a, rtpm(8, 1000, 3000, -1, "\xd5\x55\x57\x5e\x65\x03\x2a\x2a\x2a\xaa\xaa\xaa\xaa\x2a\xaa\x2a\xaa\x2a\x2a\xaa\xaa\xaa\xaa\xaa\xaa\x2a\xaa\xaa\xaa\xaa\xab\x2a\xaa\xa8\x2a\xaa\x2a\xaa\x2a\x2a\x2a\x2a\x2a\x2b\x2a\x2e\x2e\x2a\x2a\x2e\x26\xaa\xaa\xaa\x3c\x2a\x2a\xad\xad\xa3\xa7\xa7\xa3\xa2\xa1\xa3\xa4\xba\xbe\xb2\xb6\x8a\x86\x9f\x96\xee\x9b\x81\x84\x9d\x99\x9a\x85\x87\x84\x8f\x8d\x82\x83\xed\x97\x95\x87\x8b\xb1\x81\x81\x9b\x9c\xea\xcc\x79\x6c\x11\x13\x1b\x18\x19\x19\x1f\x12\x10\x12\x1d\x10\x16\x14\x6b\x68\x66\x64\x7a\x7e\x7d\x72\x72\x7c\x7f\x79\x65\x65\x60\x61\x61\x61\x7f\x7c\x72\x78\x67\x62\x78\x7a\x78\x7f\x71\x48\x44\x5c\x55\xd3\xd9\xc4\xc6\xc1\xc1\xc6\xc4\xda\xd8\xd8\xd9\xdc\xda\xdd\xdf\xd3\xd2\xd6\xda\xdd\xdf\xde\xd8\xdb\xda\xdb\xda\xdb\xda\xd8\xd9\xde\xdf\xdc\xdd\xdd\xd2\xd3\xd3\xd3\xd0\xd0\xd1\xd1\xd0\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd6\xd6\xd6\xd7\xd7\xd7\xd4\xd4\xd4\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\x55\xd5\x55\x55\x55\x55\x55\x55\x55\x55\x54\x54\x54\x54\x54\x54\x54\x54"));
# mode switch
snd($sock_a, $port_b, rtp(96, 1001, 3240, 0x6543, "\xa2\xff\x37\xd3\xe2\xb8\x50\x40\x00\x5f\xff\xff\xff\x89\xcc\xff\x76\x6a\xae\xff\xcc\x00\x00\x00\x00\x00\x00\x00\x36\x52\x9d\x93\xf8\x45\x45\x45\x12\x16"));
($ssrc) = rcv($sock_b, $port_a, rtpm(8, 1001, 3240, -1, "\xd5\xd5\x55\xaa\x2a\xaa\xaa\x2a\xaa\xaa\xaa\x2a\x2a\xaa\x2a\x2a\x2a\x2a\xaa\xaa\x2a\xaa\x2a\xaa\x2a\xaa\x2a\x2a\xa7\x2a\x2a\x2a\xaa\xaa\x2a\xaa\xaa\x2a\x2a\x2a\x2a\xaa\xaa\xaa\xaa\x2a\x2a\xaa\xaa\xaa\x2a\x2a\x2a\x2a\xaa\x2a\xaa\x2a\xaa\xaa\x2a\x2a\x2a\x2a\x2a\x2a\xaa\x2a\x2a\x2a\x2a\x28\xaa\x2a\x28\xaa\x3e\xaa\xaa\x2a\x2a\xaa\x2a\x2a\xaa\x2a\xaa\xaa\xaa\x81\x36\x2a\x2a\x2a\x2a\xaa\xaa\x2a\xaa\xaa\x2a\xaa\x2a\x2a\x2a\xa5\xaa\xaa\xaa\xaa\xaa\x2a\x2a\xaa\x2a\x2a\xaa\x2a\xaa\xaa\xaa\xaa\xa2\xa4\xaf\x7e\xec\x37\x26\x21\x2f\x28\x29\x2a\x28\x2e\x2f\x22\x20\x27\x25\x39\x32\x31\x34\x0b\x0e\x0c\x0d\x02\x03\x01\x01\x06\x06\x06\x07\x04\x05\x1e"));
snd($sock_b, $port_a, rtp(8, 1000, 3000, 0x1234, "\x00" x 240));
($ssrc) = rcv($sock_a, $port_b, rtpm(96, 1000, 3000, -1, "\xa2\xff\x30\x0e\x5b\x3e\xa0\xac\x40\x40\x00\x57\xff\xff\xfd\xa4\x58\x8b\x62\x10\xcf\xff\xb9\xaa\xbb\xff\xcc\xc0\x00\x00\x00\x00\x00\x0c\x31\x1c\xc1\x74\xaf\x85\x85\x9a\x32\x33\x63\x60\x21\x61\x58\x76"));
($sock_a, $sock_b) = new_call([qw(198.51.100.1 7322)], [qw(198.51.100.3 7324)]);
($port_a) = offer('gh854 inbound 20 ms',
{ ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 7322 RTP/AVP 96
c=IN IP4 198.51.100.1
a=rtpmap:96 iLBC/8000
a=fmtp:96 mode=20
a=ptime:20
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 96 8
c=IN IP4 203.0.113.1
a=rtpmap:96 iLBC/8000
a=rtpmap:8 PCMA/8000
a=fmtp:96 mode=20
a=sendrecv
a=rtcp:PORT
a=ptime:20
SDP
($port_b) = answer('gh854 inbound 20 ms',
{ ICE => 'remove', replace => ['origin'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 7324 RTP/AVP 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 96
c=IN IP4 203.0.113.1
a=rtpmap:96 iLBC/8000
a=fmtp:96 mode=20
a=sendrecv
a=rtcp:PORT
a=ptime:20
SDP
snd($sock_a, $port_b, rtp(96, 1000, 3000, 0x6543, "\xa2\xff\x37\xd3\xe2\xb8\x50\x40\x00\x5f\xff\xff\xff\x89\xcc\xff\x76\x6a\xae\xff\xcc\x00\x00\x00\x00\x00\x00\x00\x36\x52\x9d\x93\xf8\x45\x45\x45\x12\x16"));
($ssrc) = rcv($sock_b, $port_a, rtpm(8, 1000, 3000, -1, "\xd5\xd5\x55\xaa\x2a\xaa\xaa\x2a\xaa\xaa\xaa\x2a\x2a\xaa\x2a\x2a\x2a\x2a\xaa\xaa\x2a\xaa\x2a\xaa\x2a\xaa\x2a\x2a\xa7\x2a\x2a\x2a\xaa\xaa\x2a\xaa\xaa\x2a\x2a\x2a\x2a\xaa\xaa\xaa\xaa\x2a\x2a\xaa\xaa\xaa\x2a\x2a\x2a\x2a\xaa\x2a\xaa\x2a\xaa\xaa\x2a\x2a\x2a\x2a\x2a\x2a\xaa\x2a\x2a\x2a\x2a\x28\xaa\x2a\x28\xaa\x3e\xaa\xaa\x2a\x2a\xaa\x2a\x2a\xaa\x2a\xaa\xaa\xaa\x81\x36\x2a\x2a\x2a\x2a\xaa\xaa\x2a\xaa\xaa\x2a\xaa\x2a\x2a\x2a\xa5\xaa\xaa\xaa\xaa\xaa\x2a\x2a\xaa\x2a\x2a\xaa\x2a\xaa\xaa\xaa\xaa\xa2\xa4\xaf\x7e\xec\x37\x26\x21\x2f\x28\x29\x2a\x28\x2e\x2f\x22\x20\x27\x25\x39\x32\x31\x34\x0b\x0e\x0c\x0d\x02\x03\x01\x01\x06\x06\x06\x07\x04\x05\x1e"));
# mode switch
snd($sock_a, $port_b, rtp(96, 1001, 3160, 0x6543, "\xa2\xff\x30\x0e\x5b\x3e\xa0\xac\x40\x40\x00\x57\xff\xff\xfd\xa4\x58\x8b\x62\x10\xcf\xff\xb9\xaa\xbb\xff\xcc\xc0\x00\x00\x00\x00\x00\x0c\x31\x1c\xc1\x74\xaf\x85\x85\x9a\x32\x33\x63\x60\x21\x61\x58\x76"));
($ssrc) = rcv($sock_b, $port_a, rtpm(8, 1001, 3160, -1, "\xd5\x55\x57\x5e\x65\x03\x2a\x2a\x2a\xaa\xaa\xaa\xaa\x2a\xaa\x2a\xaa\x2a\x2a\xaa\xaa\xaa\xaa\xaa\xaa\x2a\xaa\xaa\xaa\xaa\xab\x2a\xaa\xa8\x2a\xaa\x2a\xaa\x2a\x2a\x2a\x2a\x2a\x2b\x2a\x2e\x2e\x2a\x2a\x2e\x26\xaa\xaa\xaa\x3c\x2a\x2a\xad\xad\xa3\xa7\xa7\xa3\xa2\xa1\xa3\xa4\xba\xbe\xb2\xb6\x8a\x86\x9f\x96\xee\x9b\x81\x84\x9d\x99\x9a\x85\x87\x84\x8f\x8d\x82\x83\xed\x97\x95\x87\x8b\xb1\x81\x81\x9b\x9c\xea\xcc\x79\x6c\x11\x13\x1b\x18\x19\x19\x1f\x12\x10\x12\x1d\x10\x16\x14\x6b\x68\x66\x64\x7a\x7e\x7d\x72\x72\x7c\x7f\x79\x65\x65\x60\x61\x61\x61\x7f\x7c\x72\x78\x67\x62\x78\x7a\x78\x7f\x71\x48\x44\x5c\x55\xd3\xd9\xc4\xc6\xc1\xc1\xc6\xc4\xda\xd8\xd8\xd9\xdc\xda\xdd\xdf\xd3\xd2\xd6\xda\xdd\xdf\xde\xd8\xdb\xda\xdb\xda\xdb\xda\xd8\xd9\xde\xdf\xdc\xdd\xdd\xd2\xd3\xd3\xd3\xd0\xd0\xd1\xd1\xd0\xd1\xd1\xd1\xd1\xd1\xd1\xd1\xd6\xd6\xd6\xd7\xd7\xd7\xd4\xd4\xd4\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\x55\xd5\x55\x55\x55\x55\x55\x55\x55\x55\x54\x54\x54\x54\x54\x54\x54\x54"));
snd($sock_b, $port_a, rtp(8, 1000, 3000, 0x1234, "\x00" x 160));
($ssrc) = rcv($sock_a, $port_b, rtpm(96, 1000, 3000, -1, "\xa2\xff\x37\xd3\xe2\xb8\x50\x40\x00\x5f\xff\xff\xff\x89\xcc\xff\x76\x6a\xae\xff\xcc\x00\x00\x00\x00\x00\x00\x00\x36\x52\x9d\x93\xf8\x45\x45\x45\x12\x16"));
}
# github issue 829
($sock_a, $sock_b) = new_call([qw(198.51.100.1 7316)], [qw(198.51.100.3 7318)]);

@ -56,6 +56,9 @@ for my $key (@tag_keys) {
"TAG $tag_id MEDIA $stream->{media_id} COMPONENT $stream->{component} ".
"FLAGS 0");
if ($ARGV[2]) {
if ($ARGV[3]) {
put_meta("MEDIA $stream->{media_id} PTIME $ARGV[3]", '');
}
put_meta("MEDIA $stream->{media_id} PAYLOAD TYPE $ARGV[1]", $ARGV[2]);
}
my @ret = msg_ret(7, '', 'I I I I',

Loading…
Cancel
Save