diff --git a/daemon/call.c b/daemon/call.c index 8512188fb..1e66f7334 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2177,7 +2177,7 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams, 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); + codec_tracker_finish(media, other_media); /* send and recv are from our POV */ bf_copy_same(&media->media_flags, &sp->sp_flags, diff --git a/daemon/codec.c b/daemon/codec.c index aa44baa6e..ba4ee7396 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1374,6 +1374,9 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, for (GList *l = receiver->codecs_prefs_recv.head; l; ) { struct rtp_payload_type *pt = l->data; + ilogs(internals, LOG_DEBUG, "checking recv codec " STR_FORMAT, + STR_FMT(&pt->encoding)); + if (MEDIA_ISSET(sink, TRANSCODE) && flags && flags->opmode == OP_ANSWER) { // if the other side is transcoding, we may come across a receiver entry // (recv->recv) that wasn't originally offered (recv->send). we must eliminate @@ -1410,14 +1413,14 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, goto next; } - //ilog(LOG_DEBUG, "XXXXXXXXXXXX pref dest codec " STR_FORMAT " is %i, CN match %i DTMF match %i " - //"sink TC %i/%i recv TC %i TC supp %i DTMF DSP %i", - //STR_FMT(&pref_dest_codec->encoding_with_params), - //pref_dest_codec->for_transcoding, - //cn_pt_match, dtmf_pt_match, - //MEDIA_ISSET(sink, TRANSCODE), sink_transcoding, - //receiver_transcoding, - //transcode_supplemental, pcm_dtmf_detect); + ilogs(internals, LOG_DEBUG, "pref dest codec " STR_FORMAT " is %i, CN match %i DTMF match %i " + "sink TC %i/%i recv TC %i TC supp %i DTMF DSP %i", + STR_FMT(&pref_dest_codec->encoding_with_params), + pref_dest_codec->for_transcoding, + cn_pt_match, dtmf_pt_match, + MEDIA_ISSET(sink, TRANSCODE), sink_transcoding, + receiver_transcoding, + transcode_supplemental, pcm_dtmf_detect); struct rtp_payload_type *dest_pt; // transcode to this @@ -1525,8 +1528,8 @@ next: for (GList *l = receiver->codecs_prefs_recv.head; l; ) { struct rtp_payload_type *pt = l->data; - //ilog(LOG_DEBUG, "XXXX checking recv codec " STR_FORMAT, - //STR_FMT(&pt->encoding)); + ilogs(internals, LOG_DEBUG, "checking recv codec " STR_FORMAT, + STR_FMT(&pt->encoding)); if (pt->codec_def) { // supported @@ -3252,7 +3255,7 @@ static int ptr_cmp(const void *a, const void *b) { return 1; return 0; } -void codec_tracker_finish(struct call_media *media) { +void codec_tracker_finish(struct call_media *media, struct call_media *other_media) { struct codec_tracker *sct = media->codec_tracker; if (!sct) return; @@ -3339,8 +3342,75 @@ void codec_tracker_finish(struct call_media *media) { GList *link = j->data; struct rtp_payload_type *pt = link->data; - ilogs(codec, LOG_DEBUG, "Eliminating supplemental codec " STR_FORMAT " with stray clock rate %u", - STR_FMT(&pt->encoding), clockrate); + ilogs(codec, LOG_DEBUG, "Eliminating supplemental codec " STR_FORMAT " (%i) with " + "stray clock rate %u", + STR_FMT(&pt->encoding_with_params), pt->payload_type, clockrate); + + // now we have to check the codec handlers on the opposite side to see + // if any of them were using this as output + struct rtp_payload_type *prim_dtmf = NULL; + struct rtp_payload_type *prim_cn = NULL; + for (GList *o = other_media->codecs_prefs_recv.head; o; o = o->next) { + struct rtp_payload_type *opt = o->data; + struct codec_handler *ch = codec_handler_get(other_media, + opt->payload_type); + if (!ch) + continue; + + // check DTMF + if (!prim_dtmf && ch->dtmf_payload_type != -1) + prim_dtmf = g_hash_table_lookup(other_media->codecs_recv, + &ch->dtmf_payload_type); + if (prim_dtmf) { + if (ch->dest_pt.payload_type == pt->payload_type) { + ilogs(codec, LOG_DEBUG, "Adjusting output DTMF PT for " + "opposite codec handler for " + STR_FORMAT " (%i) to %i", + STR_FMT(&opt->encoding_with_params), + opt->payload_type, + prim_dtmf->payload_type); + __make_transcoder(ch, prim_dtmf, NULL, + prim_dtmf->payload_type, + ch->pcm_dtmf_detect); + } + else if (ch->dtmf_payload_type == pt->payload_type) { + ilogs(codec, LOG_DEBUG, "Adjusting output DTMF PT for " + "opposite codec handler for " + STR_FORMAT " (%i) to %i", + STR_FMT(&opt->encoding_with_params), + opt->payload_type, + prim_dtmf->payload_type); + __make_transcoder(ch, &ch->dest_pt, NULL, + prim_dtmf->payload_type, + ch->pcm_dtmf_detect); + } + } + + // check CN + if (!prim_cn && ch->cn_payload_type != -1) + prim_cn = g_hash_table_lookup(other_media->codecs_recv, + &ch->cn_payload_type); + if (prim_cn) { + if (ch->dest_pt.payload_type == pt->payload_type) { + ilogs(codec, LOG_DEBUG, "Adjusting output CN PT for " + "opposite codec handler for " + STR_FORMAT " (%i) to %i", + STR_FMT(&opt->encoding_with_params), + opt->payload_type, + prim_cn->payload_type); + ch->cn_payload_type = prim_cn->payload_type; + } + else if (ch->cn_payload_type == pt->payload_type) { + ilogs(codec, LOG_DEBUG, "Adjusting output CN PT for " + "opposite codec handler for " + STR_FORMAT " (%i) to %i", + STR_FMT(&opt->encoding_with_params), + opt->payload_type, + prim_cn->payload_type); + ch->cn_payload_type = prim_cn->payload_type; + } + } + } __delete_receiver_codec(media, link); } diff --git a/include/codec.h b/include/codec.h index a45f4333c..6278d8f33 100644 --- a/include/codec.h +++ b/include/codec.h @@ -100,7 +100,7 @@ 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 *); +void codec_tracker_finish(struct call_media *, struct call_media *); void codec_handlers_stop(GQueue *); #else diff --git a/t/transcode-test.c b/t/transcode-test.c index f1bb39cf1..c58635734 100644 --- a/t/transcode-test.c +++ b/t/transcode-test.c @@ -122,7 +122,7 @@ static void offer(void) { codec_tracker_init(media_B); codec_rtp_payload_types(media_B, media_A, &rtp_types, &flags); codec_handlers_update(media_B, media_A, &flags, NULL); - codec_tracker_finish(media_B); + codec_tracker_finish(media_B, media_A); __init(); } @@ -132,7 +132,7 @@ static void answer(void) { codec_tracker_init(media_A); codec_rtp_payload_types(media_A, media_B, &rtp_types, &flags); codec_handlers_update(media_A, media_B, &flags, NULL); - codec_tracker_finish(media_A); + codec_tracker_finish(media_A, media_B); __init(); } @@ -1705,6 +1705,26 @@ int main(void) { expect(A, recv, "9/G722/8000 101/telephone-event/8000"); packet_seq(A, 101, "\x05\x07\x01\x40", 4000, 10, 97, "\x05\x07\x07\x80"); packet_seq(B, 97, "\x05\x07\x07\x80", 4000, 10, 101, "\x05\x07\x01\x40"); + // DTMF PT TC w eq PT + start(); + sdp_pt(96, opus, 48000); + sdp_pt(8, PCMA, 8000); + sdp_pt(102, telephone-event, 48000); + sdp_pt(101, telephone-event, 8000); + ht_set(codec_mask, all); + transcode(opus); + transcode(PCMA); + transcode(PCMU); + transcode(telephone-event); + offer(); + expect(B, recv, "96/opus/48000 8/PCMA/8000 0/PCMU/8000 102/telephone-event/48000 101/telephone-event/8000"); + sdp_pt(0, PCMU, 8000); + sdp_pt(101, telephone-event, 8000); + flags.single_codec = 1; + answer(); + expect(A, recv, "96/opus/48000 102/telephone-event/48000"); + packet_seq(A, 102, "\x05\x07\x01\x40", 4000, 10, 101, "\x05\x07\x00\x35"); + packet_seq(B, 101, "\x05\x07\x07\x80", 4000, 10, 102, "\x05\x07\x2d\x00"); return 0; }