TT#112700 rework codec offer/answer routine

Complete overhaul of the codec handling code:

*) obsolete flags `asymmetric codecs`, `symmetric codecs`, `reorder
codecs`

*) support proper codec offer/answer

*) split codec manipulation (strip/offer/accept/etc) into separate
functions for clarity and better code maintenance

*) fully update codec handlers in both directions after an answer

*) explicit allocation and handling of codecs and payload types in a
codec_store object

*) improve codec matchup logic during answer

*) more explicit handling of supplemental codecs (CN/DTMF)

*) remove now obsolete hacks for handling certain use cases

Change-Id: I996705ba8fe339524c2f70e6bb0fd854f9a1f4fb
pull/1295/head
Richard Fuchs 4 years ago
parent 9b6c69e524
commit 1d387b98ef

@ -734,69 +734,7 @@ Optionally included keys are:
- `always transcode`
When transcoding is in use, *rtpengine* will normally match up the codecs offered with
one side with the codecs offered by the other side, and engage the transcoding engine
only for codec pairs that are not supported by both sides. With this flag present,
*rtpengine* will skip the codec match-up routine and always trancode any received media
to the first (highest priority) codec offered by the other side that is supported for
transcoding. Using this flag engages the transcoding engine even if no other
`transcoding` flags are present. Unlike other transcoding options, this one is directional,
which means that it's applied only to the one side doing the signalling that is being
handled (i.e. the side doing the `offer` or the `answer`).
- `asymmetric codecs`
This flag is relevant to transcoding scenarios. By default, if an RTP client rejects a
codec that was offered to it (by not including it in the answer SDP), *rtpengine* will
assume that this client will also not send this codec (in addition to not wishing to
receive it). With this flag given, *rtpengine* will not make this assumption, meaning
that *rtpengine* will expect to potentially receive a codec from an RTP client even if
that RTP client rejected this codec in its answer SDP.
The effective difference is that when *rtpengine* is instructed to offer a new codec for
transcoding to an RTP client, and then this RTP client rejects this codec, by default
*rtpengine* is then able to shut down its transcoding engine and revert to non-transcoding
operation for this call. With this flag given however, *rtpengine* would not be able
to shut down its transcoding engine in this case, resulting in potentially different media
flow, and potentially transcoding media when it otherwise would not have to.
This flag should be given as part of the `answer` message.
- `symmetric codecs`
This flag instructs *rtpengine* to honour the list of codecs accepted by answer, including
their order, and match them up with the list of codecs that *rtpengine* itself produces
when transcoding. It must be using in an `answer` message and is ignored in an `offer`.
By default, any supported codec that was originally offered will be accepted by
*rtpengine* when transcoding, and the first codec listed will be used as output codec,
even if neither this codec nor its transcoded counterpart was accepted by the answer.
With this flag given, *rtpengine* will prefer the codecs listed in the answer over
the codecs listed in the offer and re-order the answer accordingly. This can lead to
a high-priority codec given in the offer to be listed as low-priority codec in the
answer, and vice versa. On the other hand, it can lead to the transcoding engine to be
disabled when it isn't needed.
For example: The original offer lists codecs `PCMA` and `opus`. *Rtpengine* is instructed
to add `G722` as a transcoded codec in the offer, and so the offer produced by
*rtpengine* lists `PCMA`, `opus`, and `G722`. If *rtpengine* were to receive any
G.722 media, it would transcode it to PCMA as this is the codec preferred by the
offer. The answer now accepts `opus` and rejects the other two codecs. Without this
flag, the answer produced by *rtpengine* would contain both `PCMA` and `opus`, because
receiving G.722 would still be a possibility and so would have to be transcoded to
PCMA. With this flag however, *rtpengine* honours the single accepted codec from the
answer and so is able to eliminate PCMA from its own answer as it's not needed.
- `reorder codecs`
This flag adds an additional stage in the processing of the `answer` codecs. Instead of
accepting codecs in the same order that they were offered, reorder the list of codecs
to match the codecs on the opposite (answer) side. This can avoid asymmetric codec flow
in certain cases, at the cost of the answer message possibly listing codecs in a different
order from the offer message (which then could be suppressed using `single codec`).
The config option `reorder-codecs` can be set to make this the default behaviour for
all answer messages.
Legacy flag, synonymous to `codec-accept=all`.
- `single codec`

