Removed all the silk_ prefixes in source file names (not symbols)
[opus.git] / src / opus_decoder.c
index d8f4af4..c607edf 100644 (file)
 #include "config.h"
 #endif
 
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <stdarg.h>
 #include "celt.h"
-#include "opus_decoder.h"
+#include "opus.h"
 #include "entdec.h"
 #include "modes.h"
-#include "silk_API.h"
+#include "API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus_private.h"
+#include "os_support.h"
+#include "structs.h"
+#include "define.h"
+
+struct OpusDecoder {
+   int          celt_dec_offset;
+   int          silk_dec_offset;
+   int          channels;
+   opus_int32   Fs;          /** Sampling rate (at the API level) */
+
+   /* Everything beyond this point gets cleared on a reset */
+#define OPUS_DECODER_RESET_START stream_channels
+   int          stream_channels;
+
+   int          bandwidth;
+   int          mode;
+   int          prev_mode;
+   int          frame_size;
+   int          prev_redundancy;
+
+   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
 
-/* Make sure everything's aligned to 4 bytes (this may need to be increased
-   on really weird architectures) */
-static inline int align(int i)
-{
-       return (i+3)&-4;
-}
 
 int opus_decoder_get_size(int channels)
 {
-       int silkDecSizeBytes, celtDecSizeBytes;
-       int ret;
-    ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
-       if(ret)
-               return 0;
-       silkDecSizeBytes = align(silkDecSizeBytes);
-    celtDecSizeBytes = celt_decoder_get_size(channels);
-    return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
-
+   int silkDecSizeBytes, celtDecSizeBytes;
+   int ret;
+   if (channels<1 || channels > 2)
+      return 0;
+   ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
+   if(ret)
+      return 0;
+   silkDecSizeBytes = align(silkDecSizeBytes);
+   celtDecSizeBytes = celt_decoder_get_size(channels);
+   return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
 }
 
-OpusDecoder *opus_decoder_init(OpusDecoder *st, int Fs, int channels)
+int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
 {
-       void *silk_dec;
-       CELTDecoder *celt_dec;
-       int ret, silkDecSizeBytes;
-
-       if (channels<1 || channels > 2)
-           return NULL;
-       memset(st, 0, opus_decoder_get_size(channels));
-       /* Initialize SILK encoder */
-    ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
-    if( ret ) {
-        return NULL;
-    }
-    silkDecSizeBytes = align(silkDecSizeBytes);
-    st->silk_dec_offset = align(sizeof(OpusDecoder));
-    st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
-    silk_dec = (char*)st+st->silk_dec_offset;
-    celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
-    st->stream_channels = st->channels = channels;
+   void *silk_dec;
+   CELTDecoder *celt_dec;
+   int ret, silkDecSizeBytes;
 
-    st->Fs = Fs;
+   if (channels<1 || channels > 2)
+      return OPUS_BAD_ARG;
+   OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
+   /* Initialize SILK encoder */
+   ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
+   if(ret)return OPUS_INTERNAL_ERROR;
 
-    /* Reset decoder */
-    ret = silk_InitDecoder( silk_dec );
-    if( ret ) {
-        goto failure;
-    }
+   silkDecSizeBytes = align(silkDecSizeBytes);
+   st->silk_dec_offset = align(sizeof(OpusDecoder));
+   st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
+   silk_dec = (char*)st+st->silk_dec_offset;
+   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+   st->stream_channels = st->channels = channels;
+
+   st->Fs = Fs;
+
+   /* Reset decoder */
+   ret = silk_InitDecoder( silk_dec );
+   if(ret)return OPUS_INTERNAL_ERROR;
 
-       /* Initialize CELT decoder */
-       celt_decoder_init(celt_dec, Fs, channels, &ret);
-       if (ret != CELT_OK)
-               goto failure;
-    celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
-
-       st->prev_mode = 0;
-       return st;
-failure:
-    free(st);
-    return NULL;
+   /* Initialize CELT decoder */
+   ret = celt_decoder_init(celt_dec, Fs, channels);
+   if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+   celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
+
+   st->prev_mode = 0;
+   st->frame_size = Fs/400;
+   return OPUS_OK;
 }
 
-OpusDecoder *opus_decoder_create(int Fs, int channels)
+OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
 {
-    char *raw_state = (char*)malloc(opus_decoder_get_size(channels));
-    if (raw_state == NULL)
-       return NULL;
-    return opus_decoder_init((OpusDecoder*)raw_state, Fs, channels);
+   int ret;
+   OpusDecoder *st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
+   if (st == NULL)
+   {
+      if (error)
+         *error = OPUS_ALLOC_FAIL;
+      return NULL;
+   }
+   ret = opus_decoder_init(st, Fs, channels);
+   if (error)
+      *error = ret;
+   if (ret != OPUS_OK)
+   {
+      opus_free(st);
+      st = NULL;
+   }
+   return st;
 }
 
-static void smooth_fade(const opus_int16 *in1, const opus_int16 *in2, opus_int16 *out,
-        int overlap, int channels, const opus_val16 *window, int Fs)
+static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, opus_val16 *out,
+        int overlap, int channels, const opus_val16 *window, opus_int32 Fs)
 {
        int i, c;
        int inc = 48000/Fs;
@@ -142,16 +173,17 @@ static int opus_packet_get_mode(const unsigned char *data)
 }
 
 static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
