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