From bd53179cd1bdff4726ff946e6fff3d06ae5b807b Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 12 Nov 2020 13:52:28 -0500 Subject: [PATCH] TT#100200 properly support multiple supplemental codecs Change-Id: I643fa844b504bf1264d6d2cddebf6d6602c80b35 --- daemon/codec.c | 106 +++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index edbb131b9..7ff8dbc8b 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -140,6 +140,7 @@ static codec_handler_func handler_func_passthrough_ssrc; static codec_handler_func handler_func_transcode; static codec_handler_func handler_func_playback; static codec_handler_func handler_func_inject_dtmf; +static codec_handler_func handler_func_supplemental; static codec_handler_func handler_func_dtmf; static codec_handler_func handler_func_t38; @@ -149,6 +150,7 @@ static void __free_ssrc_handler(void *); static void __transcode_packet_free(struct transcode_packet *); +static int packet_decode(struct codec_ssrc_handler *, struct transcode_packet *, struct media_packet *); static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2); static int packet_decoded_fifo(decoder_t *decoder, AVFrame *frame, void *u1, void *u2); static int packet_decoded_direct(decoder_t *decoder, AVFrame *frame, void *u1, void *u2); @@ -213,6 +215,8 @@ static void __make_passthrough(struct codec_handler *handler) { STR_FMT(&handler->source_pt.encoding_with_params)); if (handler->source_pt.codec_def && handler->source_pt.codec_def->dtmf) handler->func = handler_func_dtmf; + else if (handler->source_pt.codec_def && handler->source_pt.codec_def->supplemental) + handler->func = handler_func_supplemental; else { handler->func = handler_func_passthrough; handler->kernelize = 1; @@ -226,6 +230,8 @@ static void __make_passthrough_ssrc(struct codec_handler *handler) { STR_FMT(&handler->source_pt.encoding_with_params)); if (handler->source_pt.codec_def && handler->source_pt.codec_def->dtmf) handler->func = handler_func_dtmf; + else if (handler->source_pt.codec_def && handler->source_pt.codec_def->supplemental) + handler->func = handler_func_supplemental; else { handler->func = handler_func_passthrough_ssrc; handler->kernelize = 1; @@ -384,8 +390,19 @@ static void __dtmf_dsp_shutdown(struct call_media *sink, int payload_type) { } +static void __track_supp_codec(GHashTable *supplemental_sinks, struct rtp_payload_type *pt) { + if (!pt->codec_def || !pt->codec_def->supplemental) + return; + + GHashTable *supp_sinks = g_hash_table_lookup(supplemental_sinks, pt->codec_def->rtpname); + if (!supp_sinks) + return; + if (!g_hash_table_lookup(supp_sinks, GUINT_TO_POINTER(pt->clock_rate))) + g_hash_table_insert(supp_sinks, GUINT_TO_POINTER(pt->clock_rate), pt); +} + static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, struct call_media *sink, - const struct sdp_ng_flags *flags, GHashTable *dtmf_sinks, int *sink_transcoding) + const struct sdp_ng_flags *flags, GHashTable *supplemental_sinks, int *sink_transcoding) { struct rtp_payload_type *pref_dest_codec = NULL; @@ -416,22 +433,14 @@ static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, &pt->payload_type); if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt)) { *sink_transcoding = 1; - // can the sink receive RFC DTMF but the receiver can't send it? - if (pt->codec_def && pt->codec_def->dtmf) { - if (!g_hash_table_lookup(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate))) - g_hash_table_insert(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate), - pt); - } + // can the sink receive supplemental codec but the receiver can't send it? + __track_supp_codec(supplemental_sinks, pt); } } else if (flags && (flags->always_transcode || flags->inject_dtmf)) { - // with always-transcode, we must keep track of potential output DTMF payload + // with always-transcode, we must keep track of potential output supplemental payload // types as well - if (pt->codec_def && pt->codec_def->dtmf) { - if (!g_hash_table_lookup(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate))) - g_hash_table_insert(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate), - pt); - } + __track_supp_codec(supplemental_sinks, pt); } } @@ -439,7 +448,7 @@ static struct rtp_payload_type *__check_dest_codecs(struct call_media *receiver, } static void __check_send_codecs(struct call_media *receiver, struct call_media *sink, - const struct sdp_ng_flags *flags, GHashTable *dtmf_sinks, int *sink_transcoding) + const struct sdp_ng_flags *flags, GHashTable *supplemental_sinks, int *sink_transcoding) { if (!MEDIA_ISSET(sink, TRANSCODE)) return; @@ -450,12 +459,8 @@ static void __check_send_codecs(struct call_media *receiver, struct call_media * &pt->payload_type); if (!recv_pt || rtp_payload_type_cmp(pt, recv_pt) || (flags && flags->inject_dtmf)) { *sink_transcoding = 1; - // can the sink receive RFC DTMF but the receiver can't send it? - if (pt->codec_def && pt->codec_def->dtmf) { - if (!g_hash_table_lookup(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate))) - g_hash_table_insert(dtmf_sinks, GUINT_TO_POINTER(pt->clock_rate), - pt); - } + // can the sink receive supplemental codec but the receiver can't send it? + __track_supp_codec(supplemental_sinks, pt); continue; } @@ -473,7 +478,10 @@ static void __check_send_codecs(struct call_media *receiver, struct call_media * } } -static int __dtmf_payload_type(GHashTable *dtmf_sinks, struct rtp_payload_type *pref_dest_codec) { +static int __dtmf_payload_type(GHashTable *supplemental_sinks, struct rtp_payload_type *pref_dest_codec) { + GHashTable *dtmf_sinks = g_hash_table_lookup(supplemental_sinks, "telephone-event"); + if (!dtmf_sinks) + return -1; if (!g_hash_table_size(dtmf_sinks) || !pref_dest_codec) return -1; @@ -986,23 +994,29 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, // that the sink specified. determine this first. struct rtp_payload_type *pref_dest_codec = NULL; int sink_transcoding = 0; - // keep track of telephone-event payload types. we hash them by clock rate + // keep track of supplemental payload types. we hash them by clock rate // in case there's several of them. the clock rates of the destination - // codec and the telephone-event codec must match. - GHashTable *dtmf_sinks = g_hash_table_new(g_direct_hash, g_direct_equal); + // codec and the supplemental codec must match. + GHashTable *supplemental_sinks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + (GDestroyNotify) g_hash_table_destroy); + for (GList *l = codec_supplemental_codecs->head; l; l = l->next) { + codec_def_t *def = l->data; + g_hash_table_replace(supplemental_sinks, (void *) def->rtpname, + g_hash_table_new(g_direct_hash, g_direct_equal)); + } - pref_dest_codec = __check_dest_codecs(receiver, sink, flags, dtmf_sinks, &sink_transcoding); + pref_dest_codec = __check_dest_codecs(receiver, sink, flags, supplemental_sinks, &sink_transcoding); // similarly, if the sink can receive a codec that the receiver can't send, it's also transcoding - __check_send_codecs(receiver, sink, flags, dtmf_sinks, &sink_transcoding); + __check_send_codecs(receiver, sink, flags, supplemental_sinks, &sink_transcoding); if (flags && flags->opmode == OP_ANSWER && flags->symmetric_codecs) __symmetric_codecs(receiver, sink, &sink_transcoding); - ilog(LOG_DEBUG, "%i DTMF sink entries", g_hash_table_size(dtmf_sinks)); - int dtmf_payload_type = __dtmf_payload_type(dtmf_sinks, pref_dest_codec); + int dtmf_payload_type = __dtmf_payload_type(supplemental_sinks, pref_dest_codec); - g_hash_table_destroy(dtmf_sinks); + g_hash_table_destroy(supplemental_sinks); + supplemental_sinks = NULL; struct rtp_payload_type *dtmf_pt = NULL; struct rtp_payload_type *reverse_dtmf_pt = NULL; @@ -1031,7 +1045,7 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink, // payload type to keep track of this. GHashTable *output_transcoders = g_hash_table_new(g_direct_hash, g_direct_equal); - int transcode_dtmf = 0; // is one of our destination codecs DTMF? + int transcode_supplemental = 0; // is one of our source codecs a supplemental one? // do we need to detect PCM DTMF tones? int pcm_dtmf_detect = 0; @@ -1143,8 +1157,8 @@ unsupported: // the sink does not support this codec -> transcode ilog(LOG_DEBUG, "Sink does not support codec " STR_FORMAT, STR_FMT(&pt->encoding_with_params)); dest_pt = pref_dest_codec; - if (pt->codec_def->dtmf) - transcode_dtmf = 1; + if (pt->codec_def->supplemental) + transcode_supplemental = 1; transcode:; // look up the reverse side of this payload type, which is the decoder to our // encoder. if any codec options such as bitrate were set during an offer, @@ -1198,7 +1212,7 @@ next: // if the sink does not support DTMF but we can receive it, we must transcode // DTMF event packets to PCM. this requires all codecs to be transcoded to the // sink's preferred destination codec. - if (!transcode_dtmf && dtmf_payload_type == -1) + if (!transcode_supplemental && dtmf_payload_type == -1) __make_passthrough_ssrc(handler); else if (dtmf_pt && reverse_dtmf_pt) __make_passthrough_ssrc(handler); @@ -1602,7 +1616,10 @@ static int packet_dtmf_dup(struct codec_ssrc_handler *ch, struct transcode_packe return 0; } -static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { +static int __handler_func_supplemental(struct codec_handler *h, struct media_packet *mp, + int (*func)(struct codec_ssrc_handler *, struct transcode_packet *, struct media_packet *), + int (*dup_func)(struct codec_ssrc_handler *, struct transcode_packet *, struct media_packet *)) +{ if (G_UNLIKELY(!mp->rtp)) return handler_func_passthrough(h, mp); @@ -1610,7 +1627,8 @@ static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { // create new packet and insert it into sequencer queue - ilog(LOG_DEBUG, "Received DTMF RTP packet: SSRC %" PRIx32 ", PT %u, seq %u, TS %u, len %i", + ilog(LOG_DEBUG, "Received %s RTP packet: SSRC %" PRIx32 ", PT %u, seq %u, TS %u, len %i", + h->source_pt.codec_def->rtpname, ntohl(mp->rtp->ssrc), mp->rtp->m_pt, ntohs(mp->rtp->seq_num), ntohl(mp->rtp->timestamp), mp->payload.len); @@ -1627,14 +1645,20 @@ static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { sequencer_h = codec_handler_get(mp->media, prim_pt); if (sequencer_h == h) continue; - ilog(LOG_DEBUG, "Primary RTP payload type for handling DTMF event is %i", prim_pt); + if (sequencer_h->source_pt.codec_def && sequencer_h->source_pt.codec_def->supplemental) + continue; + ilog(LOG_DEBUG, "Primary RTP payload type for handling %s is %i", + h->source_pt.codec_def->rtpname, + prim_pt); break; } } + // XXX ? h->output_handler = sequencer_h->output_handler; // XXX locking? + struct transcode_packet *packet = g_slice_alloc0(sizeof(*packet)); - packet->func = packet_dtmf; - packet->dup_func = packet_dtmf_dup; + packet->func = func; + packet->dup_func = dup_func; packet->handler = h; packet->rtp = *mp->rtp; @@ -1647,6 +1671,12 @@ static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { return __handler_func_sequencer(mp, packet); } +static int handler_func_supplemental(struct codec_handler *h, struct media_packet *mp) { + return __handler_func_supplemental(h, mp, packet_decode, NULL); +} +static int handler_func_dtmf(struct codec_handler *h, struct media_packet *mp) { + return __handler_func_supplemental(h, mp, packet_dtmf, packet_dtmf_dup); +} static int handler_func_t38(struct codec_handler *h, struct media_packet *mp) { if (!mp->media)