-               int len, opus_int16 *pcm, int frame_size, int decode_fec)
+               int len, opus_val16 *pcm, int frame_size, int decode_fec)
 {
-       void *silk_dec;
-       CELTDecoder *celt_dec;
-       int i, silk_ret=0, celt_ret=0;
-       ec_dec dec;
+    void *silk_dec;
+    CELTDecoder *celt_dec;
+    int i, silk_ret=0, celt_ret=0;
+    ec_dec dec;
     silk_DecControlStruct DecControl;
     opus_int32 silk_frame_size;
-    opus_int16 pcm_celt[960*2];
-    opus_int16 pcm_transition[480*2];
+    VARDECL(opus_int16, pcm_silk);
+    VARDECL(opus_val16, pcm_transition);
+    VARDECL(opus_val16, redundant_audio);
 
     int audiosize;
     int mode;
@@ -160,10 +192,11 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
     int redundancy=0;
     int redundancy_bytes = 0;
     int celt_to_silk=0;
-    opus_int16 redundant_audio[240*2];
     int c;
     int F2_5, F5, F10, F20;
     const opus_val16 *window;
+    opus_uint32 redundant_rng = 0;
+    ALLOC_STACK;
 
     silk_dec = (char*)st+st->silk_dec_offset;
     celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
@@ -171,6 +204,8 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
     F10 = F20>>1;
     F5 = F10>>1;
     F2_5 = F5>>1;
+    if (frame_size < F2_5)
+       return OPUS_BUFFER_TOO_SMALL;
     /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
     if (len<=1)
     {
@@ -185,38 +220,46 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         ec_dec_init(&dec,(unsigned char*)data,len);
     } else {
        audiosize = frame_size;
+
        if (st->prev_mode == 0)
        {
                /* If we haven't got any packet yet, all we can do is return zeros */
-               for (i=0;i<audiosize;i++)
+               for (i=0;i<audiosize*st->channels;i++)
                        pcm[i] = 0;
+               RESTORE_STACK;
                return audiosize;
        } else {
                mode = st->prev_mode;
        }
     }
 
+    ALLOC(pcm_transition, F5*st->channels, opus_val16);
+
     if (data!=NULL && !st->prev_redundancy && mode != st->prev_mode && st->prev_mode > 0
                && !(mode == MODE_SILK_ONLY && st->prev_mode == MODE_HYBRID)
                && !(mode == MODE_HYBRID && st->prev_mode == MODE_SILK_ONLY))
     {
        transition = 1;
        if (mode == MODE_CELT_ONLY)
-           opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F10, audiosize), 0);
+           opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
     }
     if (audiosize > frame_size)
     {
-        fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);
+        /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
+        RESTORE_STACK;
         return OPUS_BAD_ARG;
     } else {
         frame_size = audiosize;
     }
 
+    ALLOC(pcm_silk, frame_size*st->channels, opus_int16);
+    ALLOC(redundant_audio, F5*st->channels, opus_val16);
+
     /* SILK processing */
     if (mode != MODE_CELT_ONLY)
     {
         int lost_flag, decoded_samples;
-        opus_int16 *pcm_ptr = pcm;
+        opus_int16 *pcm_ptr = pcm_silk;
 
         if (st->prev_mode==MODE_CELT_ONLY)
                silk_InitDecoder( silk_dec );
@@ -234,7 +277,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
                 DecControl.internalSampleRate = 16000;
             } else {
                DecControl.internalSampleRate = 16000;
-                SKP_assert( 0 );
+                silk_assert( 0 );
             }
         } else {
             /* Hybrid mode */
@@ -254,19 +297,18 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
                        silk_frame_size = frame_size;
                        for (i=0;i<frame_size*st->channels;i++)
                                pcm_ptr[i] = 0;
-               } else
-                    return OPUS_CORRUPTED_DATA;
+               } else {
+                  RESTORE_STACK;
+                  return OPUS_INVALID_PACKET;
+               }
             }
             pcm_ptr += silk_frame_size * st->channels;
             decoded_samples += silk_frame_size;
         } while( decoded_samples < frame_size );
