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