| 
									
										
										
										
											2016-11-04 15:08:30 +08:00
										 |  |  | /******************************************************************************
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2014 The Android Open Source Project | 
					
						
							|  |  |  |  *  Copyright 2006 Open Interface North America, Inc. All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  *  you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  *  You may obtain a copy of the License at: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  *  distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  *  See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  *  limitations under the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  ******************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**********************************************************************************
 | 
					
						
							|  |  |  |   $Revision: #1 $ | 
					
						
							|  |  |  |  ***********************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @file
 | 
					
						
							|  |  |  | @ingroup codec_internal | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**@addtogroup codec_internal */ | 
					
						
							|  |  |  | /**@{*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "oi_codec_sbc_private.h"
 | 
					
						
							|  |  |  | #include "oi_bitstream.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SPECIALIZE_READ_SAMPLES_JOINT
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Scans through a buffer looking for a codec syncword. If the decoder has been | 
					
						
							|  |  |  |  * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search | 
					
						
							|  |  |  |  * for both a standard and an enhanced syncword. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context, | 
					
						
							|  |  |  |                                const OI_BYTE **frameData, | 
					
						
							|  |  |  |                                OI_UINT32 *frameBytes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef SBC_ENHANCED
 | 
					
						
							|  |  |  |     OI_BYTE search1 = OI_SBC_SYNCWORD; | 
					
						
							|  |  |  |     OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD; | 
					
						
							|  |  |  | #endif // SBC_ENHANCED
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (*frameBytes == 0) { | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef SBC_ENHANCED
 | 
					
						
							| 
									
										
										
										
											2016-11-26 13:09:55 +08:00
										 |  |  |     if (context->limitFrameFormat && context->enhancedEnabled) { | 
					
						
							| 
									
										
										
										
											2016-11-04 15:08:30 +08:00
										 |  |  |         /* If the context is restricted, only search for specified SYNCWORD */ | 
					
						
							|  |  |  |         search1 = search2; | 
					
						
							|  |  |  |     } else if (context->enhancedEnabled == FALSE) { | 
					
						
							|  |  |  |         /* If enhanced is not enabled, only search for classic SBC SYNCWORD*/ | 
					
						
							|  |  |  |         search2 = search1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     while (*frameBytes && (**frameData != search1) && (**frameData != search2)) { | 
					
						
							|  |  |  |         (*frameBytes)--; | 
					
						
							|  |  |  |         (*frameData)++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (*frameBytes) { | 
					
						
							|  |  |  |         /* Syncword found, *frameData points to it, and *frameBytes correctly
 | 
					
						
							|  |  |  |          * reflects the number of bytes available to read, including the | 
					
						
							|  |  |  |          * syncword. */ | 
					
						
							|  |  |  |         context->common.frameInfo.enhanced = (**frameData == OI_SBC_ENHANCED_SYNCWORD); | 
					
						
							|  |  |  |         return OI_OK; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         /* No syncword was found anywhere in the provided input data.
 | 
					
						
							|  |  |  |          * *frameData points past the end of the original input, and | 
					
						
							|  |  |  |          * *frameBytes is 0. */ | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NO_SYNCWORD; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #else  // SBC_ENHANCED
 | 
					
						
							|  |  |  |     while (*frameBytes && (**frameData != OI_SBC_SYNCWORD)) { | 
					
						
							|  |  |  |         (*frameBytes)--; | 
					
						
							|  |  |  |         (*frameData)++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (*frameBytes) { | 
					
						
							|  |  |  |         /* Syncword found, *frameData points to it, and *frameBytes correctly
 | 
					
						
							|  |  |  |          * reflects the number of bytes available to read, including the | 
					
						
							|  |  |  |          * syncword. */ | 
					
						
							|  |  |  |         context->common.frameInfo.enhanced = FALSE; | 
					
						
							|  |  |  |         return OI_OK; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         /* No syncword was found anywhere in the provided input data.
 | 
					
						
							|  |  |  |          * *frameData points past the end of the original input, and | 
					
						
							|  |  |  |          * *frameBytes is 0. */ | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NO_SYNCWORD; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif // SBC_ENHANCED
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT *context, | 
					
						
							|  |  |  |                             const OI_BYTE *bodyData, | 
					
						
							|  |  |  |                             OI_INT16 *pcmData, | 
					
						
							|  |  |  |                             OI_UINT32 *pcmBytes, | 
					
						
							|  |  |  |                             OI_BOOL allowPartial) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OI_BITSTREAM bs; | 
					
						
							|  |  |  |     OI_UINT frameSamples = context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands; | 
					
						
							|  |  |  |     OI_UINT decode_block_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Based on the header data, make sure that there is enough room to write the output samples. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (*pcmBytes < (sizeof(OI_INT16) * frameSamples * context->common.pcmStride) && !allowPartial) { | 
					
						
							|  |  |  |         /* If we're not allowing partial decodes, we need room for the entire
 | 
					
						
							|  |  |  |          * codec frame */ | 
					
						
							|  |  |  |         TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA")); | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA; | 
					
						
							|  |  |  |     } else if (*pcmBytes < sizeof (OI_INT16) * context->common.frameInfo.nrof_subbands * context->common.pcmStride) { | 
					
						
							|  |  |  |         /* Even if we're allowing partials, we can still only decode on a frame
 | 
					
						
							|  |  |  |          * boundary */ | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (context->bufferedBlocks == 0) { | 
					
						
							|  |  |  |         TRACE(("Reading scalefactors")); | 
					
						
							|  |  |  |         OI_SBC_ReadScalefactors(&context->common, bodyData, &bs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TRACE(("Computing bit allocation")); | 
					
						
							|  |  |  |         OI_SBC_ComputeBitAllocation(&context->common); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TRACE(("Reading samples")); | 
					
						
							|  |  |  |         if (context->common.frameInfo.mode == SBC_JOINT_STEREO) { | 
					
						
							|  |  |  |             OI_SBC_ReadSamplesJoint(context, &bs); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             OI_SBC_ReadSamples(context, &bs); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         context->bufferedBlocks = context->common.frameInfo.nrof_blocks; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (allowPartial) { | 
					
						
							|  |  |  |         decode_block_count = *pcmBytes / sizeof(OI_INT16) / context->common.pcmStride / context->common.frameInfo.nrof_subbands; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (decode_block_count > context->bufferedBlocks) { | 
					
						
							|  |  |  |             decode_block_count = context->bufferedBlocks; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         decode_block_count = context->common.frameInfo.nrof_blocks; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TRACE(("Synthesizing frame")); | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         OI_UINT start_block = context->common.frameInfo.nrof_blocks - context->bufferedBlocks; | 
					
						
							|  |  |  |         OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     OI_ASSERT(context->bufferedBlocks >= decode_block_count); | 
					
						
							|  |  |  |     context->bufferedBlocks -= decode_block_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * When decoding mono into a stride-2 array, copy pcm data to second channel | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (context->common.frameInfo.nrof_channels == 1 && context->common.pcmStride == 2) { | 
					
						
							|  |  |  |         OI_UINT i; | 
					
						
							|  |  |  |         for (i = 0; i < frameSamples; ++i) { | 
					
						
							| 
									
										
										
										
											2016-11-26 13:09:55 +08:00
										 |  |  |             pcmData[2 * i + 1] = pcmData[2 * i]; | 
					
						
							| 
									
										
										
										
											2016-11-04 15:08:30 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Return number of pcm bytes generated by the decode operation. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     *pcmBytes = frameSamples * sizeof(OI_INT16) * context->common.pcmStride; | 
					
						
							|  |  |  |     if (context->bufferedBlocks > 0) { | 
					
						
							|  |  |  |         return OI_CODEC_SBC_PARTIAL_DECODE; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return OI_OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, | 
					
						
							|  |  |  |                                      OI_UINT8 bitpool, | 
					
						
							|  |  |  |                                      const OI_BYTE **frameData, | 
					
						
							|  |  |  |                                      OI_UINT32 *frameBytes, | 
					
						
							|  |  |  |                                      OI_INT16 *pcmData, | 
					
						
							|  |  |  |                                      OI_UINT32 *pcmBytes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OI_STATUS status; | 
					
						
							|  |  |  |     OI_UINT bodyLen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TRACE(("+OI_CODEC_SBC_DecodeRaw")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (context->bufferedBlocks == 0) { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * The bitallocator needs to know the bitpool value. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         context->common.frameInfo.bitpool = bitpool; | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Compute the frame length and check we have enough frame data to proceed | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) - SBC_HEADER_LEN; | 
					
						
							|  |  |  |         if (*frameBytes < bodyLen) { | 
					
						
							|  |  |  |             TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA")); | 
					
						
							|  |  |  |             return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         bodyLen = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Decode the SBC data. Pass TRUE to DecodeBody to allow partial decoding of | 
					
						
							|  |  |  |      * tones. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE); | 
					
						
							|  |  |  |     if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) { | 
					
						
							|  |  |  |         *frameData += bodyLen; | 
					
						
							|  |  |  |         *frameBytes -= bodyLen; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status)); | 
					
						
							|  |  |  |     return status; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OI_STATUS 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) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, | 
					
						
							|  |  |  |                                    const OI_BYTE **frameData, | 
					
						
							|  |  |  |                                    OI_UINT32 *frameBytes, | 
					
						
							|  |  |  |                                    OI_INT16 *pcmData, | 
					
						
							|  |  |  |                                    OI_UINT32 *pcmBytes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OI_STATUS status; | 
					
						
							|  |  |  |     OI_UINT framelen; | 
					
						
							|  |  |  |     OI_UINT8 crc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TRACE(("+OI_CODEC_SBC_DecodeFrame")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TRACE(("Finding syncword")); | 
					
						
							|  |  |  |     status = FindSyncword(context, frameData, frameBytes); | 
					
						
							|  |  |  |     if (!OI_SUCCESS(status)) { | 
					
						
							|  |  |  |         return status; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Make sure enough data remains to read the header. */ | 
					
						
							|  |  |  |     if (*frameBytes < SBC_HEADER_LEN) { | 
					
						
							|  |  |  |         TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA")); | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TRACE(("Reading Header")); | 
					
						
							|  |  |  |     OI_SBC_ReadHeader(&context->common, *frameData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Some implementations load the decoder into RAM and use overlays for 4 vs 8 subbands. We need | 
					
						
							|  |  |  |      * to ensure that the SBC parameters for this frame are compatible with the restrictions imposed | 
					
						
							|  |  |  |      * by the loaded overlays. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (context->limitFrameFormat && (context->common.frameInfo.subbands != context->restrictSubbands)) { | 
					
						
							|  |  |  |         ERROR(("SBC parameters incompatible with loaded overlay")); | 
					
						
							|  |  |  |         return OI_STATUS_INVALID_PARAMETERS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (context->common.frameInfo.nrof_channels > context->common.maxChannels) { | 
					
						
							|  |  |  |         ERROR(("SBC parameters incompatible with number of channels specified during reset")); | 
					
						
							|  |  |  |         return OI_STATUS_INVALID_PARAMETERS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (context->common.pcmStride < 1 || context->common.pcmStride > 2) { | 
					
						
							|  |  |  |         ERROR(("PCM stride not set correctly during reset")); | 
					
						
							|  |  |  |         return OI_STATUS_INVALID_PARAMETERS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * At this point a header has been read. However, it's possible that we found a false syncword, | 
					
						
							|  |  |  |      * so the header data might be invalid. Make sure we have enough bytes to read in the | 
					
						
							|  |  |  |      * CRC-protected header, but don't require we have the whole frame. That way, if it turns out | 
					
						
							|  |  |  |      * that we're acting on bogus header data, we don't stall the decoding process by waiting for | 
					
						
							|  |  |  |      * data that we don't actually need. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo); | 
					
						
							|  |  |  |     if (*frameBytes < framelen) { | 
					
						
							|  |  |  |         TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA")); | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TRACE(("Calculating checksum")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData); | 
					
						
							|  |  |  |     if (crc != context->common.frameInfo.crc) { | 
					
						
							|  |  |  |         TRACE(("CRC Mismatch:  calc=%02x read=%02x\n", crc, context->common.frameInfo.crc)); | 
					
						
							|  |  |  |         TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH")); | 
					
						
							|  |  |  |         return OI_CODEC_SBC_CHECKSUM_MISMATCH; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef OI_DEBUG
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Make sure the bitpool values are sane. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) && !context->common.frameInfo.enhanced) { | 
					
						
							|  |  |  |         ERROR(("Bitpool too small: %d (must be >= 2)", context->common.frameInfo.bitpool)); | 
					
						
							|  |  |  |         return OI_STATUS_INVALID_PARAMETERS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context->common.frameInfo.bitpool > OI_SBC_MaxBitpool(&context->common.frameInfo)) { | 
					
						
							|  |  |  |         ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo))); | 
					
						
							|  |  |  |         return OI_STATUS_INVALID_PARAMETERS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Now decode the SBC data. Partial decode is not yet implemented for an SBC | 
					
						
							|  |  |  |      * stream, so pass FALSE to decode body to have it enforce the old rule that | 
					
						
							|  |  |  |      * you have to decode a whole packet at a time. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes, FALSE); | 
					
						
							|  |  |  |     if (OI_SUCCESS(status)) { | 
					
						
							|  |  |  |         *frameData += framelen; | 
					
						
							|  |  |  |         *frameBytes -= framelen; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return status; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, | 
					
						
							|  |  |  |                                  const OI_BYTE **frameData, | 
					
						
							|  |  |  |                                  OI_UINT32 *frameBytes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OI_STATUS status; | 
					
						
							|  |  |  |     OI_UINT framelen; | 
					
						
							|  |  |  |     OI_UINT headerlen; | 
					
						
							|  |  |  |     OI_UINT8 crc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     status = FindSyncword(context, frameData, frameBytes); | 
					
						
							|  |  |  |     if (!OI_SUCCESS(status)) { | 
					
						
							|  |  |  |         return status; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (*frameBytes < SBC_HEADER_LEN) { | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     OI_SBC_ReadHeader(&context->common, *frameData); | 
					
						
							|  |  |  |     framelen = OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen); | 
					
						
							|  |  |  |     if (*frameBytes < headerlen) { | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData); | 
					
						
							|  |  |  |     if (crc != context->common.frameInfo.crc) { | 
					
						
							|  |  |  |         return OI_CODEC_SBC_CHECKSUM_MISMATCH; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (*frameBytes < framelen) { | 
					
						
							|  |  |  |         return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     context->bufferedBlocks = 0; | 
					
						
							|  |  |  |     *frameData += framelen; | 
					
						
							|  |  |  |     *frameBytes -= framelen; | 
					
						
							|  |  |  |     return OI_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OI_UINT8 OI_CODEC_SBC_FrameCount(OI_BYTE  *frameData, | 
					
						
							|  |  |  |                                  OI_UINT32 frameBytes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OI_UINT8 mode; | 
					
						
							|  |  |  |     OI_UINT8 blocks; | 
					
						
							|  |  |  |     OI_UINT8 subbands; | 
					
						
							|  |  |  |     OI_UINT8 frameCount = 0; | 
					
						
							|  |  |  |     OI_UINT  frameLen; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-26 13:09:55 +08:00
										 |  |  |     while (frameBytes) { | 
					
						
							|  |  |  |         while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)) { | 
					
						
							| 
									
										
										
										
											2016-11-04 15:08:30 +08:00
										 |  |  |             frameData++; | 
					
						
							|  |  |  |             frameBytes--; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (frameBytes < SBC_HEADER_LEN) { | 
					
						
							|  |  |  |             return frameCount; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Extract and translate required fields from Header */ | 
					
						
							|  |  |  |         subbands = mode = blocks = frameData[1];; | 
					
						
							|  |  |  |         mode = (mode & (BIT3 | BIT2)) >> 2; | 
					
						
							|  |  |  |         blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4]; | 
					
						
							|  |  |  |         subbands = band_values[(subbands & BIT0)]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Inline logic to avoid corrupting context */ | 
					
						
							|  |  |  |         frameLen = blocks * frameData[2]; | 
					
						
							| 
									
										
										
										
											2016-11-26 13:09:55 +08:00
										 |  |  |         switch (mode) { | 
					
						
							|  |  |  |         case SBC_JOINT_STEREO: | 
					
						
							|  |  |  |             frameLen += subbands + (8 * subbands); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         case SBC_DUAL_CHANNEL: | 
					
						
							|  |  |  |             frameLen *= 2; | 
					
						
							|  |  |  |         /* fall through */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             if (mode == SBC_MONO) { | 
					
						
							|  |  |  |                 frameLen += 4 * subbands; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 frameLen += 8 * subbands; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-11-04 15:08:30 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         frameCount++; | 
					
						
							|  |  |  |         frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8; | 
					
						
							| 
									
										
										
										
											2016-11-26 13:09:55 +08:00
										 |  |  |         if (frameBytes > frameLen) { | 
					
						
							| 
									
										
										
										
											2016-11-04 15:08:30 +08:00
										 |  |  |             frameBytes -= frameLen; | 
					
						
							|  |  |  |             frameData += frameLen; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             frameBytes = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return frameCount; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Read quantized subband samples from the input bitstream and expand them. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef SPECIALIZE_READ_SAMPLES_JOINT
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #define NROF_SUBBANDS 4
 | 
					
						
							|  |  |  | #include "readsamplesjoint.inc"
 | 
					
						
							|  |  |  | #undef NROF_SUBBANDS
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #define NROF_SUBBANDS 8
 | 
					
						
							|  |  |  | #include "readsamplesjoint.inc"
 | 
					
						
							|  |  |  | #undef NROF_SUBBANDS
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const READ_SAMPLES SpecializedReadSamples[] = { | 
					
						
							|  |  |  |     OI_SBC_ReadSamplesJoint4, | 
					
						
							|  |  |  |     OI_SBC_ReadSamplesJoint8 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* SPECIALIZE_READ_SAMPLES_JOINT */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common; | 
					
						
							|  |  |  |     OI_UINT nrof_subbands = common->frameInfo.nrof_subbands; | 
					
						
							|  |  |  | #ifdef SPECIALIZE_READ_SAMPLES_JOINT
 | 
					
						
							|  |  |  |     OI_ASSERT((nrof_subbands >> 3u) <= 1u); | 
					
						
							|  |  |  |     SpecializedReadSamples[nrof_subbands >> 3](context, global_bs); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define NROF_SUBBANDS nrof_subbands
 | 
					
						
							|  |  |  | #include "readsamplesjoint.inc"
 | 
					
						
							|  |  |  | #undef NROF_SUBBANDS
 | 
					
						
							|  |  |  | #endif /* SPECIALIZE_READ_SAMPLES_JOINT */
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**@}*/ | 
					
						
							|  |  |  | 
 |