@ -745,21 +745,11 @@ void call_free(void) {
void payload_type_free(struct rtp_payload_type *p) {
g_queue_clear(&p->rtcp_fb);
g_slice_free1(sizeof(*p), p);
}
struct call_media *call_media_new(struct call *call) {
struct call_media *med;
med = uid_slice_alloc0(med, &call->medias);
med->call = call;
med->codecs_recv = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
med->codecs_send = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
med->codec_names_recv = g_hash_table_new_full(str_case_hash, str_case_equal, free,
(void (*)(void*)) g_queue_free);
med->codec_names_send = g_hash_table_new_full(str_case_hash, str_case_equal, free,
(void (*)(void*)) g_queue_free);
codec_store_init(&med->codecs, med);
return med;
}
@ -804,7 +794,7 @@ static struct call_media *__get_media(struct call_monologue *ml, GList **it, con
med->monologue = ml;
med->index = sp->index;
call_str_cpy(ml->call, &med->type, &sp->type);
med->type_id = codec_get_type(&med->type);
med->type_id = sp->type_id;
g_queue_push_tail(&ml->medias, med);
@ -1160,10 +1150,11 @@ int __init_stream(struct packet_stream *ps) {
return 0;
}
void __rtp_stats_update(GHashTable *dst, GHashTable *src) {
void __rtp_stats_update(GHashTable *dst, struct codec_store *cs) {
struct rtp_stats *rs;
struct rtp_payload_type *pt;
GList *values, *l;
GHashTable *src = cs->codecs;
/* "src" is a call_media->codecs table, while "dst" is a
* packet_stream->rtp_stats table */
@ -1208,7 +1199,7 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru
a->rtp_sink = a;
PS_SET(a, RTP); /* XXX technically not correct, could be udptl too */
__rtp_stats_update(a->rtp_stats, A->codecs_recv);
__rtp_stats_update(a->rtp_stats, &A->codecs);
if (sp) {
__fill_stream(a, &sp->rtp_endpoint, port_off, sp, flags);
@ -2135,6 +2126,89 @@ static void __update_media_protocol(struct call_media *media, struct call_media
}
}
void codecs_offer_answer(struct call_media *media, struct call_media *other_media,
struct stream_params *sp, struct sdp_ng_flags *flags)
{
if (!flags || flags->opmode != OP_ANSWER) {
// offer
ilogs(codec, LOG_DEBUG, "Updating receiver side codecs for offerer " STR_FORMAT " #%u",
STR_FMT(&other_media->monologue->tag),
other_media->index);
codec_store_populate(&other_media->codecs, &sp->codecs, flags->codec_set);
codec_store_strip(&other_media->codecs, &flags->codec_strip, flags->codec_except);
codec_store_offer(&other_media->codecs, &flags->codec_offer, &sp->codecs);
if (!other_media->codecs.strip_full)
codec_store_offer(&other_media->codecs, &flags->codec_transcode, &sp->codecs);
codec_store_accept(&other_media->codecs, &flags->codec_accept, NULL);
codec_store_accept(&other_media->codecs, &flags->codec_consume, &sp->codecs);
codec_store_track(&other_media->codecs, &flags->codec_mask);
// we don't update the answerer side if the offer is not RTP but is going
// to RTP (i.e. T.38 transcoding) - instead we leave the existing codec list
// intact
int update_answerer = 1;
if (proto_is_rtp(media->protocol) && !proto_is_rtp(other_media->protocol))
update_answerer = 0;
if (update_answerer) {
// update/create answer/receiver side
ilogs(codec, LOG_DEBUG, "Updating receiver side codecs for answerer " STR_FORMAT " #%u",
STR_FMT(&media->monologue->tag),
media->index);
codec_store_populate(&media->codecs, &sp->codecs, NULL);
}
codec_store_strip(&media->codecs, &flags->codec_strip, flags->codec_except);
codec_store_strip(&media->codecs, &flags->codec_consume, flags->codec_except);
codec_store_strip(&media->codecs, &flags->codec_mask, flags->codec_except);
codec_store_offer(&media->codecs, &flags->codec_offer, &sp->codecs);
codec_store_transcode(&media->codecs, &flags->codec_transcode, &sp->codecs);
codec_store_synthesise(&media->codecs, &other_media->codecs);
// update supp codecs based on actions so far
codec_tracker_update(&media->codecs);
// set up handlers
codec_handlers_update(media, other_media, flags, sp);
// updating the handlers may have removed some codecs, so run update the supp codecs again
codec_tracker_update(&media->codecs);
// finally set up handlers again based on final results
codec_handlers_update(media, other_media, flags, sp);
}
else {
// answer
ilogs(codec, LOG_DEBUG, "Updating receiver side codecs for answerer " STR_FORMAT " #%u",
STR_FMT(&other_media->monologue->tag),
other_media->index);
codec_store_populate(&other_media->codecs, &sp->codecs, flags->codec_set);
codec_store_strip(&other_media->codecs, &flags->codec_strip, flags->codec_except);
codec_store_offer(&other_media->codecs, &flags->codec_offer, &sp->codecs);
// update callee side codec handlers again (second pass after the offer) as we
// might need to update some handlers, e.g. when supplemental codecs have been
// rejected
codec_handlers_update(other_media, media, NULL, NULL);
// finally set up our caller side codecs
ilogs(codec, LOG_DEBUG, "Codec answer for " STR_FORMAT " #%u",
STR_FMT(&other_media->monologue->tag),
other_media->index);
codec_store_answer(&media->codecs, &other_media->codecs, flags);
// set up handlers
codec_handlers_update(media, other_media, flags, sp);
// updating the handlers may have removed some codecs, so run update the supp codecs again
codec_tracker_update(&media->codecs);
codec_tracker_update(&other_media->codecs);
// finally set up handlers again based on final results
codec_handlers_update(media, other_media, flags, sp);
codec_handlers_update(other_media, media, NULL, NULL);
}
}
/* called with call->master_lock held in W */
int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
struct sdp_ng_flags *flags)
@ -2305,10 +2379,7 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
call_str_cpy(call, &media->format_str, &sp->format_str);
}
codec_tracker_init(media);
codec_rtp_payload_types(media, other_media, &sp->rtp_payload_types, flags);
codec_handlers_update(media, other_media, flags, sp);
codec_tracker_finish(media, other_media);
codecs_offer_answer(media, other_media, sp, flags);
/* send and recv are from our POV */
bf_copy_same(&media->media_flags, &sp->sp_flags,
@ -2483,7 +2554,7 @@ const struct rtp_payload_type *__rtp_stats_codec(struct call_media *m) {
if (atomic64_get(&rtp_s->packets) == 0)
goto out;
rtp_pt = rtp_payload_type(rtp_s->payload_type, m->codecs_recv);
rtp_pt = rtp_payload_type(rtp_s->payload_type, &m->codecs);
out:
g_list_free(values);
@ -2793,12 +2864,7 @@ void call_media_free(struct call_media **mdp) {
crypto_params_sdes_queue_clear(&md->sdes_out);
g_queue_clear(&md->streams);
g_queue_clear(&md->endpoint_maps);
g_hash_table_destroy(md->codecs_recv);
g_hash_table_destroy(md->codecs_send);
g_hash_table_destroy(md->codec_names_recv);
g_hash_table_destroy(md->codec_names_send);
g_queue_clear_full(&md->codecs_prefs_recv, (GDestroyNotify) payload_type_free);
g_queue_clear_full(&md->codecs_prefs_send, (GDestroyNotify) payload_type_free);
codec_store_cleanup(&md->codecs);
codec_handlers_free(md);
codec_handler_free(&md->t38_handler);
t38_gateway_put(&md->t38_gateway);

@ -303,22 +303,6 @@ static void streams_parse(const char *s, GQueue *q) {
pcre_multi_match(streams_re, streams_ree, s, 3, streams_parse_func, &i, q);
}
/* XXX move these somewhere else */
static void rtp_pt_free(void *p) {
g_slice_free1(sizeof(struct rtp_payload_type), p);
}
static void sp_free(void *p) {
struct stream_params *s = p;
g_queue_clear_full(&s->rtp_payload_types, rtp_pt_free);
ice_candidates_free(&s->ice_candidates);
crypto_params_sdes_queue_clear(&s->sdes_params);
g_slice_free1(sizeof(*s), s);
}
static void streams_free(GQueue *q) {
g_queue_clear_full(q, sp_free);
}
static str *call_request_lookup_tcp(char **out, enum call_opmode opmode) {
@ -364,7 +348,7 @@ static str *call_request_lookup_tcp(char **out, enum call_opmode opmode) {
out2:
rwlock_unlock_w(&c->master_lock);
streams_free(&s);
sdp_streams_free(&s);
redis_update_onekey(c, rtpe_redis_write);
@ -855,16 +839,16 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) {
break;
case CSH_LOOKUP("always-transcode"):;
static const str str_all = STR_CONST_INIT("all");
call_ng_flags_str_ht(out, (str *) &str_all, &out->codec_accept);
call_ng_flags_codec_list(out, (str *) &str_all, &out->codec_accept);
break;
case CSH_LOOKUP("asymmetric-codecs"):
out->asymmetric_codecs = 1;
ilog(LOG_INFO, "Ignoring obsolete flag `asymmetric-codecs`");
break;
case CSH_LOOKUP("symmetric-codecs"):
out->symmetric_codecs = 1;
ilog(LOG_INFO, "Ignoring obsolete flag `symmetric-codecs`");
break;
case CSH_LOOKUP("reorder-codecs"):
out->reorder_codecs = 1;
ilog(LOG_INFO, "Ignoring obsolete flag `reorder-codecs`");
break;
case CSH_LOOKUP("single-codec"):
out->single_codec = 1;
@ -895,7 +879,7 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) {
return;
if (call_ng_flags_prefix(out, s, "OSRTP-", ng_osrtp_option, NULL))
return;
if (call_ng_flags_prefix(out, s, "codec-strip-", call_ng_flags_str_ht,
if (call_ng_flags_prefix(out, s, "codec-strip-", call_ng_flags_codec_list,
&out->codec_strip))
return;
if (call_ng_flags_prefix(out, s, "codec-offer-", call_ng_flags_codec_list,
@ -912,7 +896,7 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) {
if (call_ng_flags_prefix(out, s, "codec-transcode-", call_ng_flags_codec_list,
&out->codec_transcode))
return;
if (call_ng_flags_prefix(out, s, "codec-mask-", call_ng_flags_str_ht,
if (call_ng_flags_prefix(out, s, "codec-mask-", call_ng_flags_codec_list,
&out->codec_mask))
return;
if (call_ng_flags_prefix(out, s, "T38-", ng_t38_option, NULL))
@ -923,10 +907,10 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) {
if (call_ng_flags_prefix(out, s, "codec-set-", call_ng_flags_str_ht_split,
&out->codec_set))
return;
if (call_ng_flags_prefix(out, s, "codec-accept-", call_ng_flags_str_ht,
if (call_ng_flags_prefix(out, s, "codec-accept-", call_ng_flags_codec_list,
&out->codec_accept))
return;
if (call_ng_flags_prefix(out, s, "codec-consume-", call_ng_flags_str_ht,
if (call_ng_flags_prefix(out, s, "codec-consume-", call_ng_flags_codec_list,
&out->codec_consume))
return;
#endif
@ -1133,16 +1117,16 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
}
if ((dict = bencode_dictionary_get_expect(input, "codec", BENCODE_DICTIONARY))) {
call_ng_flags_list(out, dict, "strip", call_ng_flags_str_ht, &out->codec_strip);
call_ng_flags_list(out, dict, "strip", call_ng_flags_codec_list, &out->codec_strip);
call_ng_flags_list(out, dict, "offer", call_ng_flags_codec_list, &out->codec_offer);
call_ng_flags_list(out, dict, "except", call_ng_flags_str_ht, &out->codec_except);
#ifdef WITH_TRANSCODING
if (opmode == OP_OFFER) {
call_ng_flags_list(out, dict, "transcode", call_ng_flags_codec_list, &out->codec_transcode);
call_ng_flags_list(out, dict, "mask", call_ng_flags_str_ht, &out->codec_mask);
call_ng_flags_list(out, dict, "mask", call_ng_flags_codec_list, &out->codec_mask);
call_ng_flags_list(out, dict, "set", call_ng_flags_str_ht_split, &out->codec_set);
call_ng_flags_list(out, dict, "accept", call_ng_flags_str_ht, &out->codec_accept);
call_ng_flags_list(out, dict, "consume", call_ng_flags_str_ht, &out->codec_consume);
call_ng_flags_list(out, dict, "accept", call_ng_flags_codec_list, &out->codec_accept);
call_ng_flags_list(out, dict, "consume", call_ng_flags_codec_list, &out->codec_consume);
}
#endif
}
@ -1180,22 +1164,18 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
}
}
static void call_ng_free_flags(struct sdp_ng_flags *flags) {
if (flags->codec_strip)
g_hash_table_destroy(flags->codec_strip);
if (flags->codec_except)
g_hash_table_destroy(flags->codec_except);
if (flags->codec_mask)
g_hash_table_destroy(flags->codec_mask);
if (flags->codec_set)
g_hash_table_destroy(flags->codec_set);
if (flags->codec_accept)
g_hash_table_destroy(flags->codec_accept);
if (flags->codec_consume)
g_hash_table_destroy(flags->codec_consume);
if (flags->sdes_no)
g_hash_table_destroy(flags->sdes_no);
g_queue_clear_full(&flags->codec_offer, free);
g_queue_clear_full(&flags->codec_transcode, free);
g_queue_clear_full(&flags->codec_strip, free);
g_queue_clear_full(&flags->codec_accept, free);
g_queue_clear_full(&flags->codec_consume, free);
g_queue_clear_full(&flags->codec_mask, free);
}
static enum load_limit_reasons call_offer_session_limit(void) {
@ -1251,7 +1231,7 @@ static enum load_limit_reasons call_offer_session_limit(void) {
}
static void fragment_free(struct sdp_fragment *frag) {
streams_free(&frag->streams);
sdp_streams_free(&frag->streams);
call_ng_free_flags(&frag->flags);
obj_put(frag->ngbuf);
g_slice_free1(sizeof(*frag), frag);
@ -1518,7 +1498,7 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t
errstr = NULL;
out:
sdp_free(&parsed);
streams_free(&streams);
sdp_streams_free(&streams);
call_ng_free_flags(&flags);
return errstr;
@ -2394,8 +2374,8 @@ const char *call_play_dtmf_ng(bencode_item_t *input, bencode_item_t *output) {
media = l->data;
if (media->type_id != MT_AUDIO)
continue;
if (!media->dtmf_injector)
continue;
// if (!media->dtmf_injector)
// continue;
goto found;
}

File diff suppressed because it is too large Load Diff

@ -120,7 +120,7 @@ int dtmf_event(struct media_packet *mp, str *payload, int clockrate) {
dtmf = (void *) payload->s;
ilog(LOG_DEBUG, "DTMF event: event %u, volume %u, end %u, duration %u",
dtmf->event, dtmf->volume, dtmf->end, dtmf->duration);
dtmf->event, dtmf->volume, dtmf->end, ntohs(dtmf->duration));
int ret = dtmf->end ? 1 : 0;
@ -277,14 +277,14 @@ static const char *dtmf_inject_pcm(struct call_media *media, struct call_monolog
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);
ch->dtmf_injector->func(ch->dtmf_injector, &packet);
// insert pause
tep.event = 0xff;
tep.duration = htons(pause_samples);
rtp.seq_num = htons(ssrc_in->parent->sequencer.seq);
media->dtmf_injector->func(media->dtmf_injector, &packet);
ch->dtmf_injector->func(ch->dtmf_injector, &packet);
// skip generated samples
uint64_t pts_offset = codec_encoder_pts(csh) - encoder_pts;
@ -352,7 +352,7 @@ const char *dtmf_inject(struct call_media *media, int code, int volume, int dura
return "No matching codec SSRC handler";
// if we don't have a DTMF payload type, we have to generate PCM
if (media->dtmf_injector->dtmf_payload_type == -1)
if (ch->dtmf_payload_type == -1 && ch->dtmf_injector)
return dtmf_inject_pcm(media, monologue, ps, ssrc_in, ch, csh, code, volume, duration, pause);
ilog(LOG_DEBUG, "Injecting RFC DTMF event #%i for %i ms (vol %i) from '" STR_FORMAT "' (media #%u) "

@ -266,7 +266,7 @@ void send_timer_push(struct send_timer *st, struct codec_packet *cp) {
int media_player_setup(struct media_player *mp, const struct rtp_payload_type *src_pt) {
// find suitable output payload type
struct rtp_payload_type *dst_pt;
for (GList *l = mp->media->codecs_prefs_send.head; l; l = l->next) {
for (GList *l = mp->media->codecs.codec_prefs.head; l; l = l->next) {
dst_pt = l->data;
ensure_codec_def(dst_pt, mp->media);
if (dst_pt->codec_def && !dst_pt->codec_def->supplemental)
@ -326,13 +326,14 @@ static int __ensure_codec_handler(struct media_player *mp, AVStream *avs) {
src_pt.encoding = src_pt.codec_def->rtpname_str;
src_pt.channels = avs->CODECPAR->channels;
src_pt.clock_rate = avs->CODECPAR->sample_rate;
codec_init_payload_type(&src_pt, mp->media);
codec_init_payload_type(&src_pt, MT_AUDIO);
if (media_player_setup(mp, &src_pt))
return -1;
mp->duration = avs->duration * 1000 * avs->time_base.num / avs->time_base.den;
payload_type_clear(&src_pt);
return 0;
}

@ -162,7 +162,7 @@ static void mqtt_ssrc_stats(struct ssrc_ctx *ssrc, JsonBuilder *json, struct cal
unsigned int clockrate = 0;
//struct codec_handler *h = codec_handler_get(ps->media, prim_pt);
struct rtp_payload_type *pt = g_hash_table_lookup(media->codecs_recv, GUINT_TO_POINTER(prim_pt));
struct rtp_payload_type *pt = g_hash_table_lookup(media->codecs.codecs, GUINT_TO_POINTER(prim_pt));
if (pt) {
json_builder_set_member_name(json, "codec");
json_builder_add_string_value(json, pt->encoding.s);

@ -813,7 +813,7 @@ static void setup_media_proc(struct call_media *media) {
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.codecs);
for (GList *l = pltypes; l; l = l->next) {
struct rtp_payload_type *pt = l->data;

@ -1437,7 +1437,7 @@ static struct rtp_payload_type *rbl_cb_plts_g(str *s, GQueue *q, struct redis_li
if (str_token(&ptype, s, '/'))
return NULL;
struct rtp_payload_type *pt = codec_make_payload_type(s, med);
struct rtp_payload_type *pt = codec_make_payload_type(s, med->type_id);
if (!pt)
return NULL;
@ -1447,12 +1447,7 @@ static struct rtp_payload_type *rbl_cb_plts_g(str *s, GQueue *q, struct redis_li
}
static int rbl_cb_plts_r(str *s, GQueue *q, struct redis_list *list, void *ptr) {
struct call_media *med = ptr;
__rtp_payload_type_add_recv(med, rbl_cb_plts_g(s, q, list, ptr), 0);
return 0;
}
static int rbl_cb_plts_s(str *s, GQueue *q, struct redis_list *list, void *ptr) {
struct call_media *med = ptr;
__rtp_payload_type_add_send(med, rbl_cb_plts_g(s, q, list, ptr));
codec_store_add_raw(&med->codecs, rbl_cb_plts_g(s, q, list, ptr));
return 0;
}
static int json_medias(struct call *c, struct redis_list *medias, JsonReader *root_reader) {
@ -1503,7 +1498,6 @@ static int json_medias(struct call *c, struct redis_list *medias, JsonReader *ro
return -1;
json_build_list_cb(NULL, c, "payload_types", i, NULL, rbl_cb_plts_r, med, root_reader);
json_build_list_cb(NULL, c, "payload_types_send", i, NULL, rbl_cb_plts_s, med, root_reader);
/* XXX dtls */
medias->ptrs[i] = med;
@ -1622,7 +1616,7 @@ static int json_link_streams(struct call *c, struct redis_list *streams,
return -1;
if (ps->media)
__rtp_stats_update(ps->rtp_stats, ps->media->codecs_recv);
__rtp_stats_update(ps->rtp_stats, &ps->media->codecs);
__init_stream(ps);
}
@ -2370,19 +2364,7 @@ char* redis_encode_json(struct call *c) {
snprintf(tmp, sizeof(tmp), "payload_types-%u", media->unique_id);
json_builder_set_member_name(builder, tmp);
json_builder_begin_array (builder);
for (m = media->codecs_prefs_recv.head; m; m = m->next) {
pt = m->data;
JSON_ADD_STRING("%u/" STR_FORMAT "/%u/" STR_FORMAT "/" STR_FORMAT "/%i/%i",
pt->payload_type, STR_FMT(&pt->encoding),
pt->clock_rate, STR_FMT(&pt->encoding_parameters),
STR_FMT(&pt->format_parameters), pt->bitrate, pt->ptime);
}
json_builder_end_array (builder);
snprintf(tmp, sizeof(tmp), "payload_types_send-%u", media->unique_id);
json_builder_set_member_name(builder, tmp);
json_builder_begin_array (builder);
for (m = media->codecs_prefs_send.head; m; m = m->next) {
for (m = media->codecs.codec_prefs.head; m; m = m->next) {
pt = m->data;
JSON_ADD_STRING("%u/" STR_FORMAT "/%u/" STR_FORMAT "/" STR_FORMAT "/%i/%i",
pt->payload_type, STR_FMT(&pt->encoding),

@ -10,6 +10,7 @@
#include "log.h"
#include "rtplib.h"
#include "ssrc.h"
#include "call.h"
@ -274,13 +275,13 @@ error:
return -1;
}
const struct rtp_payload_type *rtp_payload_type(unsigned int type, GHashTable *lookup) {
const struct rtp_payload_type *rtp_payload_type(unsigned int type, struct codec_store *cs) {
const struct rtp_payload_type *rtp_pt;
if (!lookup)
if (!cs)
return rtp_get_rfc_payload_type(type);
rtp_pt = g_hash_table_lookup(lookup, GINT_TO_POINTER(type));
rtp_pt = g_hash_table_lookup(cs->codecs, GINT_TO_POINTER(type));
if (rtp_pt)
return rtp_pt;

@ -18,6 +18,7 @@
#include "socket.h"
#include "call_interfaces.h"
#include "rtplib.h"
#include "codec.h"
struct network_address {
str network_type;
@ -64,7 +65,7 @@ struct sdp_media {
struct sdp_session *session;
str s;
str media_type;
str media_type_str;
str port;
str transport;
str formats; /* space separated */
@ -77,6 +78,7 @@ struct sdp_media {
int rr, rs;
struct sdp_attributes attributes;
GQueue format_list; /* list of slice-alloc'd str objects */
enum media_type media_type_id;
};
struct attribute_rtcp {
@ -374,11 +376,12 @@ static int parse_media(str *value_str, struct sdp_media *output) {
char *ep;
str *sp;
EXTRACT_TOKEN(media_type);
EXTRACT_TOKEN(media_type_str);
EXTRACT_TOKEN(port);
EXTRACT_TOKEN(transport);
output->formats = *value_str;
output->media_type_id = codec_get_type(&output->media_type_str);
output->port_num = strtol(output->port.s, &ep, 10);
if (ep == output->port.s)
return -1;
@ -1365,6 +1368,8 @@ static int __rtp_payload_types(struct stream_params *sp, struct sdp_media *media
s = g_hash_table_lookup(ht_fmtp, &i);
if (s)
pt->format_parameters = *s;
else
pt->format_parameters = STR_EMPTY;
GQueue *rq = g_hash_table_lookup(ht_rtcp_fb, GINT_TO_POINTER(i));
if (rq) {
// steal the list contents and free the list
@ -1379,7 +1384,8 @@ static int __rtp_payload_types(struct stream_params *sp, struct sdp_media *media
else if (!pt->ptime && ptrfc)
pt->ptime = ptrfc->ptime;
g_queue_push_tail(&sp->rtp_payload_types, pt);
codec_init_payload_type(pt, sp->type_id);
codec_store_add_raw(&sp->codecs, pt);
}
goto out;
@ -1515,6 +1521,7 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
sp = g_slice_alloc0(sizeof(*sp));
sp->index = ++num;
codec_store_init(&sp->codecs, NULL);
errstr = "No address info found for stream";
if (!flags->fragment
@ -1523,7 +1530,8 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
sp->consecutive_ports = media->port_count;
sp->protocol = transport_protocol(&media->transport);
sp->type = media->media_type;
sp->type = media->media_type_str;
sp->type_id = media->media_type_id;
memcpy(sp->direction, flags->direction, sizeof(sp->direction));
sp->desired_family = flags->address_family;
bf_set_clear(&sp->sp_flags, SP_FLAG_ASYMMETRIC, flags->asymmetric);
@ -1655,6 +1663,20 @@ error:
return -1;
}
static void sp_free(void *p) {
struct stream_params *s = p;
codec_store_cleanup(&s->codecs);
ice_candidates_free(&s->ice_candidates);
crypto_params_sdes_queue_clear(&s->sdes_params);
g_slice_free1(sizeof(*s), s);
}
void sdp_streams_free(GQueue *q) {
g_queue_clear_full(q, sp_free);
}
struct sdp_chopper *sdp_chopper_new(str *input) {
struct sdp_chopper *c = g_slice_alloc0(sizeof(*c));
c->input = input;
@ -1783,10 +1805,10 @@ static int replace_codec_list(struct sdp_chopper *chop,
if (proto_is_not_rtp(cm->protocol))
return replace_format_str(chop, media, cm);
if (cm->codecs_prefs_recv.length == 0)
if (cm->codecs.codec_prefs.length == 0)
return 0; // legacy protocol or usage error
for (GList *l = cm->codecs_prefs_recv.head; l; l = l->next) {
for (GList *l = cm->codecs.codec_prefs.head; l; l = l->next) {
struct rtp_payload_type *pt = l->data;
chopper_append_printf(chop, " %u", pt->payload_type);
}
@ -1796,7 +1818,7 @@ static int replace_codec_list(struct sdp_chopper *chop,
}
static void insert_codec_parameters(struct sdp_chopper *chop, struct call_media *cm) {
for (GList *l = cm->codecs_prefs_recv.head; l; l = l->next) {
for (GList *l = cm->codecs.codec_prefs.head; l; l = l->next) {
struct rtp_payload_type *pt = l->data;
if (!pt->encoding_with_params.len)
continue;
@ -1826,7 +1848,7 @@ static void insert_sdp_attributes(struct sdp_chopper *chop, struct call_media *c
}
static int replace_media_type(struct sdp_chopper *chop, struct sdp_media *media, struct call_media *cm) {
str *type = &media->media_type;
str *type = &media->media_type_str;
if (!cm->type.s)
return 0;
@ -2098,7 +2120,7 @@ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_media *
case ATTR_RTPMAP:
case ATTR_FMTP:
if (media->codecs_prefs_recv.length > 0)
if (media->codecs.codec_prefs.length > 0)
goto strip;
break;
case ATTR_PTIME:
@ -2108,7 +2130,7 @@ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_media *
case ATTR_RTCP_FB:
if (attr->u.rtcp_fb.payload_type == -1)
break; // leave this one alone
if (media->codecs_prefs_recv.length > 0)
if (media->codecs.codec_prefs.length > 0)
goto strip;
break;

@ -347,7 +347,7 @@ void ssrc_receiver_report(struct call_media *m, const struct ssrc_receiver_repor
goto out_nl_put;
}
const struct rtp_payload_type *rpt = rtp_payload_type(pt, m->codecs_send);
const struct rtp_payload_type *rpt = rtp_payload_type(pt, &m->codecs);
if (!rpt) {
ilog(LOG_INFO, "Invalid RTP payload type %i, discarding RTCP RR", pt);
goto out_nl_put;

@ -375,6 +375,7 @@ int t38_gateway_pair(struct call_media *t38_media, struct call_media *pcm_media,
tg->pcm_pt.encoding_with_params = tg->pcm_pt.encoding;
tg->pcm_pt.clock_rate = 8000;
tg->pcm_pt.channels = 1;
tg->pcm_pt.ptime = 20;
err = "Failed to init PCM codec";
ensure_codec_def(&tg->pcm_pt, pcm_media);
@ -467,7 +468,7 @@ void t38_gateway_start(struct t38_gateway *tg) {
return;
// only start our player only if we can send both ways
if (!tg->pcm_media->codecs_prefs_send.length)
if (!tg->pcm_media->codecs.codec_prefs.length)
return;
if (!tg->pcm_media->streams.length)
return;

@ -225,9 +225,21 @@ typedef bencode_buffer_t call_buffer_t;
struct codec_store {
GHashTable *codecs; // int payload type -> struct rtp_payload_type
GHashTable *codec_names; // codec name -> GQueue of int payload types; storage container
GQueue codec_prefs; // preference by order in SDP; storage container
GList *supp_link; // tracks location for codec_store_add_end
struct codec_tracker *tracker;
struct call_media *media;
unsigned int strip_all:1, // set by codec_store_strip
strip_full:1; // set by codec_store_strip
};
struct stream_params {
unsigned int index; /* starting with 1 */
str type;
enum media_type type_id;
struct endpoint rtp_endpoint;
struct endpoint rtcp_endpoint;
unsigned int consecutive_ports;
@ -238,7 +250,7 @@ struct stream_params {
sockfamily_t *desired_family;
struct dtls_fingerprint fingerprint;
unsigned int sp_flags;
GQueue rtp_payload_types; /* slice-alloc'd */
struct codec_store codecs;
GQueue ice_candidates; /* slice-alloc'd */
str ice_ufrag;
str ice_pwd;
@ -336,27 +348,16 @@ struct call_media {
GQueue streams; /* normally RTP + RTCP */
GQueue endpoint_maps;
// what we say we can receive (outgoing SDP):
GHashTable *codecs_recv; // int payload type -> struct rtp_payload_type
GHashTable *codec_names_recv; // codec name -> GQueue of int payload types; storage container
GQueue codecs_prefs_recv; // preference by order in SDP; storage container
// what we can send, taken from received SDP:
GHashTable *codecs_send; // int payload type -> struct rtp_payload_type
GHashTable *codec_names_send; // codec name -> GQueue of int payload types; storage container
GQueue codecs_prefs_send; // storage container
struct codec_tracker *codec_tracker;
struct codec_store codecs;
GQueue sdp_attributes; // str_sprintf()
GHashTable *codec_handlers; // int payload type -> struct codec_handler
// XXX combine this with 'codecs_recv' hash table?
// XXX combine this with 'codecs' hash table?
GQueue codec_handlers_store; // storage for struct codec_handler
struct codec_handler *codec_handler_cache;
struct rtcp_handler *rtcp_handler;
struct rtcp_timer *rtcp_timer; // master lock for scheduling purposes
struct mqtt_timer *mqtt_timer; // master lock for scheduling purposes
struct codec_handler *dtmf_injector;
//struct codec_handler *dtmf_injector;
struct t38_gateway *t38_gateway;
struct codec_handler *t38_handler;
#ifdef WITH_TRANSCODING
@ -402,6 +403,7 @@ struct call_monologue {
unsigned int block_dtmf:1;
unsigned int block_media:1;
unsigned int rec_forwarding:1;
unsigned int inject_dtmf:1;
};
struct call_iterator_list {
@ -523,6 +525,8 @@ struct call_monologue *call_get_mono_dialogue(struct call *call, const str *from
const str *viabranch);
struct call *call_get(const str *callid);
int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, struct sdp_ng_flags *flags);
void codecs_offer_answer(struct call_media *media, struct call_media *other_media,
struct stream_params *sp, struct sdp_ng_flags *flags);
int call_delete_branch(const str *callid, const str *branch,
const str *fromtag, const str *totag, bencode_item_t *output, int delete_delay);
void call_destroy(struct call *);
@ -538,8 +542,7 @@ int call_stream_address46(char *o, struct packet_stream *ps, enum stream_address
void add_total_calls_duration_in_interval(struct timeval *interval_tv);
void payload_type_free(struct rtp_payload_type *p);
void __rtp_stats_update(GHashTable *dst, GHashTable *src);
void __rtp_stats_update(GHashTable *dst, struct codec_store *);
int __init_stream(struct packet_stream *ps);
void call_stream_crypto_reset(struct packet_stream *ps);

@ -38,13 +38,13 @@ struct sdp_ng_flags {
str label;
str address;
sockaddr_t xmlrpc_callback;
GHashTable *codec_strip;
GQueue codec_strip;
GHashTable *codec_except;
GQueue codec_offer;
GQueue codec_transcode;
GHashTable *codec_mask;
GHashTable *codec_accept;
GHashTable *codec_consume;
GQueue codec_mask;
GQueue codec_accept;
GQueue codec_consume;
GHashTable *codec_set;
int ptime,
rev_ptime;
@ -107,9 +107,6 @@ struct sdp_ng_flags {
debug:1,
loop_protect:1,
original_sendrecv:1,
asymmetric_codecs:1,
symmetric_codecs:1,
reorder_codecs:1,
single_codec:1,
inject_dtmf:1,
t38_decode:1,

@ -23,6 +23,7 @@ struct supp_codec_tracker;
struct rtcp_timer;
struct mqtt_timer;
struct call;
struct codec_store;
typedef int codec_handler_func(struct codec_handler *, struct media_packet *);
@ -34,12 +35,13 @@ struct codec_handler {
int dtmf_payload_type;
int cn_payload_type;
codec_handler_func *func;
unsigned int passthrough:1;
unsigned int kernelize:1;
unsigned int transcoder:1;
unsigned int dtmf_scaler:1;
unsigned int pcm_dtmf_detect:1;
struct ssrc_hash *ssrc_hash;
struct codec_handler *input_handler; // == main handler for supp codecs
struct codec_handler *output_handler; // == self, or other PT handler
struct call_media *media;
#ifdef WITH_TRANSCODING
@ -49,6 +51,8 @@ struct codec_handler {
// for media playback
struct codec_ssrc_handler *ssrc_handler;
// for DTMF injection
struct codec_handler *dtmf_injector;
// stats entry
char *stats_chain;
@ -78,28 +82,38 @@ struct codec_handler *codec_handler_get(struct call_media *, int payload_type);
void codec_handlers_free(struct call_media *);
struct codec_handler *codec_handler_make_playback(const struct rtp_payload_type *src_pt,
const struct rtp_payload_type *dst_pt, unsigned long ts, struct call_media *);
void ensure_codec_def(struct rtp_payload_type *pt, struct call_media *media);
void codec_calc_jitter(struct ssrc_ctx *, unsigned long ts, unsigned int clockrate, const struct timeval *);
void codec_store_cleanup(struct codec_store *cs);
void codec_store_init(struct codec_store *cs, struct call_media *);
void codec_store_populate(struct codec_store *, struct codec_store *, GHashTable *);
void codec_store_add_raw(struct codec_store *cs, struct rtp_payload_type *pt);
void codec_store_strip(struct codec_store *, GQueue *strip, GHashTable *except);
void codec_store_offer(struct codec_store *, GQueue *, struct codec_store *);
void codec_store_accept(struct codec_store *, GQueue *, struct codec_store *);
void codec_store_track(struct codec_store *, GQueue *);
void codec_store_transcode(struct codec_store *, GQueue *, struct codec_store *);
void codec_store_answer(struct codec_store *dst, struct codec_store *src, struct sdp_ng_flags *flags);
void codec_store_synthesise(struct codec_store *dst, struct codec_store *opposite);
void codec_add_raw_packet(struct media_packet *mp, unsigned int clockrate);
void codec_packet_free(void *);
void codec_rtp_payload_types(struct call_media *media, struct call_media *other_media,
GQueue *types, struct sdp_ng_flags *flags);
void payload_type_free(struct rtp_payload_type *p);
struct rtp_payload_type *rtp_payload_type_dup(const struct rtp_payload_type *pt);
// special return value `(void *) 0x1` to signal type mismatch
struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct call_media *media);
void codec_init_payload_type(struct rtp_payload_type *, struct call_media *);
struct rtp_payload_type *codec_make_payload_type(const str *codec_str, enum media_type);
// used by redis
void __rtp_payload_type_add_recv(struct call_media *media, struct rtp_payload_type *pt, int supp_check);
void __rtp_payload_type_add_send(struct call_media *other_media, struct rtp_payload_type *pt);
// handle string allocation
void codec_init_payload_type(struct rtp_payload_type *, enum media_type);
void payload_type_clear(struct rtp_payload_type *p);
#ifdef WITH_TRANSCODING
void ensure_codec_def(struct rtp_payload_type *pt, struct call_media *media);
void codec_handler_free(struct codec_handler **handler);
void codec_handlers_update(struct call_media *receiver, struct call_media *sink, const struct sdp_ng_flags *,
const struct stream_params *);
@ -108,8 +122,7 @@ 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);
void codec_tracker_init(struct call_media *);
void codec_tracker_finish(struct call_media *, struct call_media *);
void codec_tracker_update(struct codec_store *);
void codec_handlers_stop(GQueue *);
#else
@ -117,9 +130,9 @@ void codec_handlers_stop(GQueue *);
INLINE void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
const struct sdp_ng_flags *flags, const struct stream_params *sp) { }
INLINE void codec_handler_free(struct codec_handler **handler) { }
INLINE void codec_tracker_init(struct call_media *m) { }
INLINE void codec_tracker_finish(struct call_media *m, struct call_media *mm) { }
INLINE void codec_tracker_update(struct codec_store *cs) { }
INLINE void codec_handlers_stop(GQueue *q) { }
INLINE void ensure_codec_def(struct rtp_payload_type *pt, struct call_media *media) { }
#endif

@ -8,6 +8,7 @@
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
#include "compat.h"

@ -13,12 +13,13 @@ struct rtp_header;
struct ssrc_hash;
enum ssrc_dir;
struct ssrc_ctx;
struct codec_store;
const struct rtp_payload_type *rtp_payload_type(unsigned int, GHashTable *);
const struct rtp_payload_type *rtp_payload_type(unsigned int, struct codec_store *);
int rtp_avp2savp(str *, struct crypto_context *, struct ssrc_ctx *);
int rtp_savp2avp(str *, struct crypto_context *, struct ssrc_ctx *);

@ -20,6 +20,7 @@ void sdp_init(void);
int sdp_parse(str *body, GQueue *sessions, const struct sdp_ng_flags *);
int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *);
void sdp_streams_free(GQueue *);
void sdp_free(GQueue *sessions);
int sdp_replace(struct sdp_chopper *, GQueue *, struct call_monologue *, struct sdp_ng_flags *);
int sdp_is_duplicate(GQueue *sessions);

@ -1303,6 +1303,9 @@ int encoder_config_fmtp(encoder_t *enc, const codec_def_t *def, int bitrate, int
encoder_close(enc);
if (ptime <= 0)
ptime = 20;
enc->requested_format = *requested_format;
enc->def = def;
enc->ptime = ptime / def->clockrate_mult;

@ -32,8 +32,10 @@ struct rtp_payload_type {
int bitrate;
const codec_def_t *codec_def;
GList *prefs_link; // link in `codec_prefs` list
unsigned int for_transcoding:1;
unsigned int accepted:1;
};

@ -238,19 +238,20 @@ INLINE str *str_init_dup(str *out, const char *s) {
return out;
}
INLINE str *str_init_dup_str(str *out, const str *s) {
if (!s || !s->len) {
if (!s) {
*out = STR_NULL;
return out;
}
out->s = malloc(s->len + 1);
memcpy(out->s, s->s, s->len);
out->s[s->len] = '\0';
char *buf = malloc(s->len + 1);
memcpy(buf, s->s, s->len);
buf[s->len] = '\0';
out->len = s->len;
out->s = buf;
return out;
}
INLINE void str_free_dup(str *out) {
if (!out)
return ;
return;
if (out->s)
free(out->s);

@ -85,7 +85,7 @@ COMMONOBJS= str.o auxlib.o rtplib.o loglib.o
include ../lib/common.Makefile
.PHONY: all-tests unit-tests daemon-tests all-daemon-tests \
daemon-tests-main daemon-tests-jb daemon-tests-reorder daemon-tests-dtx daemon-tests-dtx-cn
daemon-tests-main daemon-tests-jb daemon-tests-dtx daemon-tests-dtx-cn
TESTS= test-bitstr aes-crypt aead-aes-crypt test-const_str_hash.strhash
ifeq ($(with_transcoding),yes)
@ -111,7 +111,7 @@ daemon-tests: tests-preload.so
$(MAKE) -C ../daemon
$(MAKE) all-daemon-tests
all-daemon-tests: daemon-tests-main daemon-tests-jb daemon-tests-reorder daemon-tests-dtx daemon-tests-dtx-cn
all-daemon-tests: daemon-tests-main daemon-tests-jb daemon-tests-dtx daemon-tests-dtx-cn
daemon-tests-main:
rm -rf fake-$@-sockets
@ -129,14 +129,6 @@ daemon-tests-jb:
test "$$(ls fake-$@-sockets)" = ""
rmdir fake-$@-sockets
daemon-tests-reorder:
rm -rf fake-$@-sockets
mkdir fake-$@-sockets
LD_PRELOAD=../t/tests-preload.so RTPE_BIN=../daemon/rtpengine TEST_SOCKET_PATH=./fake-$@-sockets \
perl -I../perl auto-daemon-tests-reorder.pl
test "$$(ls fake-$@-sockets)" = ""
rmdir fake-$@-sockets
daemon-tests-dtx:
rm -rf fake-$@-sockets
mkdir fake-$@-sockets

File diff suppressed because one or more lines are too long

@ -165,7 +165,7 @@ t=0 0
m=audio PORT RTP/AVP 0 102 8
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:102 opus/48000/1
a=rtpmap:102 opus/48000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
@ -1708,10 +1708,9 @@ v=0
o=- 1545997027 1 IN IP4 198.51.101.40
s=tester
t=0 0
m=audio PORT RTP/AVP 0 8
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -1751,10 +1750,9 @@ v=0
o=- 1545997027 1 IN IP4 198.51.101.40
s=tester
t=0 0
m=audio PORT RTP/AVP 0 8
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -2415,102 +2413,13 @@ o=testlab 3815920663 3815920664 IN IP4 89.250.11.190
s=pjmedia
c=IN IP4 89.250.11.190
t=0 0
m=audio PORT RTP/AVP 8 0 101 13
m=audio PORT RTP/AVP 8 13 101
c=IN IP4 203.0.113.1
a=mid:1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:13 CN/8000
a=sendrecv
a=rtcp:PORT
a=ptime:20
SDP
offer('strip-all w consume and offer and s/c',
{ codec => {
strip => ['all'],
consume => ['CN'],
offer => ['PCMA', 'PCMU', 'telephone-event'],
},
flags => ['symmetric codecs'],
}, <<SDP);
v=0
o=testlab 949032 0 IN IP4 127.0.0.1
s=session
c=IN IP4 52.115.185.219
b=CT:10000000
t=0 0
m=audio 52152 RTP/AVP 104 9 103 111 18 0 8 97 101 13 118
c=IN IP4 52.115.185.219
a=rtcp:52153
a=mid:1
a=sendrecv
a=rtpmap:104 SILK/16000
a=rtpmap:9 G722/8000
a=rtpmap:103 SILK/8000
a=rtpmap:111 SIREN/16000
a=fmtp:111 bitrate=16000
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:97 RED/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:13 CN/8000
a=rtpmap:118 CN/16000
a=ptime:20
----------------------------------
v=0
o=testlab 949032 0 IN IP4 127.0.0.1
s=session
c=IN IP4 52.115.185.219
b=CT:10000000
t=0 0
m=audio PORT RTP/AVP 8 0 101
c=IN IP4 203.0.113.1
a=mid:1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=sendrecv
a=rtcp:PORT
a=ptime:20
SDP
answer('strip-all w consume and offer and s/c',
{
flags => ['symmetric codecs'],
}, <<SDP);
v=0
o=testlab 3815920663 3815920664 IN IP4 89.250.11.190
s=pjmedia
c=IN IP4 89.250.11.190
t=0 0
m=audio 4002 RTP/AVP 8 101
c=IN IP4 89.250.11.190
a=rtcp:4003 IN IP4 172.31.250.201
a=sendrecv
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
----------------------------------
v=0
o=testlab 3815920663 3815920664 IN IP4 89.250.11.190
s=pjmedia
c=IN IP4 89.250.11.190
t=0 0
m=audio PORT RTP/AVP 8 0 101 13
c=IN IP4 203.0.113.1
a=mid:1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:13 CN/8000
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -2784,12 +2693,11 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 0 101 13
m=audio PORT RTP/AVP 8 13 101
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=rtpmap:13 CN/8000
a=rtpmap:101 telephone-event/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -2812,8 +2720,9 @@ rcv($sock_b, $port_a, rtpm(13, 1002, 3320, $ssrc_b, "\x20"));
reverse_tags();
# XXX obsolete need for transcode=CN
offer('consume CN',
{ ICE => 'remove', replace => ['origin'] }, <<SDP);
{ ICE => 'remove', replace => ['origin'], codec => { transcode => ['CN'] } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.101.1
s=tester
@ -2827,12 +2736,12 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 0 101 13
m=audio PORT RTP/AVP 8 0 13 101
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=rtpmap:13 CN/8000
a=rtpmap:101 telephone-event/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -2887,57 +2796,6 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 0
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
# ^- asymmetric!
new_call;
offer('add some other codec, accept second PT, symmetric',
{ ICE => 'remove', replace => ['origin'], codec => { transcode => ['G722'] } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.101.1
s=tester
t=0 0
m=audio 3002 RTP/AVP 8 0
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 8 0 9
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:9 G722/8000
a=sendrecv
a=rtcp:PORT
SDP
answer('add some other codec, accept second PT, symmetric',
{ ICE => 'remove', replace => ['origin'], flags => ['symmetric-codecs'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.101.1
s=tester
t=0 0
m=audio 4002 RTP/AVP 0 9
c=IN IP4 198.51.101.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
@ -2946,6 +2804,7 @@ a=sendrecv
a=rtcp:PORT
SDP
# ^- reordered!
@ -2989,26 +2848,25 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
snd($sock_a, $port_b, rtp(8, 1000, 3000, 0x1234, "\x2a" x 160));
snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 160));
snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x3456, "\x00" x 160));
($ssrc) = rcv($sock_a, $port_b, rtpm(8, 2000, 4000, -1, "\x2a" x 160));
($ssrc) = rcv($sock_a, $port_b, rtpm(0, 2000, 4000, -1, "\x00" x 160));
snd($sock_b, $port_a, rtp(13, 2001, 4160, 0x3456, "\x12\x23\x23\x34\x56"));
rcv($sock_a, $port_b, rtpm(8, 2001, 4160, $ssrc, "\xfb\x70\x58\xe4\x43\xe6\x41\xfc\x44\x71\xc0\x63\x44\x77\x58\x50\x49\x66\x5a\xd8\x42\x66\x41\x67\xd0\x6f\x67\x60\x60\x7c\x10\x71\x12\x64\x10\x65\x60\x16\x6c\x63\x6c\x76\x60\xd1\x15\x74\x15\x7c\x16\x7d\x14\x7d\x16\x69\x4a\x13\x66\x67\x1c\x60\x66\x15\x7c\x7e\x67\x62\xd5\x15\xd2\x11\xf0\x1c\x72\x49\x11\x76\x6d\x6e\x14\x15\x64\x6e\x11\x76\x17\x7e\x16\x5c\x1d\x42\x15\x14\x16\x69\x11\x63\x1c\x60\x1d\x67\x6a\x15\x63\x11\x14\x10\x79\x68\x6e\x66\x60\x14\x59\x6e\x74\x50\x7d\x6d\x74\x67\x79\x60\x77\x60\x56\x6f\x56\x64\x6e\x77\x63\x62\x15\x45\x6c\x11\x45\x67\x6a\x7c\x60\x6c\x6a\x72\x12\x5f\x6d\x6d\x6a\x5d\x11\x5b\x61\x7b\x6a\x63\x67\x15\xd0\x10"));
rcv($sock_a, $port_b, rtpm(0, 2001, 4160, $ssrc, "\xce\x56\x69\xcc\x61\xca\x63\xd2\x66\x57\xe2\x47\x65\x59\x6a\x74\x5d\x4a\x68\xe9\x60\x4a\x63\x4b\xf4\x43\x4b\x48\x48\x52\x39\x57\x37\x4c\x39\x4c\x48\x3b\x43\x47\x44\x57\x48\xf5\x3e\x59\x3e\x52\x3b\x53\x3d\x53\x3b\x41\x5b\x38\x4a\x4b\x35\x48\x4a\x3e\x52\x50\x4b\x46\xfd\x3e\xf1\x3a\xd6\x35\x54\x5d\x3a\x58\x45\x42\x3d\x3e\x4c\x42\x3a\x58\x3c\x50\x3b\x6e\x36\x60\x3e\x3d\x3b\x41\x3a\x47\x35\x48\x35\x4b\x3e\x3d\x47\x3a\x3d\x39\x4f\x40\x42\x4a\x47\x3d\x6b\x42\x5a\x75\x53\x45\x5a\x4b\x4f\x48\x59\x48\x78\x43\x77\x4c\x42\x59\x47\x46\x3e\x67\x44\x3a\x67\x4b\x3f\x51\x48\x44\x3e\x54\x37\x6c\x45\x45\x3f\x6e\x3a\x68\x49\x4e\x3f\x47\x4b\x3e\xf3\x39"));
snd($sock_b, $port_a, rtp(0, 2002, 4320, 0x3456, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(8, 2002, 4320, $ssrc, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(0, 2002, 4320, $ssrc, "\x00" x 160));
snd($sock_b, $port_a, rtp(13, 2003, 4480, 0x3456, "\x12\x23\x23\x34\x56"));
rcv($sock_a, $port_b, rtpm(8, 2003, 4480, $ssrc, "\x57\x65\x6c\x6e\x6f\x11\x63\x17\x64\x15\x7b\x11\x6c\x13\x7d\x1f\x11\x16\x15\x69\x6d\x65\x15\x63\x16\x14\x65\x1e\x40\x6b\x6a\x11\x7d\x1a\x68\x6d\x16\x12\x6e\x13\x62\x63\x1f\x15\x61\x1f\x16\x1d\x6f\x18\x7b\x10\x1d\x7b\x14\x6e\x15\x6b\x11\x7c\x6b\x6d\x72\x11\x67\x7a\x14\x60\x73\x1d\x7d\x12\x51\x1a\xc6\x16\x17\x6e\x10\x65\x16\x10\x6e\x68\x17\x13\x7d\x15\x16\x45\x1f\x6b\x43\x12\x42\x7b\x77\x14\xe4\x11\x5d\x65\x6e\x46\x58\x10\x78\x51\x11\xf5\x6d\x6d\xd8\x16\x6f\xcf\x14\x63\x69\x68\x64\x6c\x6b\x17\x7a\x61\x11\x75\x79\x7a\x7f\x15\x5d\x12\x7c\x7d\x79\x60\x53\x60\x58\x15\xfe\x63\x45\xda\x7e\xe5\x68\xe0\x69\xf0\x6e\xe4\x58\x4d\x7e\x45\x69\xf7"));
rcv($sock_a, $port_b, rtpm(0, 2003, 4480, $ssrc, "\x7a\x4d\x44\x42\x42\x3a\x46\x3c\x4c\x3e\x4e\x3a\x44\x38\x53\x34\x3a\x3b\x3e\x41\x45\x4d\x3e\x47\x3b\x3d\x4d\x33\x62\x3f\x3e\x3a\x53\x2f\x40\x45\x3b\x37\x42\x38\x46\x47\x34\x3e\x49\x34\x3b\x36\x43\x31\x4e\x39\x36\x4e\x3d\x42\x3e\x3f\x3a\x52\x3f\x45\x54\x3a\x4b\x4e\x3d\x48\x55\x36\x53\x37\x77\x2f\xe3\x3b\x3c\x42\x39\x4d\x3b\x39\x42\x40\x3c\x38\x53\x3e\x3b\x67\x34\x3f\x60\x37\x60\x4e\x59\x3d\xcc\x3a\x6e\x4c\x42\x64\x69\x39\x4f\x76\x3a\xdb\x45\x45\xe9\x3b\x43\xde\x3d\x47\x41\x40\x4c\x44\x3f\x3c\x4e\x49\x3a\x5a\x4f\x4e\x51\x3e\x6e\x37\x52\x53\x4f\x48\x72\x48\x69\x3e\xd0\x47\x67\xe8\x50\xcc\x40\xc8\x41\xd6\x42\xcc\x6a\x5f\x50\x66\x41\xd9"));
snd($sock_b, $port_a, rtp(0, 2004, 4640, 0x3456, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(8, 2004, 4640, $ssrc, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(0, 2004, 4640, $ssrc, "\x00" x 160));
@ -3052,18 +2910,17 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 0
m=audio PORT RTP/AVP 0
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=sendrecv
a=rtcp:PORT
SDP
snd($sock_a, $port_b, rtp(8, 1000, 3000, 0x1234, "\x2a" x 160));
snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 160));
snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x3456, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(8, 2000, 4000, -1, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(0, 2000, 4000, -1, "\x00" x 160));
@ -3160,17 +3017,17 @@ o=- 3816337545 3816337545 IN IP4 ims.imscore.net
s=-
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 9 97 108 8 101 96 98
m=audio PORT RTP/AVP 9 97 108 8 96 98 101
a=rtpmap:9 G722/8000
a=rtpmap:97 opus/48000
a=rtpmap:108 speex/16000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/48000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=rtpmap:98 telephone-event/16000
a=fmtp:98 0-15
a=rtpmap:101 telephone-event/48000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3201,7 +3058,7 @@ t=0 0
m=audio PORT RTP/AVP 0 102 8
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:102 AMR/8000/1
a=rtpmap:102 AMR/8000
a=fmtp:102 mode-change-capability=2;max-red=0
a=rtpmap:8 PCMA/8000
a=sendrecv
@ -3225,9 +3082,8 @@ v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0 102
m=audio PORT RTP/AVP 102
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:102 AMR/8000
a=fmtp:102 octet-align=0; mode-set=7; max-red=0; mode-change-capability=2
a=sendrecv
@ -3274,17 +3130,17 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 108 97 101 96
m=audio PORT RTP/AVP 8 108 97 96 101
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:108 AMR/8000
a=fmtp:108 mode-set=7
a=rtpmap:97 AMR-WB/16000
a=fmtp:97 mode-set=0,1,2;mode-change-period=2;mode-change-capability=2
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/16000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3308,17 +3164,12 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 108 111 101 96
m=audio PORT RTP/AVP 111 96
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:108 AMR/8000
a=fmtp:108 mode-set=7
a=rtpmap:111 AMR-WB/16000
a=fmtp:111 mode-set=0,1,2; mode-change-period=2; mode-change-capability=2
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/16000
a=fmtp:96 0-16
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3361,17 +3212,17 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 108 97 101 96
m=audio PORT RTP/AVP 8 108 97 96 101
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:108 AMR/8000
a=fmtp:108 mode-set=7
a=rtpmap:97 AMR-WB/16000
a=fmtp:97 mode-set=0,1,2;mode-change-period=2;mode-change-capability=2
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/16000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3395,11 +3246,12 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 101
m=audio PORT RTP/AVP 111 96
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=rtpmap:111 AMR-WB/16000
a=fmtp:111 mode-set=0,1,2; mode-change-period=2; mode-change-capability=2
a=rtpmap:96 telephone-event/16000
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3408,7 +3260,6 @@ SDP
# GH 1098
new_call;
@ -3441,17 +3292,17 @@ o=- 3812713289 3812713289 IN IP4 foo.bar.com
s=-
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 9 97 108 8 101 96
m=audio PORT RTP/AVP 9 97 108 8 96 101
a=rtpmap:9 G722/8000
a=rtpmap:97 AMR-WB/16000
a=fmtp:97 mode-set=0,1,2;mode-change-period=2;mode-change-capability=2
a=rtpmap:108 AMR/8000
a=fmtp:108 mode-set=7
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3490,6 +3341,7 @@ a=ptime:20
SDP
new_call;
offer('gh 1098', {
@ -3520,17 +3372,17 @@ o=- 3812713289 3812713289 IN IP4 foo.bar.com
s=-
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 9 97 108 8 101 96
m=audio PORT RTP/AVP 9 97 108 8 96 101
a=rtpmap:9 G722/8000
a=rtpmap:97 AMR-WB/16000
a=fmtp:97 mode-set=0,1,2;mode-change-period=2;mode-change-capability=2
a=rtpmap:108 AMR/8000
a=fmtp:108 mode-set=7
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3600,17 +3452,17 @@ o=- 3812713289 3812713289 IN IP4 foo.bar.com
s=-
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 9 97 108 8 101 96
m=audio PORT RTP/AVP 9 97 108 8 96 101
a=rtpmap:9 G722/8000
a=rtpmap:97 AMR-WB/16000
a=fmtp:97 mode-set=0,1,2;mode-change-period=2;mode-change-capability=2
a=rtpmap:108 AMR/8000
a=fmtp:108 mode-set=7
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3644,7 +3496,7 @@ m=audio PORT RTP/AVP 8 96
a=silenceSupp:off - - - -
a=rtpmap:8 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-16
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -3655,7 +3507,6 @@ SDP
# inject DTMF with mismatched codecs
($sock_a, $sock_b) = new_call([qw(198.51.100.11 3000)], [qw(198.51.100.11 3002)]);
@ -3834,8 +3685,6 @@ Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is receiv
snd($sock_a, $port_b, rtp(8, 1001, 3160, 0x1234, "\x00" x 160));
($ssrc) = rcv($sock_b, $port_a, rtpm(96, 1000, 3000, -1, "\xf0\x44\xd0\x46\x0d\x8d\xd6\xf3\x02\x71\x71\xf0\x00\x00\x0a\x16\x87\x77\x22\x31\xc8\x21\x00\x8b\xe8\x45\xf2\x94\x41\xd6\xf7\xd1\x68\xb1\xed\x39\x5f\x37\xbe\xbc\xd6\x47\x89\xc4\x14\xad\xff\x1b\x69\xe7\x72\x80\x44\xc4\x97\x2f\x9f\xc7\xc4\xa8\x94\xc0"));
($sock_a, $sock_b) = new_call([qw(198.51.100.10 3008)], [qw(198.51.100.10 3010)]);
($port_a) = offer('PCM -> AMR-WB answer mode-set',
@ -4877,14 +4726,14 @@ o=- 3815883745 3815883745 IN IP4 ims.imscore.net
s=-
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 9 111 8 101 96
m=audio PORT RTP/AVP 9 111 8 96 101
a=rtpmap:9 G722/8000
a=rtpmap:111 opus/48000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/48000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/48000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -4913,7 +4762,7 @@ m=audio PORT RTP/AVP 8 96
a=silenceSupp:off - - - -
a=rtpmap:8 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-16
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -5017,9 +4866,8 @@ o=Z 58440449 0 IN IP4 89.225.243.254
s=Z
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 0 8
m=audio PORT RTP/AVP 0
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -5203,13 +5051,13 @@ o=Z 58440449 0 IN IP4 89.225.243.254
s=Z
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 0 8 96 101 97
m=audio PORT RTP/AVP 0 8 96 97 101
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:96 opus/48000/2
a=rtpmap:101 telephone-event/8000
a=rtpmap:97 telephone-event/48000
a=fmtp:97 0-15
a=rtpmap:101 telephone-event/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -5223,10 +5071,10 @@ o=Z 58440449 0 IN IP4 89.225.243.254
s=Z
c=IN IP4 89.225.243.254
t=0 0
m=audio 8000 RTP/AVP 0 8 96 101 97
m=audio 8000 RTP/AVP 0 8 96 101 98
a=rtpmap:96 opus/48000/2
a=rtpmap:101 telephone-event/8000
a=rtpmap:97 telephone-event/48000
a=rtpmap:98 telephone-event/48000
a=sendrecv
--------------------------------------
v=0
@ -5266,11 +5114,11 @@ o=Z 58440449 0 IN IP4 89.225.243.254
s=Z
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 97 8 102 101
m=audio PORT RTP/AVP 97 8 101 102
a=rtpmap:97 opus/48000
a=rtpmap:8 PCMA/8000
a=rtpmap:102 telephone-event/48000
a=rtpmap:101 telephone-event/8000
a=rtpmap:102 telephone-event/48000
a=sendrecv
a=rtcp:PORT
SDP
@ -5946,11 +5794,9 @@ o=dev 5418 9648 IN IP4 8.8.8.60
s=SIP Call
c=IN IP4 8.8.8.60
t=0 0
m=audio PORT RTP/AVP 0 8 3 101
m=audio PORT RTP/AVP 0 101
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:3 GSM/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
@ -7874,11 +7720,10 @@ s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio PORT RTP/AVP 8 107 101
m=audio PORT RTP/AVP 107 101
c=IN IP4 203.0.113.1
b=TIAS:96000
a=ssrc:243811319 cname:04389d431bdd5c52
a=rtpmap:8 PCMA/8000
a=rtpmap:107 opus/48000/2
a=fmtp:107 useinbandfec=1
a=rtpmap:101 telephone-event/8000
@ -8023,15 +7868,15 @@ s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio PORT RTP/AVP 8 107 101
m=audio PORT RTP/AVP 107 101 8
c=IN IP4 203.0.113.1
b=TIAS:96000
a=ssrc:243811319 cname:04389d431bdd5c52
a=rtpmap:8 PCMA/8000
a=rtpmap:107 opus/48000/2
a=fmtp:107 useinbandfec=1
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -8098,15 +7943,15 @@ s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio PORT RTP/AVP 107 8 101
m=audio PORT RTP/AVP 107 101 8
c=IN IP4 203.0.113.1
b=TIAS:96000
a=ssrc:243811319 cname:04389d431bdd5c52
a=rtpmap:107 opus/48000/2
a=fmtp:107 useinbandfec=1
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -8170,16 +8015,11 @@ s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio PORT RTP/AVP 8 107 101 96
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
b=TIAS:96000
a=ssrc:243811319 cname:04389d431bdd5c52
a=rtpmap:8 PCMA/8000
a=rtpmap:107 opus/48000/2
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:96 telephone-event/48000
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -8242,16 +8082,11 @@ s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio PORT RTP/AVP 8 107 101 96
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
b=TIAS:96000
a=ssrc:243811319 cname:04389d431bdd5c52
a=rtpmap:8 PCMA/8000
a=rtpmap:107 opus/48000/2
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=rtpmap:96 telephone-event/48000
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
a=ptime:20
@ -8298,7 +8133,6 @@ rtpe_req('delete', "delete", { 'from-tag' => ft() });
new_call();
offer('T.38 forward re-invite', { ICE => 'remove',
@ -8984,7 +8818,6 @@ is $ret1[5], $ret1[6], 'rtp rport 2';
if (0) {
# github issue 854
@ -9384,7 +9217,6 @@ rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160));
# transcoding, RFC payload type present on both sides
($sock_a, $sock_b) = new_call([qw(198.51.100.1 6110)], [qw(198.51.100.3 6112)]);
@ -9724,16 +9556,16 @@ rcv($sock_a, $port_b, rtpm(0, 4008, 9280, $ssrc, "\x97\x98\xc7\x16\x0a\x0e\x3a\x
snd($sock_b, $port_a, rtp(8, 4009, 9440, 0x6543, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(0, 4009, 9440, $ssrc, "\xda\x50\x2c\x2b\xc0\x97\x8e\x97\x39\x0e\x09\x13\xbf\x92\x8e\x9c\x57\x29\x31\xef\x72\x28\x19\x1b\x6d\x94\x8a\x8f\xce\x11\x0a\x11\x48\x9c\x98\xa5\xdc\x5e\xb5\xa9\xc6\x1f\x0f\x10\x31\x96\x89\x8d\xad\x19\x0e\x15\x37\xac\xaa\xc8\x57\xb7\x9c\x98\xac\x1e\x0c\x0c\x21\x9c\x8b\x8d\xa4\x25\x17\x1d\x3b\xcf\x48\x2b\x30\xae\x93\x8e" . "\xff" x 80));
# pause
snd($sock_b, $port_a, rtp(0, 4010, 9600, 0x6543, "\x00" x 160));
snd($sock_b, $port_a, rtp(8, 4010, 9600, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4010, 9600, $ssrc, "\xff" x 160));
snd($sock_b, $port_a, rtp(0, 4011, 9760, 0x6543, "\x00" x 160));
snd($sock_b, $port_a, rtp(8, 4011, 9760, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4011, 9760, $ssrc, "\xff" x 160));
snd($sock_b, $port_a, rtp(0, 4012, 9920, 0x6543, "\x00" x 160));
snd($sock_b, $port_a, rtp(8, 4012, 9920, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4012, 9920, $ssrc, "\xff" x 160));
snd($sock_b, $port_a, rtp(0, 4013, 10080, 0x6543, "\x00" x 160));
snd($sock_b, $port_a, rtp(8, 4013, 10080, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4013, 10080, $ssrc, "\xff" x 160));
snd($sock_b, $port_a, rtp(0, 4014, 10240, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x00" x 80));
snd($sock_b, $port_a, rtp(8, 4014, 10240, 0x6543, "\x00" x 160));
rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x29" x 80));
@ -11382,15 +11214,9 @@ o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 120 8 0 101 96
m=audio PORT RTP/AVP 120
a=rtpmap:120 opus/48000/2
a=fmtp:120 useinbandfec=1; usedtx=1; maxaveragebitrate=64000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/48000
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
SDP
@ -13247,98 +13073,6 @@ rcv($sock_a, $port_b, rtpm(0, $seq+4, 4000+640, $ssrc, "\xbd\xd3\x77\xd9\xc5\xd0
($sock_a, $sock_b) = new_call([qw(198.51.100.1 7030)], [qw(198.51.100.3 7032)]);
($port_a) = offer('PCM to RFC DTMF transcoding w/ forced PCM transcoding', { ICE => 'remove', replace => ['origin'],
codec => { transcode => ['telephone-event'] }}, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 7030 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 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=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
SDP
($port_b) = answer('PCM to RFC DTMF transcoding w/ forced PCM transcoding', { replace => ['origin'] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 7032 RTP/AVP 8 96
c=IN IP4 198.51.100.3
a=rtpmap:0 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
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));
($seq, $ssrc) = rcv($sock_b, $port_a, rtpm(8, -1, 3000, -1, "\x2a" x 160));
snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, $seq+1, 3160, $ssrc, "\x2a" x 160));
snd($sock_a, $port_b, rtp(0, 1002, 3000+160*2, 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"));
# DTMF not detected yet
rcv($sock_b, $port_a, rtpm(8, $seq+2, 3000+160*2, $ssrc, "\xd5\x9b\x87\x97\x64\x10\x6b\x41\xdc\x73\x66\xd1\x91\x9a\x97\x6d\x07\x04\x67\x91\x9a\x96\x5c\x60\x7d\xd3\x4d\x6b\x11\x7c\x91\x87\x9e\x4f\x1a\x04\x15\xe0\x93\xe8\xda\x59\xf1\xe4\x44\x10\x1b\x6b\xeb\x87\x85\xfc\x12\x1a\x17\xc3\xe2\xfc\x51\xc9\xeb\x96\xcb\x13\x07\x1c\xff\x85\x84\xee\x6f\x12\x68\x5c\xc5\x76\x7b\xc9\x93\x98\xef\x14\x06\x1a\x4f\x9c\x9a\x95\x77\x6c\x7f\xd7\x75\x6b\x14\x59\x9d\x87\x93\x66\x04\x04\x63\xeb\x9d\xe9\xd7\x41\xf4\xff\x71\x12\x19\x61\x91\x86\x9b\xd5\x1e\x1a\x68\xfc\xee\xff\x55\xf4\xeb\x95\x53\x1c\x04\x11\xec\x87\x85\xe5\x14\x1d\x6f\xd1\xcd\x4b\x73\xfc\x92\x9f\xfb\x12\x06\x19\xcd\x98\x9a\xef\x65\x69\x7e\x55\x77\x68"));
snd($sock_a, $port_b, rtp(0, 1003, 3000+160*3, 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"));
# DTMF detection kicking in mid-frame
rcv($sock_b, $port_a, rtpm(8, $seq+3, 3000+160*3, $ssrc, "\x68\xc2\x9e\x84\x94\x6b\x07\x1a\x72\x96\x9c\xec\x59\x49\xcf\xf7\x7b\x12\x1c\x76\x9c\x86\x9f\x7c\x1a\x1a\x63\xe6\xeb\xfe\xd5\xf6\xe9\xef\x71\x19\x05\x68\x97\x86\x9b\xc2\x10\x1c\x62\xc1\xf5\x43\x49\xe4\x92\x92\xda\x1e\x06\x12\xe7\x85\x9b\xe7\x62\x6b\x7e\x55\x76\x69\x62\xf9\x98\x85\xe2\x10\x06\x18\x54\x92\x9c\xe0\x49\x76\xc7\xc3\x66\x12\x13\xd3\x98\x86\x91\x6c\x05\x1b\x79\xef\x95\xff\x54\xf6\xef\xe1\x67\x1b\x1a\x64\x9d\x86\x9e\x43\x1c\x1c\x67\xf6\xf0\x5a\x5a\xe0\x92\x91\x49\x1b\x07\x17\xeb\x84\x98\xf6\x68\x15\x7c\xd7\x76\x6c\x64\xe0\x9b\x9b\xf0\x1f\x06\x1c\xf3\x9e\x9c\xe5\x72\x72\xde\xdd\x63\x12\x17\xfd\x9a\x87\xe8\x17\x04\x1e\x41\x95"));
snd($sock_a, $port_b, rtp(0, 1004, 3000+160*4, 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"));
# DTMF detected now
rcv($sock_b, $port_a, rtpm(96 | 0x80, $seq+4, 3000+160*4, $ssrc, "\x08\x0f\x00\xa0", "\x08\x10\x00\xa0")); # start event 8, vol -15, duration 160
snd($sock_a, $port_b, rtp(0, 1005, 3000+160*5, 0x1234, "\x00" x 160));
# reverting to audio, but DTMF event still progressing
rcv($sock_b, $port_a, rtpm(96, $seq+5, 3000+160*4, $ssrc, "\x08\x0f\x01\x40", "\x08\x10\x01\x40")); # event 8, vol -15, duration 320
snd($sock_a, $port_b, rtp(0, 1006, 3000+160*6, 0x1234, "\x00" x 160));
# end event, 3 times
rcv($sock_b, $port_a, rtpm(96, $seq+6, 3000+160*4, $ssrc, "\x08\x8f\x01\xe0", "\x08\x90\x01\xe0")); # end event 8, vol -15, duration 480
rcv($sock_b, $port_a, rtpm(96, $seq+7, 3000+160*4, $ssrc, "\x08\x8f\x01\xe0", "\x08\x90\x01\xe0")); # end event 8, vol -15, duration 480
rcv($sock_b, $port_a, rtpm(96, $seq+8, 3000+160*4, $ssrc, "\x08\x8f\x01\xe0", "\x08\x90\x01\xe0")); # end event 8, vol -15, duration 480
# audio passing through again
snd($sock_a, $port_b, rtp(0, 1007, 3000+160*7, 0x1234, "\x00" x 160));
rcv($sock_b, $port_a, rtpm(8, $seq+9, 3000+160*7, $ssrc, "\x2a" x 160));
snd($sock_b, $port_a, rtp(8, 2000, 4000, 0x5678, "\x2a" x 160));
($seq, $ssrc) = rcv($sock_a, $port_b, rtpm(0, -1, 4000, -1, "\x00" x 160));
snd($sock_b, $port_a, rtp(8, 2001, 4000+160, 0x5678, "\x2a" x 160));
rcv($sock_a, $port_b, rtpm(0, $seq+1, 4000+160, $ssrc, "\x00" x 160));
snd($sock_b, $port_a, rtp(96, 2002, 4000+320, 0x5678, "\x08\x10\x00\xa0"));
rcv($sock_a, $port_b, rtpm(0, $seq+2, 4000+320, $ssrc, "\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"));
snd($sock_b, $port_a, rtp(96, 2003, 4000+320, 0x5678, "\x08\x10\x01\x40"));
rcv($sock_a, $port_b, rtpm(0, $seq+3, 4000+480, $ssrc, "\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"));
snd($sock_b, $port_a, rtp(96, 2004, 4000+320, 0x5678, "\x08\x10\x01\xe0"));
rcv($sock_a, $port_b, rtpm(0, $seq+4, 4000+640, $ssrc, "\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"));
# test out of seq
snd($sock_b, $port_a, rtp(8, 2006, 4000+800, 0x5678, "\x2a" x 160)); # processed because TS difference is too large
rcv($sock_a, $port_b, rtpm(0, $seq+6, 4000+800, $ssrc, "\x00" x 160));
# test telephone-event synth options
new_call;
@ -13361,19 +13095,19 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 0 96 8 97 9 98 99 100
m=audio PORT RTP/AVP 0 96 8 97 9 99 100 98
c=IN IP4 203.0.113.1
a=rtpmap:0 PCMU/8000
a=rtpmap:96 opus/48000
a=rtpmap:8 PCMA/8000
a=rtpmap:97 speex/16000
a=rtpmap:9 G722/8000
a=rtpmap:98 telephone-event/8000
a=fmtp:98 0-15
a=rtpmap:99 telephone-event/16000
a=fmtp:99 0-15
a=rtpmap:100 telephone-event/48000
a=fmtp:100 0-15
a=rtpmap:98 telephone-event/8000
a=fmtp:98 0-15
a=sendrecv
a=rtcp:PORT
SDP
@ -13400,13 +13134,13 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8 96 97 98
m=audio PORT RTP/AVP 8 96 98 97
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=rtpmap:96 opus/48000/2
a=rtpmap:97 telephone-event/8000
a=rtpmap:98 telephone-event/48000
a=fmtp:98 0-15
a=rtpmap:97 telephone-event/8000
a=sendrecv
a=rtcp:PORT
SDP
@ -13685,14 +13419,14 @@ v=0
o=- 1545997027 1 IN IP4 203.0.113.1
s=tester
t=0 0
m=audio PORT RTP/AVP 100 8 101 96
m=audio PORT RTP/AVP 100 8 96 101
c=IN IP4 203.0.113.1
a=rtpmap:100 PCMU/16000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=rtpmap:101 telephone-event/16000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:PORT
SDP

File diff suppressed because it is too large Load Diff

@ -59,6 +59,7 @@ GetOptions(
'codec-consume=s@' => \$options{'codec-consume'},
'codec-accept=s@' => \$options{'codec-accept'},
'codec-set=s@' => \$options{'codec-set'},
'codec-except=s@' => \$options{'codec-except'},
'ptime=i' => \$options{'ptime'},
'flags=s@' => \$options{'flags'},
'codec-options-flat' => \$options{'codec options flag'},
@ -117,7 +118,7 @@ if (defined($options{direction})) {
$options{direction} =~ /(.*),(.*)/ or die;
$packet{direction} = [$1,$2];
}
for my $x (qw(strip offer transcode mask set consume accept)) {
for my $x (qw(strip offer transcode mask set consume accept except)) {
if ($options{'codec-'.$x} && @{$options{'codec-'.$x}}) {
if (!$options{'codec options flag'}) {
$packet{codec}{$x} = $options{'codec-'.$x};

Loading…
Cancel
Save