From 86e336c3ffaf49cc3cfe38352b998e4efe6f5ce7 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 10 Mar 2023 09:23:55 -0500 Subject: [PATCH] MT#56861 support DTMF injection with passthrough Change-Id: I26fa6cf033a12d6b2fe66a7c688c87739091cbd1 --- daemon/codec.c | 65 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 1bd383ecd..84e04fb3d 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1092,7 +1092,7 @@ bool codec_handlers_update(struct call_media *receiver, struct call_media *sink, if (flags && flags->inject_dtmf) sink->monologue->inject_dtmf = 1; - bool use_ssrc_passthrough = !!MEDIA_ISSET(receiver, ECHO); + bool use_ssrc_passthrough = MEDIA_ISSET(receiver, ECHO) || sink->monologue->inject_dtmf; // do we have to force everything through the transcoding engine even if codecs match? bool force_transcoding = do_pcm_dtmf_blocking || do_dtmf_blocking || use_audio_player; @@ -1307,8 +1307,8 @@ sink_pt_fixed:; } } - // force transcoding if we want DTMF injection - if (sink->monologue->inject_dtmf) + // force transcoding if we want DTMF injection and there's no DTMF PT + if (!sink_dtmf_pt && sink->monologue->inject_dtmf) goto transcode; // everything matches - we can do passthrough @@ -2399,13 +2399,66 @@ static int handler_func_passthrough_ssrc(struct codec_handler *h, struct media_p codec_calc_jitter(mp->ssrc_in, ts, h->source_pt.clock_rate, &mp->tv); codec_calc_lost(mp->ssrc_in, ntohs(mp->rtp->seq_num)); + // save original payload in case DTMF mangles it + str orig_raw = mp->raw; + + // provide an uninitialised buffer as potential output storage for DTMF + char buf[sizeof(*mp->rtp) + sizeof(struct telephone_event_payload) + RTP_BUFFER_TAIL_ROOM]; + + // default function to return packets + void (*add_packet_fn)(struct media_packet *mp, unsigned int clockrate) = codec_add_raw_packet; + + unsigned int duplicates = 0; + + // check for DTMF injection + if (h->dtmf_payload_type != -1) { + struct codec_ssrc_handler *ch = get_ssrc(mp->ssrc_in->parent->h.ssrc, h->ssrc_hash); + uint64_t ts = ntohl(mp->rtp->timestamp); + + str ev_pl = { .s = buf + sizeof(*mp->rtp) }; + + int is_dtmf = dtmf_event_payload(&ev_pl, &ts, h->source_pt.clock_rate * h->source_pt.ptime / 1000, + &ch->dtmf_event, &ch->dtmf_events); + if (is_dtmf) { + // fix up RTP header + struct rtp_header *r = (void *) buf; + *r = *mp->rtp; + r->m_pt = h->dtmf_payload_type; + r->timestamp = htonl(ts); + if (is_dtmf == 1) + r->m_pt |= 0x80; + else if (is_dtmf == 3) // end event + duplicates = 2; + mp->rtp = r; + mp->raw.s = buf; + mp->raw.len = ev_pl.len + sizeof(*mp->rtp); + + add_packet_fn = codec_add_raw_packet_dup; + } + obj_put(&ch->h); + } + // substitute out SSRC etc mp->rtp->ssrc = htonl(mp->ssrc_out->parent->h.ssrc); - mp->rtp->seq_num = htons(ntohs(mp->rtp->seq_num) + mp->ssrc_out->parent->seq_diff); - // keep track of other stats here? + // to track our seq + unsigned short seq = ntohs(mp->rtp->seq_num); - __buffer_delay_raw(h->delay_buffer, h, codec_add_raw_packet, mp, h->source_pt.clock_rate); + while (true) { + mp->rtp->seq_num = htons(seq + mp->ssrc_out->parent->seq_diff); + + // keep track of other stats here? + + __buffer_delay_raw(h->delay_buffer, h, add_packet_fn, mp, h->source_pt.clock_rate); + + if (duplicates == 0) + break; + duplicates--; + mp->ssrc_out->parent->seq_diff++; + } + + // restore original in case it was mangled + mp->raw = orig_raw; return 0; }