-    } else {
-        for (i=0;i<frame_size*st->channels;i++)
-            pcm[i] = 0;
     }
 
     start_band = 0;
-    if (mode != MODE_CELT_ONLY && data != NULL)
+    if (mode != MODE_CELT_ONLY && data != NULL && ec_tell(&dec)+29+8*(st->mode == MODE_HYBRID) < 8*len)
     {
         /* Check if we have a redundant 0-8 kHz band */
         redundancy = ec_dec_bit_logp(&dec, 12);
@@ -286,7 +328,11 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
             }
             len -= redundancy_bytes;
             if (len<0)
-                return OPUS_CORRUPTED_DATA;
+            {
+               len=0;
+               redundancy_bytes=0;
+               redundancy = 0;
+            }
             /* Shrink decoder because of raw bits */
             dec.storage -= redundancy_bytes;
         }
@@ -321,29 +367,42 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         transition = 0;
 
     if (transition && mode != MODE_CELT_ONLY)
-        opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F10, audiosize), 0);
+        opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
 
     /* 5 ms redundant frame for CELT->SILK*/
     if (redundancy && celt_to_silk)
     {
         celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
-        celt_decode(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
-        celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
+        celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
+        celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+        celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
     }
 
     /* MUST be after PLC */
     celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
 
     if (transition)
-       celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
+       celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
 
     if (mode != MODE_SILK_ONLY)
     {
        int celt_frame_size = IMIN(F20, frame_size);
         /* Decode CELT */
-        celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm_celt, celt_frame_size, &dec);
-        for (i=0;i<celt_frame_size*st->channels;i++)
-            pcm[i] = SAT16(pcm[i] + (int)pcm_celt[i]);
+        celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm, celt_frame_size, &dec);
+    } else {
+       for (i=0;i<frame_size*st->channels;i++)
+          pcm[i] = 0;
+    }
+
+    if (mode != MODE_CELT_ONLY)
+    {
+#ifdef FIXED_POINT
+        for (i=0;i<frame_size*st->channels;i++)
+            pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
+#else
+        for (i=0;i<frame_size*st->channels;i++)
+            pcm[i] = pcm[i] + (1./32768.)*pcm_silk[i];
+#endif
     }
 
     {
@@ -355,10 +414,11 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
     /* 5 ms redundant frame for SILK->CELT */
     if (redundancy && !celt_to_silk)
     {
-        celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
+        celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
         celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
 
-        celt_decode(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
+        celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
+        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);
     }
@@ -382,10 +442,14 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
                    st->channels, window, st->Fs);
     }
 
-    st->rangeFinal = dec.rng;
+    if (len <= 1)
+       st->rangeFinal = 0;
+    else
+       st->rangeFinal = dec.rng ^ redundant_rng;
 
     st->prev_mode = mode;
     st->prev_redundancy = redundancy;
+    RESTORE_STACK;
        return celt_ret<0 ? celt_ret : audiosize;
 
 }
@@ -410,35 +474,43 @@ static int parse_size(const unsigned char *data, int len, short *size)
        }
 }
 
