Browse Source

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
commit
228d822a71
13 changed files with 299 additions and 14 deletions
  1. +3
    -0
      README.md
  2. +4
    -2
      daemon/codec.c
  3. +2
    -0
      daemon/recording.c
  4. +120
    -5
      lib/codeclib.c
  5. +3
    -2
      lib/codeclib.h
  6. +2
    -2
      recording-daemon/decoder.c
  7. +1
    -1
      recording-daemon/decoder.h
  8. +20
    -0
      recording-daemon/metafile.c
  9. +2
    -1
      recording-daemon/packet.c
  10. +2
    -0
      recording-daemon/types.h
  11. +1
    -1
      t/amr-decode-test.c
  12. +136
    -0
      t/auto-daemon-tests.pl
  13. +3
    -0
      utils/kernel-intercept-pcap-replay.pl

+ 3
- 0
README.md View File

@ -993,6 +993,9 @@ Optionally included keys are:
e.g. `opus/48000/2/32000`. In this case, all format parameters (clock rate, e.g. `opus/48000/2/32000`. In this case, all format parameters (clock rate,
channels) must also be specified. 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` 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 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` *rtpengine* will treat this codec the same as if it had been used with the `offer`


+ 4
- 2
daemon/codec.c View File

@ -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) { struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct call_media *media) {
str codec_fmt = *codec_str; 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, '/')) if (str_token_sep(&codec, &codec_fmt, '/'))
return NULL; return NULL;
str_token_sep(&parms, &codec_fmt, '/'); str_token_sep(&parms, &codec_fmt, '/');
str_token_sep(&chans, &codec_fmt, '/'); str_token_sep(&chans, &codec_fmt, '/');
str_token_sep(&opts, &codec_fmt, '/'); str_token_sep(&opts, &codec_fmt, '/');
str_token_sep(&extra_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 clockrate = str_to_i(&parms, 0);
int channels = str_to_i(&chans, 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->channels = channels;
ret->bitrate = bitrate; ret->bitrate = bitrate;
ret->ptime = ptime; ret->ptime = ptime;
ret->format_parameters = STR_EMPTY;
ret->format_parameters = fmt_params;
const codec_def_t *def = codec_find(&ret->encoding, 0); const codec_def_t *def = codec_find(&ret->encoding, 0);
ret->codec_def = def; 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, 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); &ch->encoder_format, &h->source_pt.format_parameters);
if (!ch->decoder) if (!ch->decoder)
goto err; goto err;


+ 2
- 0
daemon/recording.c View File

