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