<div dir="ltr"><div dir="ltr"><div>Hi everyone,</div><div><br></div><div>Some time ago, I sent a <a href="https://github.com/xiph/opus/pull/107">pull request</a> to the Opus github page. Jean-Marc asked me to post it to the mailing list so everyone can have a look at it.</div><div><br></div><div>You can find the description and code changes below. Please let me know if you have any questions or concerns.</div><div><br></div><div>Best regards</div><div>Gustaf Ullberg</div><div><br></div><div>In WebRTC, we would like to be able to differentiate between "normal" frames and the comfort noise update frames that are encoded before and in-between DTX frames. These CNG update frames could then be flagged for routing or statistics reasons. Such flagging could also make it easier for a jitterbuffer to differ DTX from packet loss.<br></div><div><br></div><div>This PR implements an encoder CTL named OPUS_GET_IN_DTX. OPUS_GET_IN_DTX returns 1 if the last encoded frame was either a DTX frame, or a CNG update frame that is sent every 420 ms between the DTX frames.</div><div><br></div><div>This is achieved by checking if the number of consecutive inactive frames (nb_no_activity_frames) is greater or equal to NB_SPEECH_FRAMES_BEFORE_DTX.</div><div><br></div><div><br></div><div><font face="monospace, monospace">diff --git a/include/opus_defines.h b/include/opus_defines.h</font></div><div><font face="monospace, monospace">index fbf5d0eb..e35114e4 100644</font></div><div><font face="monospace, monospace">--- a/include/opus_defines.h</font></div><div><font face="monospace, monospace">+++ b/include/opus_defines.h</font></div><div><font face="monospace, monospace">@@ -168,6 +168,7 @@ extern "C" {</font></div><div><font face="monospace, monospace"> /* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */</font></div><div><font face="monospace, monospace"> #define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046</font></div><div><font face="monospace, monospace"> #define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047</font></div><div><font face="monospace, monospace">+#define OPUS_GET_IN_DTX_REQUEST              4049</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace"> /** Defines for the presence of extended APIs. */</font></div><div><font face="monospace, monospace"> #define OPUS_HAVE_OPUS_PROJECTION_H</font></div><div><font face="monospace, monospace">@@ -715,6 +716,16 @@ extern "C" {</font></div><div><font face="monospace, monospace">   * </dl></font></div><div><font face="monospace, monospace">   * @hideinitializer */</font></div><div><font face="monospace, monospace"> #define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)</font></div><div><font face="monospace, monospace">+/** Gets the DTX state of the encoder.</font></div><div><font face="monospace, monospace">+  * Returns wheter the last encoded frame was either a comfort noise update</font></div><div><font face="monospace, monospace">+  * during DTX or not encoded because of DTX.</font></div><div><font face="monospace, monospace">+  * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:</font></div><div><font face="monospace, monospace">+  * <dl></font></div><div><font face="monospace, monospace">+  * <dt>0</dt><dd>The encoder is not in DTX.</dd></font></div><div><font face="monospace, monospace">+  * <dt>1</dt><dd>The encoder is in DTX.</dd></font></div><div><font face="monospace, monospace">+  * </dl></font></div><div><font face="monospace, monospace">+  * @hideinitializer */</font></div><div><font face="monospace, monospace">+#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace"> /**@}*/</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">diff --git a/src/opus_encoder.c b/src/opus_encoder.c</font></div><div><font face="monospace, monospace">index cbeb40ae..0d84737a 100644</font></div><div><font face="monospace, monospace">--- a/src/opus_encoder.c</font></div><div><font face="monospace, monospace">+++ b/src/opus_encoder.c</font></div><div><font face="monospace, monospace">@@ -2725,6 +2725,27 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...)</font></div><div><font face="monospace, monospace">             ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value));</font></div><div><font face="monospace, monospace">         }</font></div><div><font face="monospace, monospace">         break;</font></div><div><font face="monospace, monospace">+        case OPUS_GET_IN_DTX_REQUEST:</font></div><div><font face="monospace, monospace">+        {</font></div><div><font face="monospace, monospace">+            opus_int32 *value = va_arg(ap, opus_int32*);</font></div><div><font face="monospace, monospace">+            if (!value)</font></div><div><font face="monospace, monospace">+            {</font></div><div><font face="monospace, monospace">+                goto bad_arg;</font></div><div><font face="monospace, monospace">+            }</font></div><div><font face="monospace, monospace">+            *value = 0;</font></div><div><font face="monospace, monospace">+            if (st->silk_mode.useDTX) {</font></div><div><font face="monospace, monospace">+                /* DTX determined by Silk. */</font></div><div><font face="monospace, monospace">+                void *silk_enc = (char*)st+st->silk_enc_offset;</font></div><div><font face="monospace, monospace">+                *value = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX;</font></div><div><font face="monospace, monospace">+            }</font></div><div><font face="monospace, monospace">+#ifndef DISABLE_FLOAT_API</font></div><div><font face="monospace, monospace">+            else if (st->use_dtx) {</font></div><div><font face="monospace, monospace">+                /* DTX determined by Opus. */</font></div><div><font face="monospace, monospace">+                *value = st->nb_no_activity_frames >= NB_SPEECH_FRAMES_BEFORE_DTX;</font></div><div><font face="monospace, monospace">+            }</font></div><div><font face="monospace, monospace">+#endif</font></div><div><font face="monospace, monospace">+        }</font></div><div><font face="monospace, monospace">+        break;</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">         case CELT_GET_MODE_REQUEST:</font></div><div><font face="monospace, monospace">         {</font></div><div><br></div></div></div>