-int opus_packet_parse(const unsigned char *data, int len,
-      unsigned char *out_toc, const unsigned char *frames[48],
-      short size[48], const unsigned char **payload)
+static int opus_packet_parse_impl(const unsigned char *data, int 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;
+   int 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;
-      size[0] = len;
       break;
       /* Two CBR frames */
    case 1:
       count=2;
-      if (len&0x1)
-         return OPUS_CORRUPTED_DATA;
-      size[0] = size[1] = len/2;
+      cbr = 1;
+      if (!self_delimited)
+      {
+         if (len&0x1)
+            return OPUS_INVALID_PACKET;
+         size[0] = last_size = len/2;
+      }
       break;
       /* Two VBR frames */
    case 2:
@@ -446,19 +518,19 @@ int opus_packet_parse(const unsigned char *data, int len,
       bytes = parse_size(data, len, size);
       len -= bytes;
       if (size[0]<0 || size[0] > len)
-         return OPUS_CORRUPTED_DATA;
+         return OPUS_INVALID_PACKET;
       data += bytes;
-      size[1] = len-size[0];
+      last_size = len-size[0];
       break;
       /* Multiple CBR/VBR frames (from 0 to 120 ms) */
    case 3:
       if (len<1)
-         return OPUS_CORRUPTED_DATA;
+         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_CORRUPTED_DATA;
+          return OPUS_INVALID_PACKET;
       len--;
       /* Padding flag is bit 6 */
       if (ch&0x40)
@@ -467,7 +539,7 @@ int opus_packet_parse(const unsigned char *data, int len,
          int p;
          do {
             if (len<=0)
-               return OPUS_CORRUPTED_DATA;
+               return OPUS_INVALID_PACKET;
             p = *data++;
             len--;
             padding += p==255 ? 254: p;
@@ -475,40 +547,62 @@ int opus_packet_parse(const unsigned char *data, int len,
          len -= padding;
       }
       if (len<0)
-         return OPUS_CORRUPTED_DATA;
+         return OPUS_INVALID_PACKET;
       /* VBR flag is bit 7 */
-      if (ch&0x80)
+      cbr = !(ch&0x80);
+      if (!cbr)
       {
          /* VBR case */
-         int last_size=len;
+         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_CORRUPTED_DATA;
+               return OPUS_INVALID_PACKET;
             data += bytes;
             last_size -= bytes+size[i];
          }
          if (last_size<0)
-            return OPUS_CORRUPTED_DATA;
-         size[count-1]=last_size;
-      } else {
+            return OPUS_INVALID_PACKET;
+      } else if (!self_delimited)
+      {
          /* CBR case */
-         int sz = len/count;
-         if (sz*count!=len)
-            return OPUS_CORRUPTED_DATA;
-         for (i=0;i<count;i++)
-            size[i] = sz;
+         last_size = len/count;
+         if (last_size*count!=len)
+            return OPUS_INVALID_PACKET;
+         for (i=0;i<count-1;i++)
+            size[i] = last_size;
       }
       break;
    }
-   /* 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 (size[count-1] > 1275)
-      return OPUS_CORRUPTED_DATA;
+   /* 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] = last_size;
+   }
 
    if (frames)
    {
@@ -522,34 +616,48 @@ int opus_packet_parse(const unsigned char *data, int len,
    if (out_toc)
       *out_toc = toc;
 
-   if (payload)
-      *payload = data;
+   if (payload_offset)
+      *payload_offset = data-data0;
 
    return count;
 }
 
+int opus_packet_parse(const unsigned char *data, int 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(OpusDecoder *st, const unsigned char *data,
-               int len, opus_int16 *pcm, int frame_size, int decode_fec)
+int opus_decode_native(OpusDecoder *st, const unsigned char *data,
+      int len, opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset)
 {
        int i, nb_samples;
-       int count;
+       int count, offset;
        unsigned char toc;
+       int tot_offset;
        /* 48 x 2.5 ms = 120 ms */
        short size[48];
+       if (decode_fec<0 || decode_fec>1)return OPUS_BAD_ARG;
        if (len==0 || data==NULL)
            return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0);
        else if (len<0)
                return OPUS_BAD_ARG;
+
+       tot_offset = 0;
        st->mode = opus_packet_get_mode(data);
        st->bandwidth = opus_packet_get_bandwidth(data);
        st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
        st->stream_channels = opus_packet_get_nb_channels(data);
 
-       count = opus_packet_parse(data, len, &toc, NULL, size, &data);
+       count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
        if (count < 0)
           return count;
 
+       data += offset;
+       tot_offset += offset;
+
        if (count*st->frame_size > frame_size)
                return OPUS_BAD_ARG;
        nb_samples=0;
@@ -560,58 +668,144 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
                if (ret<0)
                        return ret;
                data += size[i];
+               tot_offset += size[i];
                pcm += ret*st->channels;
                nb_samples += ret;
        }
+       if (packet_offset != NULL)
+          *packet_offset = tot_offset;
        return nb_samples;
 }
 
+#ifdef FIXED_POINT
 
-int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+      int len, opus_val16 *pcm, int frame_size, int decode_fec)
 {
-    va_list ap;
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL);
+}
 
-    va_start(ap, request);
+#ifndef DISABLE_FLOAT_API
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+      int len, float *pcm, int frame_size, int decode_fec)
+{
+   VARDECL(opus_int16, out);
+   int ret, i;
+   ALLOC_STACK;
 
-    switch (request)
-    {
-        case OPUS_GET_MODE_REQUEST:
-        {
-            int *value = va_arg(ap, int*);
-            *value = st->prev_mode;
-        }
-        break;
-        case OPUS_SET_BANDWIDTH_REQUEST:
-        {
-            int value = va_arg(ap, int);
-            st->bandwidth = value;
-        }
-        break;
-        case OPUS_GET_BANDWIDTH_REQUEST:
-        {
-            int *value = va_arg(ap, int*);
-            *value = st->bandwidth;
-        }
-        break;
-        default:
-            fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);
-            break;
-    }
+   ALLOC(out, frame_size*st->channels, opus_int16);
 
