Adding a missing "else"
[opus.git] / src / opus_decoder.c
index cf838df..149ae7f 100644 (file)
 */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
 #endif
 
 #ifndef OPUS_BUILD
-#error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
+# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW)
+# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
 #endif
 
 #include <stdarg.h>
@@ -46,6 +50,7 @@
 #include "structs.h"
 #include "define.h"
 #include "mathops.h"
+#include "cpu_support.h"
 
 struct OpusDecoder {
    int          celt_dec_offset;
@@ -54,6 +59,7 @@ struct OpusDecoder {
    opus_int32   Fs;          /** Sampling rate (at the API level) */
    silk_DecControlStruct DecControl;
    int          decode_gain;
+   int          arch;
 
    /* Everything beyond this point gets cleared on a reset */
 #define OPUS_DECODER_RESET_START stream_channels
@@ -65,16 +71,13 @@ struct OpusDecoder {
    int          frame_size;
    int          prev_redundancy;
    int          last_packet_duration;
+#ifndef FIXED_POINT
+   opus_val16   softclip_mem[2];
+#endif
 
    opus_uint32  rangeFinal;
 };
 
-#ifdef FIXED_POINT
-static inline opus_int16 SAT16(opus_int32 x) {
-   return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
-}
-#endif
-
 
 int opus_decoder_get_size(int channels)
 {
@@ -129,6 +132,7 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
 
    st->prev_mode = 0;
    st->frame_size = Fs/400;
+   st->arch = opus_select_arch();
    return OPUS_OK;
 }
 
@@ -207,7 +211,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
    VARDECL(opus_val16, pcm_transition_silk);
    int pcm_transition_celt_size;
    VARDECL(opus_val16, pcm_transition_celt);
-   opus_val16 *pcm_transition;
+   opus_val16 *pcm_transition=NULL;
    int redundant_audio_size;
    VARDECL(opus_val16, redundant_audio);
 
@@ -222,6 +226,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
    int F2_5, F5, F10, F20;
    const opus_val16 *window;
    opus_uint32 redundant_rng = 0;
+   int celt_accum;
    ALLOC_STACK;
 
    silk_dec = (char*)st+st->silk_dec_offset;
@@ -251,26 +256,52 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
       ec_dec_init(&dec,(unsigned char*)data,len);
    } else {
       audiosize = frame_size;
+      mode = st->prev_mode;
 
-      if (st->prev_mode == 0)
+      if (mode == 0)
       {
          /* If we haven't got any packet yet, all we can do is return zeros */
          for (i=0;i<audiosize*st->channels;i++)
             pcm[i] = 0;
          RESTORE_STACK;
          return audiosize;
-      } else {
-         mode = st->prev_mode;
+      }
+
+      /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
+         10, or 20 (e.g. 12.5 or 30 ms). */
+      if (audiosize > F20)
+      {
+         do {
+            int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0);
+            if (ret<0)
+            {
+               RESTORE_STACK;
+               return ret;
+            }
+            pcm += ret*st->channels;
+            audiosize -= ret;
+         } while (audiosize > 0);
+         RESTORE_STACK;
+         return frame_size;
+      } else if (audiosize < F20)
+      {
+         if (audiosize > F10)
+            audiosize = F10;
+         else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
+            audiosize = F5;
       }
    }
 
-   /* For CELT/hybrid PLC of more than 20 ms, opus_decode_native() will do
-      multiple calls */
-   if (data==NULL  && mode != MODE_SILK_ONLY)
-      frame_size = IMIN(frame_size, F20);
+   /* In fixed-point, we can tell CELT to do the accumulation on top of the
+      SILK PCM buffer. This saves some stack space. */
+#ifdef FIXED_POINT
+   celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10);
+#else
+   celt_accum = 0;
+#endif
 
-   pcm_transition_silk_size = 0;
-   pcm_transition_celt_size = 0;
+   pcm_transition_silk_size = ALLOC_NONE;
+   pcm_transition_celt_size = ALLOC_NONE;
    if (data!=NULL && st->prev_mode > 0 && (
        (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy)
     || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) )
@@ -299,14 +330,20 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
    }
 
    /* Don't allocate any memory when in CELT-only mode */
