From ec68dfeb314653eb71ac40c5e9190ceac32def9a Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 14 May 2021 14:02:48 -0400 Subject: [PATCH] TT#122401 add configurable CN method Change-Id: I2aa9901b2a9dcf64563a84d77fa40d23b6c25525 --- daemon/codec.c | 2 ++ daemon/main.c | 52 +++++++++++++++++++++++++++----------------- daemon/rtpengine.pod | 31 ++++++++++++++++++++------ include/main.h | 1 + lib/codeclib.c | 12 ++++++++-- lib/codeclib.h | 2 ++ 6 files changed, 71 insertions(+), 29 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 799bd4a61..dd6060a85 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -2835,6 +2835,8 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) { &ch->encoder_format, &h->source_pt.format_parameters, &h->source_pt.codec_opts); if (!ch->decoder) goto err; + if (rtpe_config.dtx_cn_params.len) + decoder_set_cn_dtx(ch->decoder, &rtpe_config.dtx_cn_params); ch->decoder->event_data = h->media; ch->decoder->event_func = codec_decoder_event; diff --git a/daemon/main.c b/daemon/main.c index 690b58bab..0a44c7bd0 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -363,6 +363,32 @@ static int redis_ep_parse(endpoint_t *ep, int *db, char **auth, const char *auth } +static void parse_cn_payload(str *out, char **in, const char *def, const char *name) { + if (!in || !*in) { + if (def) + str_init_dup(out, def); + return; + } + + int len = g_strv_length(in); + if (len < 1) + die("Invalid CN payload specified (--%s)", name); + out->s = malloc(len); + for (int i = 0; i < len; i++) { + char *endp; + long p = strtol(in[i], &endp, 0); + if (endp == in[i] || *endp != '\0') + die("Invalid CN payload specified (--%s)", name); + if (p < 0 || p > 254) + die("Invalid CN payload specified (--%s)", name); + if (i == 0 && p > 127) + die("Invalid CN payload specified (--%s)", name); + out->s[i] = p; + } + out->len = len; +} + + static void options(int *argc, char ***argv) { AUTO_CLEANUP_GVBUF(if_a); @@ -395,6 +421,7 @@ static void options(int *argc, char ***argv) { AUTO_CLEANUP_GBUF(dtls_sig); double silence_detect = 0; AUTO_CLEANUP_GVBUF(cn_payload); + AUTO_CLEANUP_GVBUF(dtx_cn_params); int debug_srtp = 0; rwlock_lock_w(&rtpe_config.config_lock); @@ -494,6 +521,7 @@ static void options(int *argc, char ***argv) { { "dtx-buffer", 0,0, G_OPTION_ARG_INT, &rtpe_config.dtx_buffer,"Maxmium number of packets held in DTX buffer", "INT"}, { "dtx-lag", 0,0, G_OPTION_ARG_INT, &rtpe_config.dtx_lag, "Maxmium time span in milliseconds held in DTX buffer", "INT"}, { "dtx-shift", 0,0, G_OPTION_ARG_INT, &rtpe_config.dtx_shift, "Length of time (in ms) to shift DTX buffer after over/underflow", "INT"}, + { "dtx-cn-params",0,0, G_OPTION_ARG_STRING_ARRAY,&dtx_cn_params, "Parameters for CN generated from DTX","INT INT INT ..."}, { "silence-detect",0,0, G_OPTION_ARG_DOUBLE, &silence_detect, "Audio level threshold in percent for silence detection","FLOAT"}, { "cn-payload",0,0, G_OPTION_ARG_STRING_ARRAY,&cn_payload, "Comfort noise parameters to replace silence with","INT INT INT ..."}, { "reorder-codecs",0,0, G_OPTION_ARG_NONE, &rtpe_config.reorder_codecs,"Reorder answer codecs based on sender preference",NULL}, @@ -737,26 +765,8 @@ static void options(int *argc, char ***argv) { rtpe_config.silence_detect_int = (int) ((silence_detect / 100.0) * UINT32_MAX); } - if (!cn_payload) - str_init_dup(&rtpe_config.cn_payload, "\x20"); - else { - int len = g_strv_length(cn_payload); - if (len < 1) - die("Invalid CN payload specified"); - rtpe_config.cn_payload.s = malloc(len); - for (int i = 0; i < len; i++) { - char *endp; - long p = strtol(cn_payload[i], &endp, 0); - if (endp == cn_payload[i] || *endp != '\0') - die("Invalid CN payload specified"); - if (p < 0 || p > 254) - die("Invalid CN payload specified"); - if (i == 0 && p > 127) - die("Invalid CN payload specified"); - rtpe_config.cn_payload.s[i] = p; - } - rtpe_config.cn_payload.len = len; - } + parse_cn_payload(&rtpe_config.cn_payload, cn_payload, "\x20", "cn-payload"); + parse_cn_payload(&rtpe_config.dtx_cn_params, dtx_cn_params, NULL, "dtx-cn-params"); if (!rtpe_config.software_id) rtpe_config.software_id = g_strdup_printf("rtpengine-%s", RTPENGINE_VERSION); @@ -895,6 +905,8 @@ static void options_free(void) { g_free(rtpe_config.software_id); if (rtpe_config.cn_payload.s) free(rtpe_config.cn_payload.s); + if (rtpe_config.dtx_cn_params.s) + free(rtpe_config.dtx_cn_params.s); // free common config options config_load_free(&rtpe_config.common); diff --git a/daemon/rtpengine.pod b/daemon/rtpengine.pod index 7d2466a9a..30c34737d 100644 --- a/daemon/rtpengine.pod +++ b/daemon/rtpengine.pod @@ -785,13 +785,13 @@ non-alphanumeric characters with a dash to make it universally usable. =item B<--dtx-delay=>I Processing delay in milliseconds to handle discontinuous transmission (DTX) or -other transmission gaps for codecs that support it (currently only AMR and -AMR-WB). Defaults to zero (disabled) and applicable to transcoded audio streams -only. When enabled, delays processing of received packets for the specified -time (much like a jitter buffer) in order to trigger DTX handling when a -transmission gap occurs. The decoder is then instructed to fill in the missing -time during a transmission gap, for example by generating comfort noise. The -delay should be configured to be higher than the expected incoming jitter. +other transmission gaps. Defaults to zero (disabled) and is applicable to +transcoded audio streams only. When enabled, delays processing of received +packets for the specified time (much like a jitter buffer) in order to trigger +DTX handling when a transmission gap occurs. The decoder is then instructed to +fill in the missing time during a transmission gap, for example by generating +comfort noise. The delay should be configured to be higher than the expected +incoming jitter. =item B<--max-dtx=>I @@ -820,6 +820,19 @@ or backwards (delayed) in case of a DTX buffer overflow or underflow. An underflow occurs when RTP packets are received slower than expected, while an overflow occurs when packets are received faster than expected. +=item B<--dtx-cn-params=>I + +Specify one comfort noise parameter. This option follows the same format as +B described below. + +This option is applicable to audio generated to fill in transmission gaps +during a DTX event. The default setting is no value, which means silence will +be generated to fill in DTX gaps. + +If any CN parameters are configured, the parameters will be passed to an RFC +3389 CN decoder, and the generated comfort noise will be used to fill in DTX +gaps. + =item B<--silence-detect=>I Enable silence detection and specify threshold in percent. This option is @@ -862,6 +875,10 @@ coefficients) as per RFC 3389. Allowable values for each coefficient are between 0 and 254. Specifying spectral information is optional and the number of coefficients listed (model order) is variable. +This option is applicable only to B packets generated from the silence +detection mechanism described above. The configured CN parameters are used +directly as payload of B packets sent by B. + The default values are 32 (-32 dBov) for the noise level and no spectral information. diff --git a/include/main.h b/include/main.h index d63d288f9..ffb1b1c14 100644 --- a/include/main.h +++ b/include/main.h @@ -116,6 +116,7 @@ struct rtpengine_config { int dtx_buffer; int dtx_lag; int dtx_shift; + str dtx_cn_params; double silence_detect_double; uint32_t silence_detect_int; str cn_payload; diff --git a/lib/codeclib.c b/lib/codeclib.c index e27a2d750..ebe949994 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -697,6 +697,13 @@ int decoder_switch_dtx(decoder_t *dec, enum dtx_method dm) { return 0; } +int decoder_set_cn_dtx(decoder_t *dec, const str *cn_pl) { + if (decoder_switch_dtx(dec, DTX_CN)) + return -1; + dec->dtx.u.cn.cn_payload = cn_pl; + return 0; +} + gboolean decoder_has_dtx(decoder_t *dec) { return dec->dtx.do_dtx == NULL ? FALSE : TRUE; @@ -2317,8 +2324,9 @@ static int cn_append_frame(decoder_t *dec, AVFrame *f, void *u1, void *u2) { } static int generic_cn_dtx(decoder_t *dec, GQueue *out, int ptime) { - static const str cn_pl = { "\x10", 1 }; - return decoder_input_data(dec->dtx.u.cn.cn_dec, &cn_pl, dec->rtp_ts, cn_append_frame, out, NULL); + dec->dtx.u.cn.cn_dec->ptime = ptime; + return decoder_input_data(dec->dtx.u.cn.cn_dec, dec->dtx.u.cn.cn_payload, + dec->rtp_ts, cn_append_frame, out, NULL); } static int generic_cn_dtx_init(decoder_t *dec) { diff --git a/lib/codeclib.h b/lib/codeclib.h index 834eca732..d34e06e91 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -188,6 +188,7 @@ struct dtx_method_s { union { struct { decoder_t *cn_dec; + const str *cn_payload; } cn; } u; }; @@ -305,6 +306,7 @@ 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_set_cn_dtx(decoder_t *dec, const str *); int decoder_dtx(decoder_t *dec, unsigned long ts, int ptime, int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2);