From 5609cec9a5e1ea8fcb056f2306a115cb3b61c4c9 Mon Sep 17 00:00:00 2001
From: Jean-Marc Valin <jmvalin@jmvalin.ca>
Date: Tue, 13 Dec 2011 14:52:43 -0500
Subject: [PATCH] Fixes two minor issues found in random testing at
 ridiculously low rate.

- When it cannot produce the rate it's being asked, the encoder now
  returns a "PLC packet"
- Makes it possible to use the CELT PLC for more than 20 ms
---
 src/opus_decoder.c | 14 ++++++++++++++
 src/opus_encoder.c | 21 +++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 3df0cdfce..97e3e9689 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -246,6 +246,20 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
       }
    }
 
+   /* For CELT/hybrid PLC of more than 20 ms, do multiple calls */
+   if (data==NULL && frame_size > F20 && mode != MODE_SILK_ONLY)
+   {
+      int nb_samples = 0;
+      do {
+         int ret = opus_decode_frame(st, NULL, 0, pcm, F20, 0);
+         if (ret != F20)
+            return OPUS_INTERNAL_ERROR;
+         pcm += F20*st->channels;
+         nb_samples += F20;
+      } while (nb_samples < frame_size);
+      RESTORE_STACK;
+      return frame_size;
+   }
    ALLOC(pcm_transition, F5*st->channels, opus_val16);
 
    if (data!=NULL && st->prev_mode > 0 && (
diff --git a/src/opus_encoder.c b/src/opus_encoder.c
index 54b48d421..b95cf2889 100644
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -479,6 +479,11 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
        RESTORE_STACK;
        return OPUS_BAD_ARG;
     }
+    if (max_data_bytes<=0)
+    {
+       RESTORE_STACK;
+       return OPUS_BAD_ARG;
+    }
     silk_enc = (char*)st+st->silk_enc_offset;
     celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
 
@@ -490,6 +495,22 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes);
 
     frame_rate = st->Fs/frame_size;
+    if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8
+       || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400)))
+    {
+       int tocmode = st->mode;
+       if (tocmode==0)
+          tocmode = MODE_SILK_ONLY;
+       if (frame_rate>100)
+          tocmode = MODE_CELT_ONLY;
+       if (frame_rate < 50)
+          tocmode = MODE_SILK_ONLY;
+       data[0] = gen_toc(tocmode, frame_rate,
+                         st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth,
+                         st->stream_channels);
+       RESTORE_STACK;
+       return 1;
+    }
     if (!st->use_vbr)
     {
        int cbrBytes;
-- 
GitLab