-   pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : 0;
+   pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
    ALLOC(pcm_silk, pcm_silk_size, opus_int16);
 
    /* SILK processing */
    if (mode != MODE_CELT_ONLY)
    {
       int lost_flag, decoded_samples;
-      opus_int16 *pcm_ptr = pcm_silk;
+      opus_int16 *pcm_ptr;
+#ifdef FIXED_POINT
+      if (celt_accum)
+         pcm_ptr = pcm;
+      else
+#endif
+         pcm_ptr = pcm_silk;
 
       if (st->prev_mode==MODE_CELT_ONLY)
          silk_InitDecoder( silk_dec );
@@ -340,7 +377,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         /* Call SILK decoder */
         int first_frame = decoded_samples == 0;
         silk_ret = silk_Decode( silk_dec, &st->DecControl,
-                                lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size );
+                                lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch );
         if( silk_ret ) {
            if (lost_flag) {
               /* PLC failure should not be fatal */
@@ -349,7 +386,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
                  pcm_ptr[i] = 0;
            } else {
              RESTORE_STACK;
-             return OPUS_INVALID_PACKET;
+             return OPUS_INTERNAL_ERROR;
            }
         }
         pcm_ptr += silk_frame_size * st->channels;
@@ -416,7 +453,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
    if (redundancy)
    {
       transition = 0;
-      pcm_transition_silk_size=0;
+      pcm_transition_silk_size=ALLOC_NONE;
    }
 
    ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);
@@ -428,7 +465,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
    }
 
    /* Only allocation memory for redundancy if/when needed */
-   redundant_audio_size = redundancy ? F5*st->channels : 0;
+   redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
    ALLOC(redundant_audio, redundant_audio_size, opus_val16);
 
    /* 5 ms redundant frame for CELT->SILK*/
@@ -436,7 +473,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
    {
       celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
       celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
-                          redundant_audio, F5, NULL);
+                          redundant_audio, F5, NULL, 0);
       celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
    }
 
@@ -451,25 +488,28 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
          celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
       /* Decode CELT */
       celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
-                                     len, pcm, celt_frame_size, &dec);
+                                     len, pcm, celt_frame_size, &dec, celt_accum);
    } else {
       unsigned char silence[2] = {0xFF, 0xFF};
-      for (i=0;i<frame_size*st->channels;i++)
-         pcm[i] = 0;
+      if (!celt_accum)
+      {
+         for (i=0;i<frame_size*st->channels;i++)
+            pcm[i] = 0;
+      }
       /* For hybrid -> SILK transitions, we let the CELT MDCT
          do a fade-out by decoding a silence frame */
       if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
       {
          celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
-         celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL);
+         celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum);
       }
    }
 
-   if (mode != MODE_CELT_ONLY)
+   if (mode != MODE_CELT_ONLY && !celt_accum)
    {
 #ifdef FIXED_POINT
       for (i=0;i<frame_size*st->channels;i++)
-         pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
+         pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i]));
 #else
       for (i=0;i<frame_size*st->channels;i++)
          pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
@@ -488,7 +528,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
       celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
       celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
 
-      celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
+      celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0);
       celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
       smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
                   pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
@@ -543,197 +583,28 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
 
    st->prev_mode = mode;
    st->prev_redundancy = redundancy && !celt_to_silk;
