SILK update
[opus.git] / src / opus_decoder.c
index 2fef286..00fd2ab 100644 (file)
@@ -47,6 +47,7 @@ struct OpusDecoder {
    int          silk_dec_offset;
    int          channels;
    opus_int32   Fs;          /** Sampling rate (at the API level) */
+   silk_DecControlStruct DecControl;
 
    /* Everything beyond this point gets cleared on a reset */
 #define OPUS_DECODER_RESET_START stream_channels
@@ -104,6 +105,8 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
    st->stream_channels = st->channels = channels;
 
    st->Fs = Fs;
+   st->DecControl.API_sampleRate = st->Fs;
+   st->DecControl.nChannelsAPI      = st->channels;
 
    /* Reset decoder */
    ret = silk_InitDecoder( silk_dec );
@@ -123,13 +126,14 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
 OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
 {
    int ret;
+   OpusDecoder *st;
    if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2))
    {
       if (error)
          *error = OPUS_BAD_ARG;
       return NULL;
    }
-   OpusDecoder *st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
+   st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
    if (st == NULL)
    {
       if (error)
@@ -186,7 +190,6 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
     CELTDecoder *celt_dec;
     int i, silk_ret=0, celt_ret=0;
     ec_dec dec;
-    silk_DecControlStruct DecControl;
     opus_int32 silk_frame_size;
     VARDECL(opus_int16, pcm_silk);
     VARDECL(opus_val16, pcm_transition);
@@ -259,7 +262,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         frame_size = audiosize;
     }
 
-    ALLOC(pcm_silk, frame_size*st->channels, opus_int16);
+    ALLOC(pcm_silk, IMAX(F10, frame_size)*st->channels, opus_int16);
     ALLOC(redundant_audio, F5*st->channels, opus_val16);
 
     /* SILK processing */
@@ -271,24 +274,27 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         if (st->prev_mode==MODE_CELT_ONLY)
                silk_InitDecoder( silk_dec );
 
-        DecControl.API_sampleRate = st->Fs;
-        DecControl.nChannelsAPI      = st->channels;
-        DecControl.nChannelsInternal = st->stream_channels;
-        DecControl.payloadSize_ms = 1000 * audiosize / st->Fs;
-        if( mode == MODE_SILK_ONLY ) {
-            if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
-                DecControl.internalSampleRate = 8000;
-            } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
-                DecControl.internalSampleRate = 12000;
-            } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
-                DecControl.internalSampleRate = 16000;
+        /* The SILK PLC cannot support produce frames of less than 10 ms */
+        st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs);
+
+        if (data != NULL)
+        {
+            st->DecControl.nChannelsInternal = st->stream_channels;
+            if( mode == MODE_SILK_ONLY ) {
+                if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
+                    st->DecControl.internalSampleRate = 8000;
+                } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
+                    st->DecControl.internalSampleRate = 12000;
+                } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
+                    st->DecControl.internalSampleRate = 16000;
+                } else {
+                    st->DecControl.internalSampleRate = 16000;
+                    silk_assert( 0 );
+                }
             } else {
-               DecControl.internalSampleRate = 16000;
-                silk_assert( 0 );
+                /* Hybrid mode */
+                st->DecControl.internalSampleRate = 16000;
             }
-        } else {
-            /* Hybrid mode */
-            DecControl.internalSampleRate = 16000;
         }
 
         lost_flag = data == NULL ? 1 : 2 * decode_fec;
@@ -296,7 +302,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         do {
             /* Call SILK decoder */
             int first_frame = decoded_samples == 0;
-            silk_ret = silk_Decode( silk_dec, &DecControl,
+            silk_ret = silk_Decode( silk_dec, &st->DecControl,
                 lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size );
             if( silk_ret ) {
                if (lost_flag) {
@@ -322,8 +328,8 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
         if (redundancy)
         {
             celt_to_silk = ec_dec_bit_logp(&dec, 1);
-            /*Due to the ec_tell check above redundancy_bytes will be at least two for hybrid*/
-            redundancy_bytes = mode==MODE_HYBRID ? ec_dec_uint(&dec, 256)+2 : len-((ec_tell(&dec)+7)>>3);
+            /* redundancy_bytes will be at least two, in the non-hybrid case due to the ec_tell() check above */
+            redundancy_bytes = mode==MODE_HYBRID ? (opus_int32)ec_dec_uint(&dec, 256)+2 : len-((ec_tell(&dec)+7)>>3);
             len -= redundancy_bytes;
             if (len<0)
             {
@@ -385,11 +391,21 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
     if (mode != MODE_SILK_ONLY)
     {
        int celt_frame_size = IMIN(F20, frame_size);
+       /* Make sure to discard any previous CELT state */
+       if (st->prev_mode == MODE_SILK_ONLY)
+          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);
     } else {
+       unsigned char silence[2] = {0xFF, 0xFF};
        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)
+       {
+          celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+          celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL);
+       }
     }
 
     if (mode != MODE_CELT_ONLY)