xref: /btstack/3rd-party/bluedroid/decoder/srce/decoder-sbc.c (revision df25739fc3ea5a0a90f0f5925e6461d653697d2e)
1*df25739fSMilanka Ringwald /******************************************************************************
2*df25739fSMilanka Ringwald  *
3*df25739fSMilanka Ringwald  *  Copyright (C) 2014 The Android Open Source Project
4*df25739fSMilanka Ringwald  *  Copyright 2006 Open Interface North America, Inc. All rights reserved.
5*df25739fSMilanka Ringwald  *
6*df25739fSMilanka Ringwald  *  Licensed under the Apache License, Version 2.0 (the "License");
7*df25739fSMilanka Ringwald  *  you may not use this file except in compliance with the License.
8*df25739fSMilanka Ringwald  *  You may obtain a copy of the License at:
9*df25739fSMilanka Ringwald  *
10*df25739fSMilanka Ringwald  *  http://www.apache.org/licenses/LICENSE-2.0
11*df25739fSMilanka Ringwald  *
12*df25739fSMilanka Ringwald  *  Unless required by applicable law or agreed to in writing, software
13*df25739fSMilanka Ringwald  *  distributed under the License is distributed on an "AS IS" BASIS,
14*df25739fSMilanka Ringwald  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*df25739fSMilanka Ringwald  *  See the License for the specific language governing permissions and
16*df25739fSMilanka Ringwald  *  limitations under the License.
17*df25739fSMilanka Ringwald  *
18*df25739fSMilanka Ringwald  ******************************************************************************/
19*df25739fSMilanka Ringwald 
20*df25739fSMilanka Ringwald /**********************************************************************************
21*df25739fSMilanka Ringwald   $Revision: #1 $
22*df25739fSMilanka Ringwald  ***********************************************************************************/
23*df25739fSMilanka Ringwald 
24*df25739fSMilanka Ringwald /** @file
25*df25739fSMilanka Ringwald @ingroup codec_internal
26*df25739fSMilanka Ringwald */
27*df25739fSMilanka Ringwald 
28*df25739fSMilanka Ringwald /**@addtogroup codec_internal */
29*df25739fSMilanka Ringwald /**@{*/
30*df25739fSMilanka Ringwald 
31*df25739fSMilanka Ringwald #include "oi_codec_sbc_private.h"
32*df25739fSMilanka Ringwald #include "oi_bitstream.h"
33*df25739fSMilanka Ringwald 
34*df25739fSMilanka Ringwald #define SPECIALIZE_READ_SAMPLES_JOINT
35*df25739fSMilanka Ringwald 
36*df25739fSMilanka Ringwald /**
37*df25739fSMilanka Ringwald  * Scans through a buffer looking for a codec syncword. If the decoder has been
38*df25739fSMilanka Ringwald  * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search
39*df25739fSMilanka Ringwald  * for both a standard and an enhanced syncword.
40*df25739fSMilanka Ringwald  */
41*df25739fSMilanka Ringwald PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context,
42*df25739fSMilanka Ringwald                                const OI_BYTE **frameData,
43*df25739fSMilanka Ringwald                                OI_UINT32 *frameBytes)
44*df25739fSMilanka Ringwald {
45*df25739fSMilanka Ringwald #ifdef SBC_ENHANCED
46*df25739fSMilanka Ringwald     OI_BYTE search1 = OI_SBC_SYNCWORD;
47*df25739fSMilanka Ringwald     OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD;
48*df25739fSMilanka Ringwald #endif // SBC_ENHANCED
49*df25739fSMilanka Ringwald 
50*df25739fSMilanka Ringwald     if (*frameBytes == 0) {
51*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
52*df25739fSMilanka Ringwald     }
53*df25739fSMilanka Ringwald 
54*df25739fSMilanka Ringwald #ifdef SBC_ENHANCED
55*df25739fSMilanka Ringwald     if (context->limitFrameFormat && context->enhancedEnabled){
56*df25739fSMilanka Ringwald         /* If the context is restricted, only search for specified SYNCWORD */
57*df25739fSMilanka Ringwald         search1 = search2;
58*df25739fSMilanka Ringwald     } else if (context->enhancedEnabled == FALSE) {
59*df25739fSMilanka Ringwald         /* If enhanced is not enabled, only search for classic SBC SYNCWORD*/
60*df25739fSMilanka Ringwald         search2 = search1;
61*df25739fSMilanka Ringwald     }
62*df25739fSMilanka Ringwald     while (*frameBytes && (**frameData != search1) && (**frameData != search2)) {
63*df25739fSMilanka Ringwald         (*frameBytes)--;
64*df25739fSMilanka Ringwald         (*frameData)++;
65*df25739fSMilanka Ringwald     }
66*df25739fSMilanka Ringwald     if (*frameBytes) {
67*df25739fSMilanka Ringwald         /* Syncword found, *frameData points to it, and *frameBytes correctly
68*df25739fSMilanka Ringwald          * reflects the number of bytes available to read, including the
69*df25739fSMilanka Ringwald          * syncword. */
70*df25739fSMilanka Ringwald         context->common.frameInfo.enhanced = (**frameData == OI_SBC_ENHANCED_SYNCWORD);
71*df25739fSMilanka Ringwald         return OI_OK;
72*df25739fSMilanka Ringwald     } else {
73*df25739fSMilanka Ringwald         /* No syncword was found anywhere in the provided input data.
74*df25739fSMilanka Ringwald          * *frameData points past the end of the original input, and
75*df25739fSMilanka Ringwald          * *frameBytes is 0. */
76*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NO_SYNCWORD;
77*df25739fSMilanka Ringwald     }
78*df25739fSMilanka Ringwald #else  // SBC_ENHANCED
79*df25739fSMilanka Ringwald     while (*frameBytes && (**frameData != OI_SBC_SYNCWORD)) {
80*df25739fSMilanka Ringwald         (*frameBytes)--;
81*df25739fSMilanka Ringwald         (*frameData)++;
82*df25739fSMilanka Ringwald     }
83*df25739fSMilanka Ringwald 
84*df25739fSMilanka Ringwald     if (*frameBytes) {
85*df25739fSMilanka Ringwald         /* Syncword found, *frameData points to it, and *frameBytes correctly
86*df25739fSMilanka Ringwald          * reflects the number of bytes available to read, including the
87*df25739fSMilanka Ringwald          * syncword. */
88*df25739fSMilanka Ringwald         context->common.frameInfo.enhanced = FALSE;
89*df25739fSMilanka Ringwald         return OI_OK;
90*df25739fSMilanka Ringwald     } else {
91*df25739fSMilanka Ringwald         /* No syncword was found anywhere in the provided input data.
92*df25739fSMilanka Ringwald          * *frameData points past the end of the original input, and
93*df25739fSMilanka Ringwald          * *frameBytes is 0. */
94*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NO_SYNCWORD;
95*df25739fSMilanka Ringwald     }
96*df25739fSMilanka Ringwald #endif // SBC_ENHANCED
97*df25739fSMilanka Ringwald }
98*df25739fSMilanka Ringwald 
99*df25739fSMilanka Ringwald 
100*df25739fSMilanka Ringwald static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT *context,
101*df25739fSMilanka Ringwald                             const OI_BYTE *bodyData,
102*df25739fSMilanka Ringwald                             OI_INT16 *pcmData,
103*df25739fSMilanka Ringwald                             OI_UINT32 *pcmBytes,
104*df25739fSMilanka Ringwald                             OI_BOOL allowPartial)
105*df25739fSMilanka Ringwald {
106*df25739fSMilanka Ringwald     OI_BITSTREAM bs;
107*df25739fSMilanka Ringwald     OI_UINT frameSamples = context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands;
108*df25739fSMilanka Ringwald     OI_UINT decode_block_count;
109*df25739fSMilanka Ringwald 
110*df25739fSMilanka Ringwald     /*
111*df25739fSMilanka Ringwald      * Based on the header data, make sure that there is enough room to write the output samples.
112*df25739fSMilanka Ringwald      */
113*df25739fSMilanka Ringwald     if (*pcmBytes < (sizeof(OI_INT16) * frameSamples * context->common.pcmStride) && !allowPartial) {
114*df25739fSMilanka Ringwald         /* If we're not allowing partial decodes, we need room for the entire
115*df25739fSMilanka Ringwald          * codec frame */
116*df25739fSMilanka Ringwald         TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA"));
117*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
118*df25739fSMilanka Ringwald     } else if (*pcmBytes < sizeof (OI_INT16) * context->common.frameInfo.nrof_subbands * context->common.pcmStride) {
119*df25739fSMilanka Ringwald         /* Even if we're allowing partials, we can still only decode on a frame
120*df25739fSMilanka Ringwald          * boundary */
121*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
122*df25739fSMilanka Ringwald     }
123*df25739fSMilanka Ringwald 
124*df25739fSMilanka Ringwald     if (context->bufferedBlocks == 0) {
125*df25739fSMilanka Ringwald         TRACE(("Reading scalefactors"));
126*df25739fSMilanka Ringwald         OI_SBC_ReadScalefactors(&context->common, bodyData, &bs);
127*df25739fSMilanka Ringwald 
128*df25739fSMilanka Ringwald         TRACE(("Computing bit allocation"));
129*df25739fSMilanka Ringwald         OI_SBC_ComputeBitAllocation(&context->common);
130*df25739fSMilanka Ringwald 
131*df25739fSMilanka Ringwald         TRACE(("Reading samples"));
132*df25739fSMilanka Ringwald         if (context->common.frameInfo.mode == SBC_JOINT_STEREO) {
133*df25739fSMilanka Ringwald             OI_SBC_ReadSamplesJoint(context, &bs);
134*df25739fSMilanka Ringwald         } else {
135*df25739fSMilanka Ringwald             OI_SBC_ReadSamples(context, &bs);
136*df25739fSMilanka Ringwald         }
137*df25739fSMilanka Ringwald 
138*df25739fSMilanka Ringwald         context->bufferedBlocks = context->common.frameInfo.nrof_blocks;
139*df25739fSMilanka Ringwald     }
140*df25739fSMilanka Ringwald 
141*df25739fSMilanka Ringwald     if (allowPartial) {
142*df25739fSMilanka Ringwald         decode_block_count = *pcmBytes / sizeof(OI_INT16) / context->common.pcmStride / context->common.frameInfo.nrof_subbands;
143*df25739fSMilanka Ringwald 
144*df25739fSMilanka Ringwald         if (decode_block_count > context->bufferedBlocks) {
145*df25739fSMilanka Ringwald             decode_block_count = context->bufferedBlocks;
146*df25739fSMilanka Ringwald         }
147*df25739fSMilanka Ringwald 
148*df25739fSMilanka Ringwald     } else {
149*df25739fSMilanka Ringwald         decode_block_count = context->common.frameInfo.nrof_blocks;
150*df25739fSMilanka Ringwald     }
151*df25739fSMilanka Ringwald 
152*df25739fSMilanka Ringwald     TRACE(("Synthesizing frame"));
153*df25739fSMilanka Ringwald     {
154*df25739fSMilanka Ringwald         OI_UINT start_block = context->common.frameInfo.nrof_blocks - context->bufferedBlocks;
155*df25739fSMilanka Ringwald         OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count);
156*df25739fSMilanka Ringwald     }
157*df25739fSMilanka Ringwald 
158*df25739fSMilanka Ringwald     OI_ASSERT(context->bufferedBlocks >= decode_block_count);
159*df25739fSMilanka Ringwald     context->bufferedBlocks -= decode_block_count;
160*df25739fSMilanka Ringwald 
161*df25739fSMilanka Ringwald     frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands;
162*df25739fSMilanka Ringwald 
163*df25739fSMilanka Ringwald     /*
164*df25739fSMilanka Ringwald      * When decoding mono into a stride-2 array, copy pcm data to second channel
165*df25739fSMilanka Ringwald      */
166*df25739fSMilanka Ringwald     if (context->common.frameInfo.nrof_channels == 1 && context->common.pcmStride == 2) {
167*df25739fSMilanka Ringwald         OI_UINT i;
168*df25739fSMilanka Ringwald         for (i = 0; i < frameSamples; ++i) {
169*df25739fSMilanka Ringwald             pcmData[2*i+1] = pcmData[2*i];
170*df25739fSMilanka Ringwald         }
171*df25739fSMilanka Ringwald     }
172*df25739fSMilanka Ringwald 
173*df25739fSMilanka Ringwald     /*
174*df25739fSMilanka Ringwald      * Return number of pcm bytes generated by the decode operation.
175*df25739fSMilanka Ringwald      */
176*df25739fSMilanka Ringwald     *pcmBytes = frameSamples * sizeof(OI_INT16) * context->common.pcmStride;
177*df25739fSMilanka Ringwald 
178*df25739fSMilanka Ringwald     if (context->bufferedBlocks > 0) {
179*df25739fSMilanka Ringwald         return OI_CODEC_SBC_PARTIAL_DECODE;
180*df25739fSMilanka Ringwald     } else {
181*df25739fSMilanka Ringwald         return OI_OK;
182*df25739fSMilanka Ringwald     }
183*df25739fSMilanka Ringwald }
184*df25739fSMilanka Ringwald 
185*df25739fSMilanka Ringwald PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
186*df25739fSMilanka Ringwald                                      OI_UINT8 bitpool,
187*df25739fSMilanka Ringwald                                      const OI_BYTE **frameData,
188*df25739fSMilanka Ringwald                                      OI_UINT32 *frameBytes,
189*df25739fSMilanka Ringwald                                      OI_INT16 *pcmData,
190*df25739fSMilanka Ringwald                                      OI_UINT32 *pcmBytes)
191*df25739fSMilanka Ringwald {
192*df25739fSMilanka Ringwald     OI_STATUS status;
193*df25739fSMilanka Ringwald     OI_UINT bodyLen;
194*df25739fSMilanka Ringwald 
195*df25739fSMilanka Ringwald     TRACE(("+OI_CODEC_SBC_DecodeRaw"));
196*df25739fSMilanka Ringwald 
197*df25739fSMilanka Ringwald     if (context->bufferedBlocks == 0) {
198*df25739fSMilanka Ringwald         /*
199*df25739fSMilanka Ringwald          * The bitallocator needs to know the bitpool value.
200*df25739fSMilanka Ringwald          */
201*df25739fSMilanka Ringwald         context->common.frameInfo.bitpool = bitpool;
202*df25739fSMilanka Ringwald         /*
203*df25739fSMilanka Ringwald          * Compute the frame length and check we have enough frame data to proceed
204*df25739fSMilanka Ringwald          */
205*df25739fSMilanka Ringwald         bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) - SBC_HEADER_LEN;
206*df25739fSMilanka Ringwald         if (*frameBytes < bodyLen) {
207*df25739fSMilanka Ringwald             TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
208*df25739fSMilanka Ringwald             return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
209*df25739fSMilanka Ringwald         }
210*df25739fSMilanka Ringwald     } else {
211*df25739fSMilanka Ringwald         bodyLen = 0;
212*df25739fSMilanka Ringwald     }
213*df25739fSMilanka Ringwald     /*
214*df25739fSMilanka Ringwald      * Decode the SBC data. Pass TRUE to DecodeBody to allow partial decoding of
215*df25739fSMilanka Ringwald      * tones.
216*df25739fSMilanka Ringwald      */
217*df25739fSMilanka Ringwald     status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE);
218*df25739fSMilanka Ringwald     if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) {
219*df25739fSMilanka Ringwald         *frameData += bodyLen;
220*df25739fSMilanka Ringwald         *frameBytes -= bodyLen;
221*df25739fSMilanka Ringwald     }
222*df25739fSMilanka Ringwald     TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status));
223*df25739fSMilanka Ringwald     return status;
224*df25739fSMilanka Ringwald }
225*df25739fSMilanka Ringwald 
226*df25739fSMilanka Ringwald OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
227*df25739fSMilanka Ringwald                                     OI_UINT32 *decoderData,
228*df25739fSMilanka Ringwald                                     OI_UINT32 decoderDataBytes,
229*df25739fSMilanka Ringwald                                     OI_UINT8 maxChannels,
230*df25739fSMilanka Ringwald                                     OI_UINT8 pcmStride,
231*df25739fSMilanka Ringwald                                     OI_BOOL enhanced)
232*df25739fSMilanka Ringwald {
233*df25739fSMilanka Ringwald     return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced);
234*df25739fSMilanka Ringwald }
235*df25739fSMilanka Ringwald 
236*df25739fSMilanka Ringwald OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
237*df25739fSMilanka Ringwald                                    const OI_BYTE **frameData,
238*df25739fSMilanka Ringwald                                    OI_UINT32 *frameBytes,
239*df25739fSMilanka Ringwald                                    OI_INT16 *pcmData,
240*df25739fSMilanka Ringwald                                    OI_UINT32 *pcmBytes)
241*df25739fSMilanka Ringwald {
242*df25739fSMilanka Ringwald     OI_STATUS status;
243*df25739fSMilanka Ringwald     OI_UINT framelen;
244*df25739fSMilanka Ringwald     OI_UINT8 crc;
245*df25739fSMilanka Ringwald 
246*df25739fSMilanka Ringwald     TRACE(("+OI_CODEC_SBC_DecodeFrame"));
247*df25739fSMilanka Ringwald 
248*df25739fSMilanka Ringwald     TRACE(("Finding syncword"));
249*df25739fSMilanka Ringwald 
250*df25739fSMilanka Ringwald     status = FindSyncword(context, frameData, frameBytes);
251*df25739fSMilanka Ringwald     if (!OI_SUCCESS(status)) {
252*df25739fSMilanka Ringwald         return status;
253*df25739fSMilanka Ringwald     }
254*df25739fSMilanka Ringwald     /* Make sure enough data remains to read the header. */
255*df25739fSMilanka Ringwald     if (*frameBytes < SBC_HEADER_LEN) {
256*df25739fSMilanka Ringwald         TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA"));
257*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
258*df25739fSMilanka Ringwald     }
259*df25739fSMilanka Ringwald 
260*df25739fSMilanka Ringwald     TRACE(("Reading Header"));
261*df25739fSMilanka Ringwald     OI_SBC_ReadHeader(&context->common, *frameData);
262*df25739fSMilanka Ringwald 
263*df25739fSMilanka Ringwald     /*
264*df25739fSMilanka Ringwald      * Some implementations load the decoder into RAM and use overlays for 4 vs 8 subbands. We need
265*df25739fSMilanka Ringwald      * to ensure that the SBC parameters for this frame are compatible with the restrictions imposed
266*df25739fSMilanka Ringwald      * by the loaded overlays.
267*df25739fSMilanka Ringwald      */
268*df25739fSMilanka Ringwald     if (context->limitFrameFormat && (context->common.frameInfo.subbands != context->restrictSubbands)) {
269*df25739fSMilanka Ringwald         ERROR(("SBC parameters incompatible with loaded overlay"));
270*df25739fSMilanka Ringwald         return OI_STATUS_INVALID_PARAMETERS;
271*df25739fSMilanka Ringwald     }
272*df25739fSMilanka Ringwald     TRACE(("Frame: "));
273*df25739fSMilanka Ringwald 
274*df25739fSMilanka Ringwald     if (context->common.frameInfo.nrof_channels > context->common.maxChannels) {
275*df25739fSMilanka Ringwald         ERROR(("SBC parameters incompatible with number of channels specified during reset"));
276*df25739fSMilanka Ringwald         return OI_STATUS_INVALID_PARAMETERS;
277*df25739fSMilanka Ringwald     }
278*df25739fSMilanka Ringwald 
279*df25739fSMilanka Ringwald     if (context->common.pcmStride < 1 || context->common.pcmStride > 2) {
280*df25739fSMilanka Ringwald         ERROR(("PCM stride not set correctly during reset"));
281*df25739fSMilanka Ringwald         return OI_STATUS_INVALID_PARAMETERS;
282*df25739fSMilanka Ringwald     }
283*df25739fSMilanka Ringwald 
284*df25739fSMilanka Ringwald     /*
285*df25739fSMilanka Ringwald      * At this point a header has been read. However, it's possible that we found a false syncword,
286*df25739fSMilanka Ringwald      * so the header data might be invalid. Make sure we have enough bytes to read in the
287*df25739fSMilanka Ringwald      * CRC-protected header, but don't require we have the whole frame. That way, if it turns out
288*df25739fSMilanka Ringwald      * that we're acting on bogus header data, we don't stall the decoding process by waiting for
289*df25739fSMilanka Ringwald      * data that we don't actually need.
290*df25739fSMilanka Ringwald      */
291*df25739fSMilanka Ringwald     framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo);
292*df25739fSMilanka Ringwald     if (*frameBytes < framelen) {
293*df25739fSMilanka Ringwald         TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
294*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
295*df25739fSMilanka Ringwald     }
296*df25739fSMilanka Ringwald     TRACE(("frame len %d\n", framelen));
297*df25739fSMilanka Ringwald 
298*df25739fSMilanka Ringwald     TRACE(("Calculating checksum"));
299*df25739fSMilanka Ringwald 
300*df25739fSMilanka Ringwald     crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
301*df25739fSMilanka Ringwald     if (crc != context->common.frameInfo.crc) {
302*df25739fSMilanka Ringwald         TRACE(("CRC Mismatch:  calc=%02x read=%02x\n", crc, context->common.frameInfo.crc));
303*df25739fSMilanka Ringwald         TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH"));
304*df25739fSMilanka Ringwald         return OI_CODEC_SBC_CHECKSUM_MISMATCH;
305*df25739fSMilanka Ringwald     }
306*df25739fSMilanka Ringwald 
307*df25739fSMilanka Ringwald #ifdef OI_DEBUG
308*df25739fSMilanka Ringwald     /*
309*df25739fSMilanka Ringwald      * Make sure the bitpool values are sane.
310*df25739fSMilanka Ringwald      */
311*df25739fSMilanka Ringwald     if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) && !context->common.frameInfo.enhanced) {
312*df25739fSMilanka Ringwald         ERROR(("Bitpool too small: %d (must be >= 2)", context->common.frameInfo.bitpool));
313*df25739fSMilanka Ringwald         return OI_STATUS_INVALID_PARAMETERS;
314*df25739fSMilanka Ringwald     }
315*df25739fSMilanka Ringwald     if (context->common.frameInfo.bitpool > OI_SBC_MaxBitpool(&context->common.frameInfo)) {
316*df25739fSMilanka Ringwald         ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo)));
317*df25739fSMilanka Ringwald         return OI_STATUS_INVALID_PARAMETERS;
318*df25739fSMilanka Ringwald     }
319*df25739fSMilanka Ringwald #endif
320*df25739fSMilanka Ringwald 
321*df25739fSMilanka Ringwald     /*
322*df25739fSMilanka Ringwald      * Now decode the SBC data. Partial decode is not yet implemented for an SBC
323*df25739fSMilanka Ringwald      * stream, so pass FALSE to decode body to have it enforce the old rule that
324*df25739fSMilanka Ringwald      * you have to decode a whole packet at a time.
325*df25739fSMilanka Ringwald      */
326*df25739fSMilanka Ringwald     status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes, FALSE);
327*df25739fSMilanka Ringwald     if (OI_SUCCESS(status)) {
328*df25739fSMilanka Ringwald         *frameData += framelen;
329*df25739fSMilanka Ringwald         *frameBytes -= framelen;
330*df25739fSMilanka Ringwald     }
331*df25739fSMilanka Ringwald     TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status));
332*df25739fSMilanka Ringwald 
333*df25739fSMilanka Ringwald     return status;
334*df25739fSMilanka Ringwald }
335*df25739fSMilanka Ringwald 
336*df25739fSMilanka Ringwald OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
337*df25739fSMilanka Ringwald                                  const OI_BYTE **frameData,
338*df25739fSMilanka Ringwald                                  OI_UINT32 *frameBytes)
339*df25739fSMilanka Ringwald {
340*df25739fSMilanka Ringwald     OI_STATUS status;
341*df25739fSMilanka Ringwald     OI_UINT framelen;
342*df25739fSMilanka Ringwald     OI_UINT headerlen;
343*df25739fSMilanka Ringwald     OI_UINT8 crc;
344*df25739fSMilanka Ringwald 
345*df25739fSMilanka Ringwald     status = FindSyncword(context, frameData, frameBytes);
346*df25739fSMilanka Ringwald     if (!OI_SUCCESS(status)) {
347*df25739fSMilanka Ringwald         return status;
348*df25739fSMilanka Ringwald     }
349*df25739fSMilanka Ringwald     if (*frameBytes < SBC_HEADER_LEN) {
350*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
351*df25739fSMilanka Ringwald     }
352*df25739fSMilanka Ringwald     OI_SBC_ReadHeader(&context->common, *frameData);
353*df25739fSMilanka Ringwald     framelen = OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen);
354*df25739fSMilanka Ringwald     if (*frameBytes < headerlen) {
355*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
356*df25739fSMilanka Ringwald     }
357*df25739fSMilanka Ringwald     crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
358*df25739fSMilanka Ringwald     if (crc != context->common.frameInfo.crc) {
359*df25739fSMilanka Ringwald         return OI_CODEC_SBC_CHECKSUM_MISMATCH;
360*df25739fSMilanka Ringwald     }
361*df25739fSMilanka Ringwald     if (*frameBytes < framelen) {
362*df25739fSMilanka Ringwald         return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
363*df25739fSMilanka Ringwald     }
364*df25739fSMilanka Ringwald     context->bufferedBlocks = 0;
365*df25739fSMilanka Ringwald     *frameData += framelen;
366*df25739fSMilanka Ringwald     *frameBytes -= framelen;
367*df25739fSMilanka Ringwald     return OI_OK;
368*df25739fSMilanka Ringwald }
369*df25739fSMilanka Ringwald 
370*df25739fSMilanka Ringwald OI_UINT8 OI_CODEC_SBC_FrameCount(OI_BYTE  *frameData,
371*df25739fSMilanka Ringwald                                  OI_UINT32 frameBytes)
372*df25739fSMilanka Ringwald {
373*df25739fSMilanka Ringwald     OI_UINT8 mode;
374*df25739fSMilanka Ringwald     OI_UINT8 blocks;
375*df25739fSMilanka Ringwald     OI_UINT8 subbands;
376*df25739fSMilanka Ringwald     OI_UINT8 frameCount = 0;
377*df25739fSMilanka Ringwald     OI_UINT  frameLen;
378*df25739fSMilanka Ringwald 
379*df25739fSMilanka Ringwald     while (frameBytes){
380*df25739fSMilanka Ringwald         while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)){
381*df25739fSMilanka Ringwald             frameData++;
382*df25739fSMilanka Ringwald             frameBytes--;
383*df25739fSMilanka Ringwald         }
384*df25739fSMilanka Ringwald 
385*df25739fSMilanka Ringwald         if (frameBytes < SBC_HEADER_LEN) {
386*df25739fSMilanka Ringwald             return frameCount;
387*df25739fSMilanka Ringwald         }
388*df25739fSMilanka Ringwald 
389*df25739fSMilanka Ringwald         /* Extract and translate required fields from Header */
390*df25739fSMilanka Ringwald         subbands = mode = blocks = frameData[1];;
391*df25739fSMilanka Ringwald         mode = (mode & (BIT3 | BIT2)) >> 2;
392*df25739fSMilanka Ringwald         blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4];
393*df25739fSMilanka Ringwald         subbands = band_values[(subbands & BIT0)];
394*df25739fSMilanka Ringwald 
395*df25739fSMilanka Ringwald         /* Inline logic to avoid corrupting context */
396*df25739fSMilanka Ringwald         frameLen = blocks * frameData[2];
397*df25739fSMilanka Ringwald         switch (mode){
398*df25739fSMilanka Ringwald             case SBC_JOINT_STEREO:
399*df25739fSMilanka Ringwald                 frameLen += subbands + (8 * subbands);
400*df25739fSMilanka Ringwald                 break;
401*df25739fSMilanka Ringwald 
402*df25739fSMilanka Ringwald             case SBC_DUAL_CHANNEL:
403*df25739fSMilanka Ringwald                 frameLen *= 2;
404*df25739fSMilanka Ringwald                 /* fall through */
405*df25739fSMilanka Ringwald 
406*df25739fSMilanka Ringwald             default:
407*df25739fSMilanka Ringwald                 if (mode == SBC_MONO){
408*df25739fSMilanka Ringwald                     frameLen += 4*subbands;
409*df25739fSMilanka Ringwald                 } else {
410*df25739fSMilanka Ringwald                     frameLen += 8*subbands;
411*df25739fSMilanka Ringwald                 }
412*df25739fSMilanka Ringwald         }
413*df25739fSMilanka Ringwald 
414*df25739fSMilanka Ringwald         frameCount++;
415*df25739fSMilanka Ringwald         frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8;
416*df25739fSMilanka Ringwald         if (frameBytes > frameLen){
417*df25739fSMilanka Ringwald             frameBytes -= frameLen;
418*df25739fSMilanka Ringwald             frameData += frameLen;
419*df25739fSMilanka Ringwald         } else {
420*df25739fSMilanka Ringwald             frameBytes = 0;
421*df25739fSMilanka Ringwald         }
422*df25739fSMilanka Ringwald     }
423*df25739fSMilanka Ringwald     return frameCount;
424*df25739fSMilanka Ringwald }
425*df25739fSMilanka Ringwald 
426*df25739fSMilanka Ringwald /** Read quantized subband samples from the input bitstream and expand them. */
427*df25739fSMilanka Ringwald 
428*df25739fSMilanka Ringwald #ifdef SPECIALIZE_READ_SAMPLES_JOINT
429*df25739fSMilanka Ringwald 
430*df25739fSMilanka Ringwald PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
431*df25739fSMilanka Ringwald {
432*df25739fSMilanka Ringwald #define NROF_SUBBANDS 4
433*df25739fSMilanka Ringwald #include "readsamplesjoint.inc"
434*df25739fSMilanka Ringwald #undef NROF_SUBBANDS
435*df25739fSMilanka Ringwald }
436*df25739fSMilanka Ringwald 
437*df25739fSMilanka Ringwald PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
438*df25739fSMilanka Ringwald {
439*df25739fSMilanka Ringwald #define NROF_SUBBANDS 8
440*df25739fSMilanka Ringwald #include "readsamplesjoint.inc"
441*df25739fSMilanka Ringwald #undef NROF_SUBBANDS
442*df25739fSMilanka Ringwald }
443*df25739fSMilanka Ringwald 
444*df25739fSMilanka Ringwald typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs);
445*df25739fSMilanka Ringwald 
446*df25739fSMilanka Ringwald static const READ_SAMPLES SpecializedReadSamples[] = {
447*df25739fSMilanka Ringwald     OI_SBC_ReadSamplesJoint4,
448*df25739fSMilanka Ringwald     OI_SBC_ReadSamplesJoint8
449*df25739fSMilanka Ringwald };
450*df25739fSMilanka Ringwald 
451*df25739fSMilanka Ringwald #endif /* SPECIALIZE_READ_SAMPLES_JOINT */
452*df25739fSMilanka Ringwald 
453*df25739fSMilanka Ringwald 
454*df25739fSMilanka Ringwald PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
455*df25739fSMilanka Ringwald {
456*df25739fSMilanka Ringwald     OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
457*df25739fSMilanka Ringwald     OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
458*df25739fSMilanka Ringwald #ifdef SPECIALIZE_READ_SAMPLES_JOINT
459*df25739fSMilanka Ringwald     OI_ASSERT((nrof_subbands >> 3u) <= 1u);
460*df25739fSMilanka Ringwald     SpecializedReadSamples[nrof_subbands >> 3](context, global_bs);
461*df25739fSMilanka Ringwald #else
462*df25739fSMilanka Ringwald 
463*df25739fSMilanka Ringwald #define NROF_SUBBANDS nrof_subbands
464*df25739fSMilanka Ringwald #include "readsamplesjoint.inc"
465*df25739fSMilanka Ringwald #undef NROF_SUBBANDS
466*df25739fSMilanka Ringwald #endif /* SPECIALIZE_READ_SAMPLES_JOINT */
467*df25739fSMilanka Ringwald }
468*df25739fSMilanka Ringwald 
469*df25739fSMilanka Ringwald /**@}*/
470*df25739fSMilanka Ringwald 
471