-   RESTORE_STACK;
-   return celt_ret < 0 ? celt_ret : audiosize;
-
-}
-
-static int parse_size(const unsigned char *data, opus_int32 len, short *size)
-{
-   if (len<1)
-   {
-      *size = -1;
-      return -1;
-   } else if (data[0]<252)
-   {
-      *size = data[0];
-      return 1;
-   } else if (len<2)
-   {
-      *size = -1;
-      return -1;
-   } else {
-      *size = 4*data[1] + data[0];
-      return 2;
-   }
-}
-
-static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
-      int self_delimited, unsigned char *out_toc,
-      const unsigned char *frames[48], short size[48], int *payload_offset)
-{
-   int i, bytes;
-   int count;
-   int cbr;
-   unsigned char ch, toc;
-   int framesize;
-   opus_int32 last_size;
-   const unsigned char *data0 = data;
-
-   if (size==NULL)
-      return OPUS_BAD_ARG;
-
-   framesize = opus_packet_get_samples_per_frame(data, 48000);
-
-   cbr = 0;
-   toc = *data++;
-   len--;
-   last_size = len;
-   switch (toc&0x3)
-   {
-   /* One frame */
-   case 0:
-      count=1;
-      break;
-   /* Two CBR frames */
-   case 1:
-      count=2;
-      cbr = 1;
-      if (!self_delimited)
-      {
-         if (len&0x1)
-            return OPUS_INVALID_PACKET;
-         last_size = len/2;
-         /* If last_size doesn't fit in size[0], we'll catch it later */
-         size[0] = (short)last_size;
-      }
-      break;
-   /* Two VBR frames */
-   case 2:
-      count = 2;
-      bytes = parse_size(data, len, size);
-      len -= bytes;
-      if (size[0]<0 || size[0] > len)
-         return OPUS_INVALID_PACKET;
-      data += bytes;
-      last_size = len-size[0];
-      break;
-   /* Multiple CBR/VBR frames (from 0 to 120 ms) */
-   default: /*case 3:*/
-      if (len<1)
-         return OPUS_INVALID_PACKET;
-      /* Number of frames encoded in bits 0 to 5 */
-      ch = *data++;
-      count = ch&0x3F;
-      if (count <= 0 || framesize*count > 5760)
-         return OPUS_INVALID_PACKET;
-      len--;
-      /* Padding flag is bit 6 */
-      if (ch&0x40)
-      {
-         int p;
-         do {
-            if (len<=0)
-               return OPUS_INVALID_PACKET;
-            p = *data++;
-            len--;
-            len -= p==255 ? 254: p;
-         } while (p==255);
-      }
-      if (len<0)
-         return OPUS_INVALID_PACKET;
-      /* VBR flag is bit 7 */
-      cbr = !(ch&0x80);
-      if (!cbr)
-      {
-         /* VBR case */
-         last_size = len;
-         for (i=0;i<count-1;i++)
-         {
-            bytes = parse_size(data, len, size+i);
-            len -= bytes;
-            if (size[i]<0 || size[i] > len)
-               return OPUS_INVALID_PACKET;
-            data += bytes;
-            last_size -= bytes+size[i];
-         }
-         if (last_size<0)
-            return OPUS_INVALID_PACKET;
-      } else if (!self_delimited)
-      {
-         /* CBR case */
-         last_size = len/count;
-         if (last_size*count!=len)
-            return OPUS_INVALID_PACKET;
-         for (i=0;i<count-1;i++)
-            size[i] = (short)last_size;
-      }
-      break;
-   }
-   /* Self-delimited framing has an extra size for the last frame. */
-   if (self_delimited)
-   {
-      bytes = parse_size(data, len, size+count-1);
-      len -= bytes;
-      if (size[count-1]<0 || size[count-1] > len)
-         return OPUS_INVALID_PACKET;
-      data += bytes;
-      /* For CBR packets, apply the size to all the frames. */
-      if (cbr)
-      {
-         if (size[count-1]*count > len)
-            return OPUS_INVALID_PACKET;
-         for (i=0;i<count-1;i++)
-            size[i] = size[count-1];
-      } else if(size[count-1] > last_size)
-         return OPUS_INVALID_PACKET;
-   } else
-   {
-      /* Because it's not encoded explicitly, it's possible the size of the
-         last packet (or all the packets, for the CBR case) is larger than
-         1275. Reject them here.*/
-      if (last_size > 1275)
-         return OPUS_INVALID_PACKET;
-      size[count-1] = (short)last_size;
-   }
 
-   if (frames)
+   if (celt_ret>=0)
    {
-      for (i=0;i<count;i++)
-      {
-         frames[i] = data;
-         data += size[i];
-      }
+      if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
+         OPUS_PRINT_INT(audiosize);
    }
 
-   if (out_toc)
-      *out_toc = toc;
-
-   if (payload_offset)
-      *payload_offset = (int)(data-data0);
-
-   return count;
-}
+   RESTORE_STACK;
+   return celt_ret < 0 ? celt_ret : audiosize;
 
-int opus_packet_parse(const unsigned char *data, opus_int32 len,
-      unsigned char *out_toc, const unsigned char *frames[48],
-      short size[48], int *payload_offset)
-{
-   return opus_packet_parse_impl(data, len, 0, out_toc,
-                                 frames, size, payload_offset);
 }
 
 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, opus_int32 *packet_offset, int soft_clip)
 {
    int i, nb_samples;
    int count, offset;
    unsigned char toc;
-   int tot_offset;
    int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
    /* 48 x 2.5 ms = 120 ms */
-   short size[48];
+   opus_int16 size[48];
    if (decode_fec<0 || decode_fec>1)
       return OPUS_BAD_ARG;
    /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
@@ -744,12 +615,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;
@@ -759,20 +633,32 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
    packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
    packet_stream_channels = opus_packet_get_nb_channels(data);
 
-   count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
+   count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+                                  size, &offset, packet_offset);
+   if (count<0)
+      return count;
 
    data += offset;
 
    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,14 +668,13 @@ 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)
-      return count;
-
-   tot_offset += offset;
 
    if (count*packet_frame_size > frame_size)
       return OPUS_BUFFER_TOO_SMALL;
@@ -804,17 +689,22 @@ 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 +713,9 @@ 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);
+   if(frame_size<=0)
+      return OPUS_BAD_ARG;
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
 }
 
 #ifndef DISABLE_FLOAT_API