@ -783,6 +783,8 @@ static void setup_media_proc(struct call_media *media) {
if (!recording) if (!recording)
return; 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); GList *pltypes = g_hash_table_get_values(media->codecs_recv);
for (GList *l = pltypes; l; l = l->next) { for (GList *l = pltypes; l; l = l->next) {


+ 120
- 5
lib/codeclib.c View File

@ -42,6 +42,9 @@ static packetizer_f packetizer_amr;
static format_init_f opus_init; static format_init_f opus_init;
static set_enc_options_f opus_set_enc_options; 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_enc_options_f amr_set_enc_options;
static set_dec_options_f amr_set_dec_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 void avc_encoder_close(encoder_t *enc);
static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out); 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 const char *dtmf_decoder_init(decoder_t *, const str *);
static int dtmf_decoder_input(decoder_t *dec, const str *data, GQueue *out); 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_input = avc_encoder_input,
.encoder_close = avc_encoder_close, .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 = { static const codec_type_t codec_type_amr = {
.def_init = avc_def_init, .def_init = avc_def_init,
.decoder_init = avc_decoder_init, .decoder_init = avc_decoder_init,
@ -242,11 +255,14 @@ static codec_def_t __codec_defs[] = {
.avcodec_id = AV_CODEC_ID_ILBC, .avcodec_id = AV_CODEC_ID_ILBC,
.default_clockrate = 8000, .default_clockrate = 8000,
.default_channels = 1, .default_channels = 1,
.default_ptime = 20,
.default_ptime = 30,
.default_fmtp = "mode=30",
//.default_bitrate = 15200, //.default_bitrate = 15200,
.packetizer = packetizer_passthrough, .packetizer = packetizer_passthrough,
.media_type = MT_AUDIO, .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", .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 str *fmtp)
{ {
const char *err; 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; ret->out_format = ret->in_format;
if (resample_fmt) if (resample_fmt)
ret->out_format = *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); err = def->codec_type->decoder_init(ret, fmtp);
if (err) if (err)
@ -1358,6 +1378,101 @@ static void opus_set_enc_options(encoder_t *enc, const str *fmtp) {
// XXX additional opus options // 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);
}


+ 3
- 2
lib/codeclib.h View File

@ -150,6 +150,7 @@ struct decoder_s {
unsigned long rtp_ts; unsigned long rtp_ts;
uint64_t pts; uint64_t pts;
int ptime;
}; };
struct encoder_s { 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); 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); const str *fmtp);
void decoder_close(decoder_t *dec); void decoder_close(decoder_t *dec);
int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts, int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts,


+ 2
- 2
recording-daemon/decoder.c View File

@ -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; str name;
char *slash = strchr(payload_str, '/'); char *slash = strchr(payload_str, '/');
if (!slash) { 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; 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) if (!dec)
return NULL; return NULL;
decode_t *deco = g_slice_alloc0(sizeof(decode_t)); decode_t *deco = g_slice_alloc0(sizeof(decode_t));


+ 1
- 1
recording-daemon/decoder.h View File

@ -8,7 +8,7 @@
extern int resample_audio; 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 *); int decoder_input(decode_t *, const str *, unsigned long ts, ssrc_t *);
void decoder_free(decode_t *); void decoder_free(decode_t *);


+ 20
- 0
recording-daemon/metafile.c View File

@ -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); 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) { if (payload_num >= 128) {
ilog(LOG_ERR, "Payload type number %u is invalid", payload_num); ilog(LOG_ERR, "Payload type number %u is invalid", payload_num);
return; 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); pthread_mutex_lock(&mf->payloads_lock);
mf->payload_types[payload_num] = g_string_chunk_insert(mf->gsc, mf->payload_types[payload_num] = g_string_chunk_insert(mf->gsc,
payload_type); payload_type);
mf->payload_ptimes[payload_num] = ptime;
pthread_mutex_unlock(&mf->payloads_lock); 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 // mf is locked
static void meta_metadata(metafile_t *mf, char *content) { static void meta_metadata(metafile_t *mf, char *content) {
mf->metadata = g_string_chunk_insert(mf->gsc, 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) { static void meta_section(metafile_t *mf, char *section, char *content, unsigned long len) {
unsigned long lu; unsigned long lu;
unsigned int u; unsigned int u;
int i;
if (!strcmp(section, "CALL-ID")) if (!strcmp(section, "CALL-ID"))
mf->call_id = g_string_chunk_insert(mf->gsc, content); 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); meta_stream_details(mf, lu, content);
else if (sscanf_match(section, "MEDIA %lu PAYLOAD TYPE %u", &lu, &u) == 2) else if (sscanf_match(section, "MEDIA %lu PAYLOAD TYPE %u", &lu, &u) == 2)
meta_rtp_payload_type(mf, lu, u, content); 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) else if (sscanf_match(section, "TAG %lu", &lu) == 1)
tag_name(mf, lu, content); tag_name(mf, lu, content);
else if (sscanf_match(section, "LABEL %lu", &lu) == 1) else if (sscanf_match(section, "LABEL %lu", &lu) == 1)


+ 2
- 1
recording-daemon/packet.c View File

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


+ 2
- 0
recording-daemon/types.h View File

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


+ 1
- 1
t/amr-decode-test.c View File

@ -51,7 +51,7 @@ static void do_test_amr_xx(const char *file, int line,
str_init(&fmtp_str, fmtp_s); str_init(&fmtp_str, fmtp_s);
fmtp = &fmtp_str; 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); assert(d);
const str data = { data_s, data_len }; const str data = { data_s, data_len };
int ret = decoder_input_data(d, &data, 1, frame_cb, &expect_s, &expect_len); int ret = decoder_input_data(d, &data, 1, frame_cb, &expect_s, &expect_len);


+ 136
- 0
t/auto-daemon-tests.pl View File

@ -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 # github issue 829
($sock_a, $sock_b) = new_call([qw(198.51.100.1 7316)], [qw(198.51.100.3 7318)]); ($sock_a, $sock_b) = new_call([qw(198.51.100.1 7316)], [qw(198.51.100.3 7318)]);


+ 3
- 0
utils/kernel-intercept-pcap-replay.pl View File

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


Loading…
Cancel
Save