Fixes FEC issues introduced in 7fcd66c
[opus.git] / src / opus_decoder.c
index cf838df..32b849b 100644 (file)
@@ -65,6 +65,9 @@ struct OpusDecoder {
    int          frame_size;
    int          prev_redundancy;
    int          last_packet_duration;
+#ifndef FIXED_POINT
+   opus_val16   softclip_mem[2];
+#endif
 
    opus_uint32  rangeFinal;
 };
@@ -543,6 +546,13 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
 
    st->prev_mode = mode;
    st->prev_redundancy = redundancy && !celt_to_silk;
+
+   if (celt_ret>=0)
+   {
+      if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
+         OPUS_PRINT_INT(audiosize);
+   }
+
    RESTORE_STACK;
    return celt_ret < 0 ? celt_ret : audiosize;
 
@@ -725,7 +735,7 @@ int opus_packet_parse(const unsigned char *data, opus_int32 len,
 
 int opus_decode_native(OpusDecoder *st, const unsigned char *data,
       opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
-      int self_delimited, int *packet_offset)
+      int self_delimited, int *packet_offset, int soft_clip)
 {
    int i, nb_samples;
    int count, offset;
@@ -744,12 +754,15 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
       int pcm_count=0;
       do {
          int ret;
-         ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0);
+         ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
          if (ret<0)
             return ret;
-         pcm += st->channels*ret;
          pcm_count += ret;
       } while (pcm_count < frame_size);
+      celt_assert(pcm_count == frame_size);
+      if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
+         OPUS_PRINT_INT(pcm_count);
+      st->last_packet_duration = pcm_count;
       return pcm_count;
    } else if (len<0)
       return OPUS_BAD_ARG;
@@ -765,14 +778,23 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
 
    if (decode_fec)
    {
+      int duration_copy;
       int ret;
       /* If no FEC can be present, run the PLC (recursive call) */
-      if (frame_size <= packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
-         return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL);
+      if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
+         return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
       /* Otherwise, run the PLC on everything except the size for which we might have FEC */
-      ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-packet_frame_size, 0);
-      if (ret<0)
-         return ret;
+      duration_copy = st->last_packet_duration;
+      if (frame_size-packet_frame_size!=0)
+      {
+         ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
+         if (ret<0)
+         {
+            st->last_packet_duration = duration_copy;
+            return ret;
+         }
+         celt_assert(ret==frame_size-packet_frame_size);
+      }
       /* Complete with FEC */
       st->mode = packet_mode;
       st->bandwidth = packet_bandwidth;
@@ -782,8 +804,12 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
             packet_frame_size, 1);
       if (ret<0)
          return ret;
-      else
+      else {
+         if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
+            OPUS_PRINT_INT(frame_size);
+         st->last_packet_duration = frame_size;
          return frame_size;
+      }
    }
    tot_offset = 0;
    if (count < 0)
@@ -804,17 +830,25 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
    for (i=0;i<count;i++)
    {
       int ret;
-      ret = opus_decode_frame(st, data, size[i], pcm, frame_size-nb_samples, decode_fec);
+      ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
       if (ret<0)
          return ret;
+      celt_assert(ret==packet_frame_size);
       data += size[i];
       tot_offset += size[i];
-      pcm += ret*st->channels;
       nb_samples += ret;
    }
    if (packet_offset != NULL)
       *packet_offset = tot_offset;
    st->last_packet_duration = nb_samples;
+   if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
+      OPUS_PRINT_INT(nb_samples);
+#ifndef FIXED_POINT
+   if (soft_clip)
+      opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
+   else
+      st->softclip_mem[0]=st->softclip_mem[1]=0;
+#endif
    return nb_samples;
 }
 
@@ -823,7 +857,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
 int opus_decode(OpusDecoder *st, const unsigned char *data,
       opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
 {
-   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL);
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
 }
 
 #ifndef DISABLE_FLOAT_API
@@ -836,7 +870,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data,
 
    ALLOC(out, frame_size*st->channels, opus_int16);
 
-   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL);
+   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
    if (ret > 0)
    {
       for (i=0;i<ret*st->channels;i++)
@@ -864,7 +898,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
 
    ALLOC(out, frame_size*st->channels, float);
 
-   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL);
+   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
    if (ret > 0)
    {
       for (i=0;i<ret*st->channels;i++)
@@ -877,7 +911,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
 int opus_decode_float(OpusDecoder *st, const unsigned char *data,
       opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
 {
-   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL);
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
 }
 
 #endif