From dc38a0e88e6483402b5085412481bbb94a310150 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 14 May 2021 09:28:41 -0400 Subject: [PATCH] TT#122401 support multiple DTX method per codec Change-Id: I775d56e675255b3dca4227779d1146d8c8806f06 --- daemon/codec.c | 2 +- lib/codeclib.c | 141 ++++++++++++++++++++++++++++++++++++++++--------- lib/codeclib.h | 21 +++++++- 3 files changed, 137 insertions(+), 27 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 9eef109a3..799bd4a61 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -2642,7 +2642,7 @@ static void __dtx_free(void *p) { mutex_destroy(&dtxb->lock); } static void __dtx_setup(struct codec_ssrc_handler *ch) { - if (!ch->handler->source_pt.codec_def->dtx || ch->dtx_buffer) + if (!decoder_has_dtx(ch->decoder) || ch->dtx_buffer) return; if (!rtpe_config.dtx_delay) diff --git a/lib/codeclib.c b/lib/codeclib.c index 3132518cd..1855eb548 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -106,6 +106,13 @@ static const codec_type_t codec_type_cn = { .decoder_close = avc_decoder_close, }; +static const dtx_method_t dtx_method_silence = { + .do_dtx = generic_silence_dtx, +}; +static const dtx_method_t dtx_method_amr = { + .do_dtx = amr_dtx, +}; + #ifdef HAVE_BCG729 static packetizer_f packetizer_g729; // aggregate some frames into packets @@ -142,7 +149,9 @@ static codec_def_t __codec_defs[] = { .bits_per_sample = 8, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "PCMU", @@ -155,7 +164,9 @@ static codec_def_t __codec_defs[] = { .bits_per_sample = 8, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "G723", @@ -168,7 +179,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "G722", @@ -181,7 +194,9 @@ static codec_def_t __codec_defs[] = { .bits_per_sample = 8, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "QCELP", @@ -191,7 +206,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, #ifndef HAVE_BCG729 { @@ -204,7 +221,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "G729a", @@ -216,7 +235,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, #else { @@ -231,7 +252,9 @@ static codec_def_t __codec_defs[] = { .bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits .media_type = MT_AUDIO, .codec_type = &codec_type_bcg729, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "G729a", @@ -244,7 +267,9 @@ static codec_def_t __codec_defs[] = { .bits_per_sample = 1, // 10 ms frame has 80 samples and encodes as (max) 10 bytes = 80 bits .media_type = MT_AUDIO, .codec_type = &codec_type_bcg729, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, #endif { @@ -257,7 +282,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "GSM", @@ -269,7 +296,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "iLBC", @@ -299,7 +328,9 @@ static codec_def_t __codec_defs[] = { .codec_type = &codec_type_avcodec, .init = opus_init, .set_enc_options = opus_set_enc_options, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "vorbis", @@ -310,7 +341,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "ac3", @@ -319,7 +352,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "eac3", @@ -328,7 +363,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "ATRAC3", @@ -337,7 +374,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "ATRAC-X", @@ -346,7 +385,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 0, 0) { @@ -356,7 +397,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "EVRC0", @@ -366,7 +409,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "EVRC1", @@ -376,7 +421,9 @@ static codec_def_t __codec_defs[] = { .packetizer = packetizer_passthrough, .media_type = MT_AUDIO, .codec_type = &codec_type_avcodec, - .dtx = generic_silence_dtx, + .dtx_methods = { + [DTX_SILENCE] = &dtx_method_silence, + }, }, #endif { @@ -395,7 +442,10 @@ static codec_def_t __codec_defs[] = { .codec_type = &codec_type_amr, .set_enc_options = amr_set_enc_options, .set_dec_options = amr_set_dec_options, - .dtx = amr_dtx, + .dtx_methods = { + [DTX_NATIVE] = &dtx_method_amr, + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "AMR-WB", @@ -413,7 +463,10 @@ static codec_def_t __codec_defs[] = { .codec_type = &codec_type_amr, .set_enc_options = amr_set_enc_options, .set_dec_options = amr_set_dec_options, - .dtx = amr_dtx, + .dtx_methods = { + [DTX_NATIVE] = &dtx_method_amr, + [DTX_SILENCE] = &dtx_method_silence, + }, }, { .rtpname = "telephone-event", @@ -559,6 +612,15 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, else ret->ptime = def->default_ptime; + // init with first supported DTX method + enum dtx_method dm = -1; + for (int i = 0; i < NUM_DTX_METHODS; i++) { + if (def->dtx_methods[i]) { + dm = i; + break; + } + } + err = def->codec_type->decoder_init(ret, fmtp, extra_opts); if (err) goto err; @@ -568,6 +630,8 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, ret->pts = (uint64_t) -1LL; ret->rtp_ts = (unsigned long) -1L; + decoder_switch_dtx(ret, dm); + return ret; err: @@ -579,6 +643,33 @@ err: } +int decoder_switch_dtx(decoder_t *dec, enum dtx_method dm) { + if (dec->dtx.cleanup) + dec->dtx.cleanup(dec); + ZERO(dec->dtx); + unsigned int i = dm; + if (i >= NUM_DTX_METHODS) + return -1; + const dtx_method_t *dmp = dec->def->dtx_methods[i]; + if (!dmp) + return -1; + dec->dtx = *dmp; + if (dmp->init) { + if (dmp->init(dec)) { + ilog(LOG_ERR, "Failed to initialise DTX (%u)", i); + decoder_switch_dtx(dec, -1); + return -1; + } + } + return 0; +} + + +gboolean decoder_has_dtx(decoder_t *dec) { + return dec->dtx.do_dtx == NULL ? FALSE : TRUE; +} + + static void avc_decoder_close(decoder_t *dec) { #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 1, 0) avcodec_free_context(&dec->u.avc.avcctx); @@ -597,6 +688,8 @@ void decoder_close(decoder_t *dec) { if (dec->def && dec->def->codec_type && dec->def->codec_type->decoder_close) dec->def->codec_type->decoder_close(dec); + decoder_switch_dtx(dec, -1); + resample_shutdown(&dec->resampler); g_slice_free1(sizeof(*dec), dec); } @@ -712,7 +805,7 @@ static int __decoder_input_data(decoder_t *dec, const str *data, unsigned long t if (G_UNLIKELY(!dec)) return -1; - if (!data && !dec->def->dtx) + if (!data && !dec->dtx.do_dtx) return 0; ts *= dec->def->clockrate_mult; @@ -741,7 +834,7 @@ static int __decoder_input_data(decoder_t *dec, const str *data, unsigned long t if (data) dec->def->codec_type->decoder_input(dec, data, &frames); else - dec->def->dtx(dec, &frames, ptime); + dec->dtx.do_dtx(dec, &frames, ptime); AVFrame *frame; int ret = 0; diff --git a/lib/codeclib.h b/lib/codeclib.h index c2758b62b..92240f618 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -58,6 +58,7 @@ struct resample_s; struct seq_packet_s; struct rtp_payload_type; union codec_options_u; +struct dtx_method_s; typedef struct codec_type_s codec_type_t; typedef struct decoder_s decoder_t; @@ -66,13 +67,13 @@ typedef struct format_s format_t; typedef struct resample_s resample_t; typedef struct seq_packet_s seq_packet_t; typedef union codec_options_u codec_options_t; +typedef struct dtx_method_s dtx_method_t; typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *); typedef void format_init_f(struct rtp_payload_type *); typedef void set_enc_options_f(encoder_t *, const str *, const str *); typedef void set_dec_options_f(decoder_t *, const str *, const str *); typedef int format_cmp_f(const struct rtp_payload_type *, const struct rtp_payload_type *); -typedef int decoder_dtx_f(decoder_t *, GQueue *, int); @@ -117,6 +118,13 @@ union codec_options_u { } amr; }; +enum dtx_method { + DTX_NATIVE = 0, + DTX_SILENCE, + + NUM_DTX_METHODS +}; + struct codec_def_s { const char * const rtpname; int clockrate_mult; @@ -137,7 +145,7 @@ struct codec_def_s { format_init_f *init; set_enc_options_f *set_enc_options; set_dec_options_f *set_dec_options; - decoder_dtx_f *dtx; + const dtx_method_t * const dtx_methods[NUM_DTX_METHODS]; // filled in by codeclib_init() str rtpname_str; @@ -171,9 +179,16 @@ enum codec_event { CE_AMR_SEND_CMR, }; +struct dtx_method_s { + int (*init)(decoder_t *); + void (*cleanup)(decoder_t *); + int (*do_dtx)(decoder_t *, GQueue *, int); +}; + struct decoder_s { const codec_def_t *def; codec_options_t codec_options; + dtx_method_t dtx; format_t in_format, dec_out_format, @@ -281,6 +296,8 @@ decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, void decoder_close(decoder_t *dec); int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts, int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2); +gboolean decoder_has_dtx(decoder_t *); +int decoder_switch_dtx(decoder_t *dec, enum dtx_method); int decoder_dtx(decoder_t *dec, unsigned long ts, int ptime, int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2);