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