-    va_end(ap);
-    return OPUS_OK;
+   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL);
+   if (ret > 0)
+   {
+      for (i=0;i<ret*st->channels;i++)
+         pcm[i] = (1./32768.)*(out[i]);
+   }
+   RESTORE_STACK;
+   return ret;
 }
+#endif
 
-void opus_decoder_destroy(OpusDecoder *st)
+
+#else
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+      int len, opus_int16 *pcm, int frame_size, int decode_fec)
 {
-       free(st);
+   VARDECL(float, out);
+   int ret, i;
+   ALLOC_STACK;
+
+   ALLOC(out, frame_size*st->channels, float);
+
+   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL);
+   if (ret > 0)
+   {
+      for (i=0;i<ret*st->channels;i++)
+         pcm[i] = FLOAT2INT16(out[i]);
+   }
+   RESTORE_STACK;
+   return ret;
 }
 
-int opus_decoder_get_final_range(OpusDecoder *st)
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+        int len, opus_val16 *pcm, int frame_size, int decode_fec)
 {
-    return st->rangeFinal;
+   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL);
 }
 
+#endif
+
+int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+{
+   int ret = OPUS_OK;
+   va_list ap;
+   void *silk_dec;
+   CELTDecoder *celt_dec;
+
+   silk_dec = (char*)st+st->silk_dec_offset;
+   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+
+
+   va_start(ap, request);
+
+   switch (request)
+   {
+   case OPUS_GET_BANDWIDTH_REQUEST:
+   {
+      opus_int32 *value = va_arg(ap, opus_int32*);
+      *value = st->bandwidth;
+   }
+   break;
+   case OPUS_GET_FINAL_RANGE_REQUEST:
+   {
+      opus_uint32 *value = va_arg(ap, opus_uint32*);
+      *value = st->rangeFinal;
+   }
+   break;
+   case OPUS_RESET_STATE:
+   {
+      OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
+            sizeof(OpusDecoder)-
+            ((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
+
+      celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+      silk_InitDecoder( silk_dec );
+      st->stream_channels = st->channels;
+      st->frame_size = st->Fs/400;
+   }
+   break;
+   case OPUS_GET_PITCH_REQUEST:
+   {
+      int *value = va_arg(ap, opus_int32*);
+      if (value==NULL)
+      {
+         ret = OPUS_BAD_ARG;
+         break;
+      }
+      if (st->prev_mode == MODE_CELT_ONLY)
+         celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
+      else
+         *value = ((silk_decoder_state*)silk_dec)->indices.signalType == TYPE_VOICED
+         ? ((silk_decoder_state*)silk_dec)->lagPrev*48/((silk_decoder_state*)silk_dec)->fs_kHz
+         : 0;
+   }
+   break;
+   default:
+      /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
+      ret = OPUS_UNIMPLEMENTED;
+      break;
+   }
+
+   va_end(ap);
+   return ret;
+}
+
+void opus_decoder_destroy(OpusDecoder *st)
+{
+       opus_free(st);
+}
+
+
 int opus_packet_get_bandwidth(const unsigned char *data)
 {
        int bandwidth;
@@ -630,9 +824,9 @@ int opus_packet_get_bandwidth(const unsigned char *data)
     return bandwidth;
 }
 
-int opus_packet_get_samples_per_frame(const unsigned char *data, int Fs)
+int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs)
 {
-       int audiosize;
+    int audiosize;
     if (data[0]&0x80)
     {
         audiosize = ((data[0]>>3)&0x3);
@@ -667,7 +861,7 @@ int opus_packet_get_nb_frames(const unsigned char packet[], int len)
        else if (count!=3)
                return 2;
        else if (len<2)
-               return OPUS_CORRUPTED_DATA;
+               return OPUS_INVALID_PACKET;
        else
                return packet[1]&0x3F;
 }
@@ -679,8 +873,7 @@ int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char pack
        samples = count*opus_packet_get_samples_per_frame(packet, dec->Fs);
        /* Can't have more than 120 ms */
        if (samples*25 > dec->Fs*3)
-               return OPUS_CORRUPTED_DATA;
+               return OPUS_INVALID_PACKET;
        else
                return samples;
 }
-