shithub: opus

Download patch

ref: 8101b33e6c59b51b22aeeeaf39045e34a402b01f
parent: ccaaffa9a3ee427e9401c4dcf6462e378d9a4694
author: Mark Harris <mark.hsj@gmail.com>
date: Mon Jun 20 18:23:26 EDT 2022

Correct redundancy handling with lost/DTX frames

In https://github.com/xiph/opus/issues/253, the encoder generates a
Hybrid frame with redundancy, to switch to CELT-only mode, and then
activates DTX immediately afterwards.  The decoder ran Hybrid PLC,
which isn't right.  Use CELT PLC instead if there was already a
transition to CELT via redundancy at the end of the previous frame.

Also do not use a stale CELT decoder to decode a second redundancy
frame when the first redundancy frame for a transition from SILK-only
mode was lost.  Instead of mixing in old audio from the last time
that CELT was used, ignore the second redundancy frame in this case.
Alternatively the CELT decoder could be reset before decoding, but
it would not be ready until after the 2.5 ms of audio that is needed.

Reviewed by Jean-Marc Valin.

--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -278,7 +278,8 @@
       ec_dec_init(&dec,(unsigned char*)data,len);
    } else {
       audiosize = frame_size;
-      mode = st->prev_mode;
+      /* Run PLC using last used mode (CELT if we ended with CELT redundancy) */
+      mode = st->prev_redundancy ? MODE_CELT_ONLY : st->prev_mode;
       bandwidth = 0;
 
       if (mode == 0)
@@ -419,7 +420,7 @@
 
    start_band = 0;
    if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
-    && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len)
+    && ec_tell(&dec)+17+20*(mode == MODE_HYBRID) <= 8*len)
    {
       /* Check if we have a redundant 0-8 kHz band */
       if (mode == MODE_HYBRID)
@@ -454,6 +455,10 @@
    {
       transition = 0;
       pcm_transition_silk_size=ALLOC_NONE;
+      /* don't use stale CELT decoder to decode second redundancy frame if
+         the first redundancy frame for a transition from SILK was lost */
+      if (celt_to_silk && st->prev_mode == MODE_SILK_ONLY && !st->prev_redundancy)
+         redundancy = 0;
    }
 
    ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);