@@ -832,11 +724,25 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data,
 {
    VARDECL(opus_int16, out);
    int ret, i;
+   int nb_samples;
    ALLOC_STACK;
 
+   if(frame_size<=0)
+   {
+      RESTORE_STACK;
+      return OPUS_BAD_ARG;
+   }
+   if (data != NULL && len > 0 && !decode_fec)
+   {
+      nb_samples = opus_decoder_get_nb_samples(st, data, len);
+      if (nb_samples>0)
+         frame_size = IMIN(frame_size, nb_samples);
+      else
+         return OPUS_INVALID_PACKET;
+   }
    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++)
@@ -854,17 +760,26 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
 {
    VARDECL(float, out);
    int ret, i;
+   int nb_samples;
    ALLOC_STACK;
 
-   if(frame_size<0)
+   if(frame_size<=0)
    {
       RESTORE_STACK;
       return OPUS_BAD_ARG;
    }
 
+   if (data != NULL && len > 0 && !decode_fec)
+   {
+      nb_samples = opus_decoder_get_nb_samples(st, data, len);
+      if (nb_samples>0)
+         frame_size = IMIN(frame_size, nb_samples);
+      else
+         return OPUS_INVALID_PACKET;
+   }
    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 +792,9 @@ 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);
+   if(frame_size<=0)
+      return OPUS_BAD_ARG;
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
 }
 
 #endif
@@ -900,12 +817,20 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
    case OPUS_GET_BANDWIDTH_REQUEST:
    {
       opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
       *value = st->bandwidth;
    }
    break;
    case OPUS_GET_FINAL_RANGE_REQUEST:
    {
       opus_uint32 *value = va_arg(ap, opus_uint32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
       *value = st->rangeFinal;
    }
    break;
@@ -924,10 +849,9 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
    case OPUS_GET_SAMPLE_RATE_REQUEST:
    {
       opus_int32 *value = va_arg(ap, opus_int32*);
-      if (value==NULL)
+      if (!value)
       {
-         ret = OPUS_BAD_ARG;
-         break;
+         goto bad_arg;
       }
       *value = st->Fs;
    }
@@ -935,10 +859,9 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
    case OPUS_GET_PITCH_REQUEST:
    {
       opus_int32 *value = va_arg(ap, opus_int32*);
-      if (value==NULL)
+      if (!value)
       {
-         ret = OPUS_BAD_ARG;
-         break;
+         goto bad_arg;
       }
       if (st->prev_mode == MODE_CELT_ONLY)
          celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
@@ -949,10 +872,9 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
    case OPUS_GET_GAIN_REQUEST:
    {
       opus_int32 *value = va_arg(ap, opus_int32*);
-      if (value==NULL)
+      if (!value)
       {
-         ret = OPUS_BAD_ARG;
-         break;
+         goto bad_arg;
       }
       *value = st->decode_gain;
    }
@@ -962,18 +884,41 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
        opus_int32 value = va_arg(ap, opus_int32);
        if (value<-32768 || value>32767)
        {
-          ret = OPUS_BAD_ARG;
-          break;
+          goto bad_arg;
        }
        st->decode_gain = value;
    }
    break;
    case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
    {
-      opus_uint32 *value = va_arg(ap, opus_uint32*);
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      if (!value)
+      {
+         goto bad_arg;
+      }
       *value = st->last_packet_duration;
    }
    break;
+   case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+   {
+       opus_int32 value = va_arg(ap, opus_int32);
+       if(value<0 || value>1)
+       {
+          goto bad_arg;
+       }
+       celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value));
+   }
+   break;
+   case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+   {
+       opus_int32 *value = va_arg(ap, opus_int32*);
+       if (!value)
+       {
+          goto bad_arg;
+       }
+       celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value));
+   }
+   break;
    default:
       /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
       ret = OPUS_UNIMPLEMENTED;
@@ -982,6 +927,9 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
 
    va_end(ap);
    return ret;
+bad_arg:
+   va_end(ap);
+   return OPUS_BAD_ARG;
 }
 
 void opus_decoder_destroy(OpusDecoder *st)
@@ -1008,27 +956,6 @@ int opus_packet_get_bandwidth(const unsigned char *data)
    return bandwidth;
 }
 
-int opus_packet_get_samples_per_frame(const unsigned char *data,
-      opus_int32 Fs)
-{
-   int audiosize;
-   if (data[0]&0x80)
-   {
-      audiosize = ((data[0]>>3)&0x3);
-      audiosize = (Fs<<audiosize)/400;
-   } else if ((data[0]&0x60) == 0x60)
-   {
-      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
-   } else {
-      audiosize = ((data[0]>>3)&0x3);
-      if (audiosize == 3)
-         audiosize = Fs*60/1000;
-      else
-         audiosize = (Fs<<audiosize)/100;
-   }
-   return audiosize;
-}
-
 int opus_packet_get_nb_channels(const unsigned char *data)
 {
    return (data[0]&0x4) ? 2 : 1;