1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   Written by Jean-Marc Valin and Koen Vos */
3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org/*
4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   Redistribution and use in source and binary forms, with or without
5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   modification, are permitted provided that the following conditions
6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   are met:
7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   - Redistributions of source code must retain the above copyright
9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   notice, this list of conditions and the following disclaimer.
10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
11885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   - Redistributions in binary form must reproduce the above copyright
12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   notice, this list of conditions and the following disclaimer in the
13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   documentation and/or other materials provided with the distribution.
14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
15885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org*/
27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef HAVE_CONFIG_H
293c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# include "config.h"
30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifndef OPUS_BUILD
333c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# 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."
343c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#endif
353c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com
363c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__)
373c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
40885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include <stdarg.h>
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "celt.h"
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "opus.h"
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "entdec.h"
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "modes.h"
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "API.h"
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "stack_alloc.h"
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "float_cast.h"
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "opus_private.h"
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "os_support.h"
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "structs.h"
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "define.h"
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "mathops.h"
53e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "cpu_support.h"
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstruct OpusDecoder {
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          celt_dec_offset;
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          silk_dec_offset;
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          channels;
59885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   opus_int32   Fs;          /** Sampling rate (at the API level) */
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   silk_DecControlStruct DecControl;
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          decode_gain;
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* Everything beyond this point gets cleared on a reset */
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#define OPUS_DECODER_RESET_START stream_channels
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          stream_channels;
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          bandwidth;
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          mode;
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          prev_mode;
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          frame_size;
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int          prev_redundancy;
726b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   int          last_packet_duration;
73e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifndef FIXED_POINT
74e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_val16   softclip_mem[2];
75e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   opus_uint32  rangeFinal;
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef FIXED_POINT
813c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.comstatic OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decoder_get_size(int channels)
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int silkDecSizeBytes, celtDecSizeBytes;
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int ret;
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (channels<1 || channels > 2)
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return 0;
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if(ret)
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return 0;
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   silkDecSizeBytes = align(silkDecSizeBytes);
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   celtDecSizeBytes = celt_decoder_get_size(channels);
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   void *silk_dec;
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   CELTDecoder *celt_dec;
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int ret, silkDecSizeBytes;
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    || (channels!=1&&channels!=2))
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BAD_ARG;
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* Initialize SILK encoder */
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (ret)
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_INTERNAL_ERROR;
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   silkDecSizeBytes = align(silkDecSizeBytes);
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->silk_dec_offset = align(sizeof(OpusDecoder));
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   silk_dec = (char*)st+st->silk_dec_offset;
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->stream_channels = st->channels = channels;
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->Fs = Fs;
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->DecControl.API_sampleRate = st->Fs;
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->DecControl.nChannelsAPI      = st->channels;
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* Reset decoder */
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ret = silk_InitDecoder( silk_dec );
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if(ret)return OPUS_INTERNAL_ERROR;
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* Initialize CELT decoder */
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ret = celt_decoder_init(celt_dec, Fs, channels);
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR;
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->prev_mode = 0;
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->frame_size = Fs/400;
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return OPUS_OK;
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgOpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int ret;
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   OpusDecoder *st;
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
148885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    || (channels!=1&&channels!=2))
149885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (error)
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         *error = OPUS_BAD_ARG;
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return NULL;
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (st == NULL)
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (error)
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         *error = OPUS_ALLOC_FAIL;
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return NULL;
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
161885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ret = opus_decoder_init(st, Fs, channels);
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (error)
163885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      *error = ret;
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (ret != OPUS_OK)
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_free(st);
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      st = NULL;
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return st;
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic void smooth_fade(const opus_val16 *in1, const opus_val16 *in2,
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_val16 *out, int overlap, int channels,
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      const opus_val16 *window, opus_int32 Fs)
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int i, c;
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int inc = 48000/Fs;
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   for (c=0;c<channels;c++)
179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<overlap;i++)
181885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
182885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]);
183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]),
184885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                   Q15ONE-w, in1[i*channels+c]), 15);
185885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
186885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
187885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
188885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
189885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic int opus_packet_get_mode(const unsigned char *data)
190885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
191885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int mode;
192885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (data[0]&0x80)
193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      mode = MODE_CELT_ONLY;
195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else if ((data[0]&0x60) == 0x60)
196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      mode = MODE_HYBRID;
198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else {
199885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      mode = MODE_SILK_ONLY;
200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return mode;
202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstatic int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
205885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   void *silk_dec;
208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   CELTDecoder *celt_dec;
209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int i, silk_ret=0, celt_ret=0;
210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ec_dec dec;
211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   opus_int32 silk_frame_size;
212e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int pcm_silk_size;
213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   VARDECL(opus_int16, pcm_silk);
214e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int pcm_transition_silk_size;
215e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   VARDECL(opus_val16, pcm_transition_silk);
216e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int pcm_transition_celt_size;
217e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   VARDECL(opus_val16, pcm_transition_celt);
218e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_val16 *pcm_transition;
219e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   int redundant_audio_size;
220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   VARDECL(opus_val16, redundant_audio);
221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int audiosize;
223885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int mode;
224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int transition=0;
225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int start_band;
226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int redundancy=0;
227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int redundancy_bytes = 0;
228885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int celt_to_silk=0;
229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int c;
230885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int F2_5, F5, F10, F20;
231885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   const opus_val16 *window;
232885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   opus_uint32 redundant_rng = 0;
233885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ALLOC_STACK;
234885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
235885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   silk_dec = (char*)st+st->silk_dec_offset;
236885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
237885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   F20 = st->Fs/50;
238885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   F10 = F20>>1;
239885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   F5 = F10>>1;
240885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   F2_5 = F5>>1;
241885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (frame_size < F2_5)
242885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
243885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      RESTORE_STACK;
244885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BUFFER_TOO_SMALL;
245885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
246660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org   /* Limit frame_size to avoid excessive stack allocations. */
247660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org   frame_size = IMIN(frame_size, st->Fs/25*3);
248885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
249885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (len<=1)
250885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
251885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      data = NULL;
252885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /* In that case, don't conceal more than what the ToC says */
253885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      frame_size = IMIN(frame_size, st->frame_size);
254885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
255885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (data != NULL)
256885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
257885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      audiosize = st->frame_size;
258885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      mode = st->mode;
259885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      ec_dec_init(&dec,(unsigned char*)data,len);
260885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else {
261885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      audiosize = frame_size;
2623c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      mode = st->prev_mode;
263885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
2643c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      if (mode == 0)
265885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
266885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         /* If we haven't got any packet yet, all we can do is return zeros */
267885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         for (i=0;i<audiosize*st->channels;i++)
268885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            pcm[i] = 0;
269885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         RESTORE_STACK;
270885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         return audiosize;
271885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
272885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
2733c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
2743c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         10, or 20 (e.g. 12.5 or 30 ms). */
2753c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      if (audiosize > F20)
2763c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      {
2773c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         do {
2783c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0);
2793c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            if (ret<0)
2803c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            {
2813c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com               RESTORE_STACK;
2823c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com               return ret;
2833c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            }
2843c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            pcm += ret*st->channels;
2853c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            audiosize -= ret;
2863c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         } while (audiosize > 0);
2873c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         RESTORE_STACK;
2883c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         return frame_size;
2893c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      } else if (audiosize < F20)
2903c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      {
2913c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         if (audiosize > F10)
2923c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            audiosize = F10;
2933c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com         else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
2943c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com            audiosize = F5;
2953c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      }
2963c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   }
297885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
2983c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   pcm_transition_silk_size = ALLOC_NONE;
2993c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   pcm_transition_celt_size = ALLOC_NONE;
300885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (data!=NULL && st->prev_mode > 0 && (
301885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy)
302885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) )
303885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      )
304885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
305885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      transition = 1;
306e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      /* Decide where to allocate the stack memory for pcm_transition */
307885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (mode == MODE_CELT_ONLY)
308e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         pcm_transition_celt_size = F5*st->channels;
309e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      else
310e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         pcm_transition_silk_size = F5*st->channels;
311e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
312e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16);
313e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (transition && mode == MODE_CELT_ONLY)
314e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
315e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      pcm_transition = pcm_transition_celt;
316e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
317885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
318885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (audiosize > frame_size)
319885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
320885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
321885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      RESTORE_STACK;
322885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BAD_ARG;
323885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else {
324885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      frame_size = audiosize;
325885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
326885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
327e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   /* Don't allocate any memory when in CELT-only mode */
3283c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
329e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ALLOC(pcm_silk, pcm_silk_size, opus_int16);
330885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
331885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* SILK processing */
332885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (mode != MODE_CELT_ONLY)
333885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
334885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      int lost_flag, decoded_samples;
335885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int16 *pcm_ptr = pcm_silk;
336885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
337885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (st->prev_mode==MODE_CELT_ONLY)
338885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         silk_InitDecoder( silk_dec );
339885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
340885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /* The SILK PLC cannot produce frames of less than 10 ms */
341885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs);
342885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
343885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (data != NULL)
344885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
345885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        st->DecControl.nChannelsInternal = st->stream_channels;
346885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( mode == MODE_SILK_ONLY ) {
347885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
348885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              st->DecControl.internalSampleRate = 8000;
349885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
350885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              st->DecControl.internalSampleRate = 12000;
351885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
352885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              st->DecControl.internalSampleRate = 16000;
353885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           } else {
354885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              st->DecControl.internalSampleRate = 16000;
355885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              silk_assert( 0 );
356885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           }
357885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        } else {
358885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           /* Hybrid mode */
359885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           st->DecControl.internalSampleRate = 16000;
360885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
361885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     }
362885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
363885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     lost_flag = data == NULL ? 1 : 2 * decode_fec;
364885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     decoded_samples = 0;
365885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     do {
366885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        /* Call SILK decoder */
367885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        int first_frame = decoded_samples == 0;
368885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        silk_ret = silk_Decode( silk_dec, &st->DecControl,
369885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size );
370885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        if( silk_ret ) {
371885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           if (lost_flag) {
372885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              /* PLC failure should not be fatal */
373885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              silk_frame_size = frame_size;
374885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org              for (i=0;i<frame_size*st->channels;i++)
375885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                 pcm_ptr[i] = 0;
376885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           } else {
377885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org             RESTORE_STACK;
3783c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com             return OPUS_INTERNAL_ERROR;
379885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org           }
380885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        }
381885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pcm_ptr += silk_frame_size * st->channels;
382885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        decoded_samples += silk_frame_size;
383885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      } while( decoded_samples < frame_size );
384885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
385885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
386885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   start_band = 0;
387885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
388885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len)
389885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
390885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /* Check if we have a redundant 0-8 kHz band */
391885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (mode == MODE_HYBRID)
392885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         redundancy = ec_dec_bit_logp(&dec, 12);
393885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      else
394885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         redundancy = 1;
395885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (redundancy)
396885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
397885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         celt_to_silk = ec_dec_bit_logp(&dec, 1);
398885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         /* redundancy_bytes will be at least two, in the non-hybrid
399885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            case due to the ec_tell() check above */
400885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         redundancy_bytes = mode==MODE_HYBRID ?
401885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org               (opus_int32)ec_dec_uint(&dec, 256)+2 :
402885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org               len-((ec_tell(&dec)+7)>>3);
403885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         len -= redundancy_bytes;
404885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         /* This is a sanity check. It should never happen for a valid
405885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            packet, so the exact behaviour is not normative. */
406885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         if (len*8 < ec_tell(&dec))
407885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         {
408885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            len = 0;
409885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            redundancy_bytes = 0;
410885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            redundancy = 0;
411885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         }
412885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         /* Shrink decoder because of raw bits */
413885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         dec.storage -= redundancy_bytes;
414885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
415885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
416885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (mode != MODE_CELT_ONLY)
417885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      start_band = 17;
418885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
419885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
420885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      int endband=21;
421885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
422885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      switch(st->bandwidth)
423885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
424885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      case OPUS_BANDWIDTH_NARROWBAND:
425885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         endband = 13;
426885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         break;
427885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      case OPUS_BANDWIDTH_MEDIUMBAND:
428885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      case OPUS_BANDWIDTH_WIDEBAND:
429885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         endband = 17;
430885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         break;
431885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      case OPUS_BANDWIDTH_SUPERWIDEBAND:
432885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         endband = 19;
433885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         break;
434885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      case OPUS_BANDWIDTH_FULLBAND:
435885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         endband = 21;
436885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         break;
437885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
438885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband));
439885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels));
440885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
441885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
442885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (redundancy)
443e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
444885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      transition = 0;
4453c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      pcm_transition_silk_size=ALLOC_NONE;
446e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
447e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
448e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);
449885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
450885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (transition && mode != MODE_CELT_ONLY)
451e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
452e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      pcm_transition = pcm_transition_silk;
453885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
454e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
455e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
456e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   /* Only allocation memory for redundancy if/when needed */
4573c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
458e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ALLOC(redundant_audio, redundant_audio_size, opus_val16);
459885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
460885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* 5 ms redundant frame for CELT->SILK*/
461885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (redundancy && celt_to_silk)
462885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
463885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
464885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
465885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                          redundant_audio, F5, NULL);
466885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
467885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
468885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
469885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* MUST be after PLC */
470885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
471885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
472885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (mode != MODE_SILK_ONLY)
473885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
474885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      int celt_frame_size = IMIN(F20, frame_size);
475885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /* Make sure to discard any previous CELT state */
476885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy)
477885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
478885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /* Decode CELT */
479885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
480885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                     len, pcm, celt_frame_size, &dec);
481885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else {
482885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      unsigned char silence[2] = {0xFF, 0xFF};
483885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<frame_size*st->channels;i++)
484885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         pcm[i] = 0;
485885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /* For hybrid -> SILK transitions, we let the CELT MDCT
486885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         do a fade-out by decoding a silence frame */
487885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
488885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
489885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
490885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL);
491885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
492885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
493885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
494885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (mode != MODE_CELT_ONLY)
495885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
496885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef FIXED_POINT
497885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<frame_size*st->channels;i++)
498885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
499885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#else
500885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<frame_size*st->channels;i++)
501885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
502885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
503885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
504885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
505885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
506885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      const CELTMode *celt_mode;
507885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
508885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      window = celt_mode->window;
509885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
510885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
511885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* 5 ms redundant frame for SILK->CELT */
512885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (redundancy && !celt_to_silk)
513885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
514885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
515885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
516885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
517885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
518885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
519885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
520885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                  pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
521885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
522885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (redundancy && celt_to_silk)
523885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
524885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (c=0;c<st->channels;c++)
525885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
526885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         for (i=0;i<F2_5;i++)
527885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            pcm[st->channels*i+c] = redundant_audio[st->channels*i+c];
528885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
529885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5,
530885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                  pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs);
531885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
532885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (transition)
533885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
534885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (audiosize >= F5)
535885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
536885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         for (i=0;i<st->channels*F2_5;i++)
537885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            pcm[i] = pcm_transition[i];
538885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5,
539885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                     pcm+st->channels*F2_5, F2_5,
540885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                     st->channels, window, st->Fs);
541885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      } else {
542885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         /* Not enough time to do a clean transition, but we do it anyway
543885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            This will not preserve amplitude perfectly and may introduce
544885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            a bit of temporal aliasing, but it shouldn't be too bad and
545885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            that's pretty much the best we can do. In any case, generating this
546885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            transition it pretty silly in the first place */
547885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         smooth_fade(pcm_transition, pcm,
548885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                     pcm, F2_5,
549885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                     st->channels, window, st->Fs);
550885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
551885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
552885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
553885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if(st->decode_gain)
554885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
555885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_val32 gain;
556885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain));
557885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<frame_size*st->channels;i++)
558885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
559885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         opus_val32 x;
560885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         x = MULT16_32_P16(pcm[i],gain);
561885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         pcm[i] = SATURATE(x, 32767);
562885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
563885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
564885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
565885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (len <= 1)
566885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      st->rangeFinal = 0;
567885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   else
568885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      st->rangeFinal = dec.rng ^ redundant_rng;
569885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
570885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->prev_mode = mode;
571885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   st->prev_redundancy = redundancy && !celt_to_silk;
572e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
573e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (celt_ret>=0)
574e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   {
575e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
576e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         OPUS_PRINT_INT(audiosize);
577e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   }
578e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
579885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   RESTORE_STACK;
580885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return celt_ret < 0 ? celt_ret : audiosize;
581885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
582885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
583885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
584885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decode_native(OpusDecoder *st, const unsigned char *data,
585885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
5863c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      int self_delimited, opus_int32 *packet_offset, int soft_clip)
587885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
588885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int i, nb_samples;
589885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int count, offset;
590885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   unsigned char toc;
5916b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
592885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* 48 x 2.5 ms = 120 ms */
593e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   opus_int16 size[48];
594885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (decode_fec<0 || decode_fec>1)
595885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BAD_ARG;
5966b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
5976b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
5986b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      return OPUS_BAD_ARG;
599885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (len==0 || data==NULL)
6006b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   {
6016b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      int pcm_count=0;
6026b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      do {
6036b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org         int ret;
604e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
6056b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org         if (ret<0)
6066b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org            return ret;
6076b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org         pcm_count += ret;
6086b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      } while (pcm_count < frame_size);
609e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      celt_assert(pcm_count == frame_size);
610e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
611e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         OPUS_PRINT_INT(pcm_count);
6126b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      st->last_packet_duration = pcm_count;
6136b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      return pcm_count;
6146b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   } else if (len<0)
615885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BAD_ARG;
616885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
6176b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   packet_mode = opus_packet_get_mode(data);
6186b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   packet_bandwidth = opus_packet_get_bandwidth(data);
6196b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
6206b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   packet_stream_channels = opus_packet_get_nb_channels(data);
621885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
6223c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
6233c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com                                  size, &offset, packet_offset);
6243c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   if (count<0)
6253c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      return count;
6266b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org
6276b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   data += offset;
6286b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org
6296b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   if (decode_fec)
6306b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   {
6316b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      int duration_copy;
6326b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      int ret;
6336b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      /* If no FEC can be present, run the PLC (recursive call) */
634e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
635e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
6366b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      /* Otherwise, run the PLC on everything except the size for which we might have FEC */
6376b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      duration_copy = st->last_packet_duration;
638e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (frame_size-packet_frame_size!=0)
6396b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      {
640e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
641e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         if (ret<0)
642e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         {
643e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            st->last_packet_duration = duration_copy;
644e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            return ret;
645e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         }
646e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         celt_assert(ret==frame_size-packet_frame_size);
6476b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      }
6486b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      /* Complete with FEC */
6496b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      st->mode = packet_mode;
6506b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      st->bandwidth = packet_bandwidth;
6516b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      st->frame_size = packet_frame_size;
6526b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      st->stream_channels = packet_stream_channels;
6536b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
6546b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org            packet_frame_size, 1);
6556b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      if (ret<0)
6566b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org         return ret;
657e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      else {
658e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
659e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org            OPUS_PRINT_INT(frame_size);
660e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         st->last_packet_duration = frame_size;
661e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         return frame_size;
662e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
6636b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   }
664885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
6656b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   if (count*packet_frame_size > frame_size)
666885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BUFFER_TOO_SMALL;
6676b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org
6686b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   /* Update the state as the last step to avoid updating it on an invalid packet */
6696b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   st->mode = packet_mode;
6706b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   st->bandwidth = packet_bandwidth;
6716b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   st->frame_size = packet_frame_size;
6726b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   st->stream_channels = packet_stream_channels;
6736b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org
674885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   nb_samples=0;
675885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   for (i=0;i<count;i++)
676885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
677885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      int ret;
678e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
679885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (ret<0)
680885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         return ret;
681e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      celt_assert(ret==packet_frame_size);
682885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      data += size[i];
683885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      nb_samples += ret;
684885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
6856b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   st->last_packet_duration = nb_samples;
686e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
687e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      OPUS_PRINT_INT(nb_samples);
688e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#ifndef FIXED_POINT
689e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   if (soft_clip)
690e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
691e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   else
692e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      st->softclip_mem[0]=st->softclip_mem[1]=0;
693e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#endif
694885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return nb_samples;
695885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
696885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
697885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifdef FIXED_POINT
698885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
699885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decode(OpusDecoder *st, const unsigned char *data,
700885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
701885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
7023c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   if(frame_size<=0)
7033c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      return OPUS_BAD_ARG;
704e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
705885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
706885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
707885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#ifndef DISABLE_FLOAT_API
708885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decode_float(OpusDecoder *st, const unsigned char *data,
709885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 len, float *pcm, int frame_size, int decode_fec)
710885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
711885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   VARDECL(opus_int16, out);
712885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int ret, i;
713885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ALLOC_STACK;
714885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
7153c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   if(frame_size<=0)
7163c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   {
7173c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      RESTORE_STACK;
7183c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      return OPUS_BAD_ARG;
7193c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   }
720885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ALLOC(out, frame_size*st->channels, opus_int16);
721885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
722e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
723885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (ret > 0)
724885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
725885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<ret*st->channels;i++)
726885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         pcm[i] = (1.f/32768.f)*(out[i]);
727885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
728885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   RESTORE_STACK;
729885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return ret;
730885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
731885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
732885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
733885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
734885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#else
735885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decode(OpusDecoder *st, const unsigned char *data,
736885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
737885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
738885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   VARDECL(float, out);
739885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int ret, i;
740885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ALLOC_STACK;
741885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
7423c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   if(frame_size<=0)
743885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
744885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      RESTORE_STACK;
745885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BAD_ARG;
746885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
747885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
748885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   ALLOC(out, frame_size*st->channels, float);
749885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
750e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
751885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (ret > 0)
752885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
753885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      for (i=0;i<ret*st->channels;i++)
754885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         pcm[i] = FLOAT2INT16(out[i]);
755885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
756885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   RESTORE_STACK;
757885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return ret;
758885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
759885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
760885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decode_float(OpusDecoder *st, const unsigned char *data,
761885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
762885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
7633c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com   if(frame_size<=0)
7643c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com      return OPUS_BAD_ARG;
765e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
766885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
767885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
768885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#endif
769885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
770885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_decoder_ctl(OpusDecoder *st, int request, ...)
771885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
772885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int ret = OPUS_OK;
773885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   va_list ap;
774885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   void *silk_dec;
775885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   CELTDecoder *celt_dec;
776885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
777885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   silk_dec = (char*)st+st->silk_dec_offset;
778885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
779885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
780885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
781885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   va_start(ap, request);
782885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
783885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   switch (request)
784885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
785885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   case OPUS_GET_BANDWIDTH_REQUEST:
786885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
787885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 *value = va_arg(ap, opus_int32*);
788e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!value)
789e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
790e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         goto bad_arg;
791e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
792885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      *value = st->bandwidth;
793885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
794885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   break;
795885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   case OPUS_GET_FINAL_RANGE_REQUEST:
796885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
797885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_uint32 *value = va_arg(ap, opus_uint32*);
798e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!value)
799e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
800e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         goto bad_arg;
801e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
802885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      *value = st->rangeFinal;
803885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
804885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   break;
805885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   case OPUS_RESET_STATE:
806885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
807885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
808885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            sizeof(OpusDecoder)-
809885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            ((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
810885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
811885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
812885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      silk_InitDecoder( silk_dec );
813885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      st->stream_channels = st->channels;
814885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      st->frame_size = st->Fs/400;
815885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
816885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   break;
817660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org   case OPUS_GET_SAMPLE_RATE_REQUEST:
818660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org   {
819660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org      opus_int32 *value = va_arg(ap, opus_int32*);
820e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!value)
821660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org      {
822e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         goto bad_arg;
823660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org      }
824660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org      *value = st->Fs;
825660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org   }
826660e25f9ad9e0b421241dcf675c6883fecb859cdsergeyu@chromium.org   break;
827885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   case OPUS_GET_PITCH_REQUEST:
828885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
829885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 *value = va_arg(ap, opus_int32*);
830e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!value)
831885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
832e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         goto bad_arg;
833885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
834885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (st->prev_mode == MODE_CELT_ONLY)
835885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
836885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      else
837885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         *value = st->DecControl.prevPitchLag;
838885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
839885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   break;
840885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   case OPUS_GET_GAIN_REQUEST:
841885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
842885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 *value = va_arg(ap, opus_int32*);
843e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!value)
844885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      {
845e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         goto bad_arg;
846885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      }
847885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      *value = st->decode_gain;
848885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
849885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   break;
850885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   case OPUS_SET_GAIN_REQUEST:
851885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
852885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       opus_int32 value = va_arg(ap, opus_int32);
853885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       if (value<-32768 || value>32767)
854885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       {
855e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org          goto bad_arg;
856885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       }
857885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org       st->decode_gain = value;
858885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
859885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   break;
8606b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
8616b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   {
8626b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      opus_uint32 *value = va_arg(ap, opus_uint32*);
863e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      if (!value)
864e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      {
865e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org         goto bad_arg;
866e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org      }
8676b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      *value = st->last_packet_duration;
8686b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   }
8696b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   break;
870885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   default:
871885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
872885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      ret = OPUS_UNIMPLEMENTED;
873885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      break;
874885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
875885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
876885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   va_end(ap);
877885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return ret;
878e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.orgbad_arg:
879e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   va_end(ap);
880e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org   return OPUS_BAD_ARG;
881885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
882885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
883885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid opus_decoder_destroy(OpusDecoder *st)
884885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
885885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   opus_free(st);
886885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
887885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
888885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
889885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_packet_get_bandwidth(const unsigned char *data)
890885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
891885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int bandwidth;
892885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (data[0]&0x80)
893885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
894885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3);
895885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
896885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         bandwidth = OPUS_BANDWIDTH_NARROWBAND;
897885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else if ((data[0]&0x60) == 0x60)
898885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
899885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND :
900885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                   OPUS_BANDWIDTH_SUPERWIDEBAND;
901885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else {
902885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3);
903885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
904885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return bandwidth;
905885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
906885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
907885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_packet_get_samples_per_frame(const unsigned char *data,
908885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      opus_int32 Fs)
909885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
910885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int audiosize;
911885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (data[0]&0x80)
912885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
913885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      audiosize = ((data[0]>>3)&0x3);
914885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      audiosize = (Fs<<audiosize)/400;
915885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else if ((data[0]&0x60) == 0x60)
916885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   {
917885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
918885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   } else {
919885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      audiosize = ((data[0]>>3)&0x3);
920885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      if (audiosize == 3)
921885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         audiosize = Fs*60/1000;
922885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      else
923885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org         audiosize = (Fs<<audiosize)/100;
924885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   }
925885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return audiosize;
926885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
927885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
928885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_packet_get_nb_channels(const unsigned char *data)
929885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
930885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   return (data[0]&0x4) ? 2 : 1;
931885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
932885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
933885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgint opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len)
934885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
935885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int count;
936885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (len<1)
937885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_BAD_ARG;
938885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   count = packet[0]&0x3;
939885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (count==0)
940885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return 1;
941885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   else if (count!=3)
942885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return 2;
943885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   else if (len<2)
944885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_INVALID_PACKET;
945885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   else
946885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return packet[1]&0x3F;
947885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
948885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
9496b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.orgint opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
9506b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      opus_int32 Fs)
951885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org{
952885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int samples;
953885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   int count = opus_packet_get_nb_frames(packet, len);
954885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
955885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   if (count<0)
956885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return count;
957885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
9586b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   samples = count*opus_packet_get_samples_per_frame(packet, Fs);
959885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   /* Can't have more than 120 ms */
9606b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   if (samples*25 > Fs*3)
961885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return OPUS_INVALID_PACKET;
962885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org   else
963885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      return samples;
964885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
9656b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org
9666b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.orgint opus_decoder_get_nb_samples(const OpusDecoder *dec,
9676b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org      const unsigned char packet[], opus_int32 len)
9686b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org{
9696b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org   return opus_packet_get_nb_samples(packet, len, dec->Fs);
9706b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org}
971