sl@0: // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include // KMmfUidSBCConfigure sl@0: sl@0: #include "SBCEncoder.h" sl@0: #include "SBCConst.h" sl@0: #include "SBCFrameParameters.h" sl@0: sl@0: /** sl@0: The sbc configuration UID, used to identify configuration type, sl@0: have to use this to configure any sbc codec. sl@0: */ sl@0: const TUid KSBCConfigTypeUid = { KMmfUidSBCConfigure }; sl@0: sl@0: /** sl@0: SBC CRC shift register initial value for SBC CRC calculation sl@0: */ sl@0: const TUint8 KSbcCRCShiftRegisterInit = 0x0f; sl@0: /** sl@0: SBC CRC XOR mask, derived from polynomial G(X) = X^8 + X^4 + X^3 + X^2 + 1 sl@0: */ sl@0: const TUint8 KSbcCRCShiftRegisterXorMask = 0x1d; sl@0: sl@0: #ifdef _DEBUG sl@0: sl@0: enum sl@0: { sl@0: ESbcBitstreamPosErr, sl@0: ESbcSampleOverflow sl@0: }; sl@0: sl@0: _LIT(KSBCEncoderPanicCategory, "CSBCEncoder"); sl@0: sl@0: static inline void Panic(TInt aError) sl@0: { sl@0: User::Panic(KSBCEncoderPanicCategory, aError); sl@0: } sl@0: sl@0: #endif sl@0: sl@0: /* ========================= class CBitStreamParser ========================= */ sl@0: sl@0: /** sl@0: class CBitStreamParser constructor sl@0: @internalComponent sl@0: @param aBitStream sl@0: The bit stream buffer to be parsed sl@0: */ sl@0: CBitStreamParser::CBitStreamParser(TDes8& aBitStream) : iBitStream(aBitStream), sl@0: iByteOffset(0), iBitOffset(0) sl@0: { sl@0: iPtr = const_cast(aBitStream.Ptr() ); sl@0: } sl@0: sl@0: /** sl@0: class CBitStreamParser destructor sl@0: @internalComponent sl@0: */ sl@0: CBitStreamParser::~CBitStreamParser() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: class CBitStreamParser second phase constructor sl@0: @internalComponent sl@0: */ sl@0: void CBitStreamParser::ConstructL() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: This function creates a new CBitStreamParser object and push it into CleanupStack. sl@0: @internalComponent sl@0: @param aBitStream sl@0: The bit stream buffer to be parsed sl@0: @return pointer to the new CBitStreamParser object sl@0: @leave if out of memory sl@0: */ sl@0: CBitStreamParser* CBitStreamParser::NewLC(TDes8& aBitStream) sl@0: { sl@0: CBitStreamParser* self = new(ELeave) CBitStreamParser(aBitStream); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: This function reset the internal bit position of CBitStreamParser sl@0: @internalComponent sl@0: */ sl@0: void CBitStreamParser::Reset() sl@0: { sl@0: iPtr = const_cast(iBitStream.Ptr() ); sl@0: iByteOffset = 0; sl@0: iBitOffset = 0; sl@0: } sl@0: sl@0: /** sl@0: This function reads a number of bits from bit stream buffer at current bit position sl@0: and change the bit position to then end of the last bit read. sl@0: @internalComponent sl@0: @param aBitsToRead sl@0: Number of bits to read, at most 8 bits sl@0: @return the bits value in byte sl@0: @panic if bit position is outside of the stream buffer sl@0: */ sl@0: TUint8 CBitStreamParser::ReadBits(TInt aBitsToRead) sl@0: { sl@0: TUint8 result = 0; sl@0: if (aBitsToRead >= 8 - iBitOffset) sl@0: { sl@0: __ASSERT_DEBUG(iByteOffset < static_cast(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) ); sl@0: // extra code to handle exception for URel version sl@0: if (iByteOffset >= static_cast(iBitStream.MaxLength() ) ) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: aBitsToRead -= (8 - iBitOffset); sl@0: result = static_cast( (*iPtr & (0xff >> iBitOffset) ) << aBitsToRead); sl@0: sl@0: iPtr++; sl@0: iByteOffset++; sl@0: iBitOffset = 0; sl@0: } sl@0: if (aBitsToRead > 0) sl@0: { sl@0: __ASSERT_DEBUG(iByteOffset < static_cast(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) ); sl@0: // extra code to handle exception for URel version sl@0: if (iByteOffset >= static_cast(iBitStream.MaxLength() ) ) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: result |= static_cast( (*iPtr & (0xff >> iBitOffset) ) >> (8 - iBitOffset - aBitsToRead) ); sl@0: iBitOffset = static_cast(iBitOffset + aBitsToRead); sl@0: } sl@0: return result; sl@0: } sl@0: sl@0: /** sl@0: This function writes a number of bits to the bit stream buffer at current bit position sl@0: and change the bit position to then end of the last bit written. sl@0: @internalComponent sl@0: @param aBitsToWrite sl@0: Number of bits to write, at most 8 bits sl@0: @param aBitsValue sl@0: The bits value to write in byte sl@0: @panic if bit position is outside of the stream buffer sl@0: */ sl@0: void CBitStreamParser::WriteBits(TInt aBitsToWrite, TUint8 aBitsValue) sl@0: { sl@0: if (aBitsToWrite >= 8 - iBitOffset) sl@0: { sl@0: __ASSERT_DEBUG(iByteOffset < static_cast(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) ); sl@0: // extra code to handle exception for URel version sl@0: if (iByteOffset >= static_cast(iBitStream.MaxLength() ) ) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: aBitsToWrite -= (8 - iBitOffset); sl@0: *iPtr &= ~(0xff >> iBitOffset); // clear bits sl@0: *iPtr |= (aBitsValue >> aBitsToWrite) & (0xff >> iBitOffset); // set bits sl@0: sl@0: iPtr++; sl@0: iByteOffset++; sl@0: iBitOffset = 0; sl@0: } sl@0: if (aBitsToWrite > 0) sl@0: { sl@0: __ASSERT_DEBUG(iByteOffset < static_cast(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) ); sl@0: // extra code to handle exception for URel version sl@0: if (iByteOffset >= static_cast(iBitStream.MaxLength() ) ) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: *iPtr &= (0xff << (8 - iBitOffset) ) | (0xff >> (iBitOffset + aBitsToWrite) ); // clear bits sl@0: *iPtr |= (aBitsValue << (8 - iBitOffset - aBitsToWrite) ) & (0xff >> iBitOffset); // set bits sl@0: iBitOffset = static_cast(iBitOffset + aBitsToWrite); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function reads 8 bits from bit stream buffer at current bit position sl@0: and change the bit position to then end of the last bit read. sl@0: @internalComponent sl@0: @return the bits value in byte sl@0: */ sl@0: TUint8 CBitStreamParser::ReadByte() sl@0: { sl@0: return ReadBits(8); sl@0: } sl@0: sl@0: /** sl@0: This function writes 8 bits to the bit stream buffer at current bit position sl@0: and change the bit position to then end of the last bit written. sl@0: @internalComponent sl@0: @param aByteValue sl@0: The byte value to write sl@0: */ sl@0: void CBitStreamParser::WriteByte(TUint8 aByteValue) sl@0: { sl@0: WriteBits(8, aByteValue); sl@0: } sl@0: sl@0: /** sl@0: This function sets the bit position to a specific position. sl@0: @internalComponent sl@0: @param aByteOffset sl@0: New byte position to set sl@0: @param aBitOffset sl@0: New bit position to set sl@0: @panic if bit position is outside of the stream buffer sl@0: */ sl@0: void CBitStreamParser::SetPosition(TUint aByteOffset, TUint8 aBitOffset) sl@0: { sl@0: while (aBitOffset >= 8) sl@0: { sl@0: aBitOffset -= 8; sl@0: iByteOffset++; sl@0: } sl@0: sl@0: __ASSERT_DEBUG(iByteOffset < static_cast(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) ); sl@0: // extra code to handle exception for URel version sl@0: if (iByteOffset >= static_cast(iBitStream.MaxLength() ) ) sl@0: { sl@0: aBitOffset = 0; sl@0: iByteOffset = iBitStream.MaxLength(); sl@0: } sl@0: sl@0: iPtr = const_cast(iBitStream.Ptr() ) + aByteOffset; sl@0: iByteOffset = aByteOffset; sl@0: iBitOffset = aBitOffset; sl@0: } sl@0: sl@0: /** sl@0: This function gets the bit position. sl@0: @internalComponent sl@0: @param aByteOffset sl@0: Read byte position sl@0: @param aBitOffset sl@0: Read bit position sl@0: */ sl@0: void CBitStreamParser::Position(TUint& aByteOffset, TUint8& aBitOffset) const sl@0: { sl@0: aByteOffset = iByteOffset; sl@0: aBitOffset = iBitOffset; sl@0: } sl@0: sl@0: /* ========================= class CSbcCRCCalculator ========================= */ sl@0: sl@0: /** sl@0: Constructor sl@0: @internalComponent sl@0: */ sl@0: CSbcCRCCalculator::CSbcCRCCalculator() : iShiftRegister(KSbcCRCShiftRegisterInit) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: This function resets the shift register value to intial SBC CRC value sl@0: @internalComponent sl@0: */ sl@0: void CSbcCRCCalculator::Reset() sl@0: { sl@0: iShiftRegister = KSbcCRCShiftRegisterInit; sl@0: } sl@0: sl@0: /** sl@0: This function inputs one bit into the shift register sl@0: @internalComponent sl@0: @param aBit sl@0: The lowest bit contains the bit to input. sl@0: */ sl@0: void CSbcCRCCalculator::InputBit(TUint8 aBit) sl@0: { sl@0: TUint8 inputBit = static_cast( (iShiftRegister >> 7) ^ (aBit & 0x1) ); sl@0: iShiftRegister <<= 1; sl@0: sl@0: if (inputBit) sl@0: { sl@0: iShiftRegister ^= KSbcCRCShiftRegisterXorMask; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function inputs a number of bits into the shift register sl@0: @internalComponent sl@0: @param aBits sl@0: The number of bits to input, at most 8 bits. sl@0: @param aValue sl@0: The input bits value. sl@0: */ sl@0: void CSbcCRCCalculator::InputBits(TUint8 aBits, TUint8 aValue) sl@0: { sl@0: for (TInt bit = aBits - 1; bit >= 0; bit--) sl@0: { sl@0: InputBit(static_cast(aValue >> bit) ); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function inputs 8 bits into the shift register. sl@0: @internalComponent sl@0: @param aValue sl@0: The input byte value. sl@0: */ sl@0: void CSbcCRCCalculator::InputByte(TUint8 aByte) sl@0: { sl@0: InputBit(static_cast(aByte >> 7) ); sl@0: InputBit(static_cast(aByte >> 6) ); sl@0: InputBit(static_cast(aByte >> 5) ); sl@0: InputBit(static_cast(aByte >> 4) ); sl@0: InputBit(static_cast(aByte >> 3) ); sl@0: InputBit(static_cast(aByte >> 2) ); sl@0: InputBit(static_cast(aByte >> 1) ); sl@0: InputBit(aByte); sl@0: } sl@0: sl@0: /** sl@0: This function gets the shift register value. sl@0: @internalComponent sl@0: @return the shift register value. sl@0: */ sl@0: TUint8 CSbcCRCCalculator::ShiftRegister() sl@0: { sl@0: return iShiftRegister; sl@0: } sl@0: sl@0: /* ============================ class CSBCEncoder ============================ */ sl@0: sl@0: /** sl@0: Constructor. sl@0: @internalComponent sl@0: */ sl@0: CSBCEncoder::CSBCEncoder() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Destructor. sl@0: @internalComponent sl@0: */ sl@0: CSBCEncoder::~CSBCEncoder() sl@0: { sl@0: delete iSbcFrameEncoder; sl@0: delete iPcmSampleCach; // this is used to cache any remaining samples less than on frame sl@0: } sl@0: sl@0: /** sl@0: Second phase constructor. sl@0: @internalComponent sl@0: @param aInitParams sl@0: Initial parameters for creating this object, not in use for the moment sl@0: @leave never sl@0: */ sl@0: void CSBCEncoder::ConstructL(TAny* /*aInitParams*/) sl@0: { sl@0: } sl@0: sl@0: /** sl@0: This function resets any existing audio samples from the cach. sl@0: @internalComponent sl@0: @leave never sl@0: */ sl@0: void CSBCEncoder::ResetL() sl@0: { sl@0: if (iPcmSampleCach) sl@0: { sl@0: iPcmSampleCach->Des().Zero(); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function creates a new CSBCEncoder object. sl@0: @internalComponent sl@0: @param aInitParams sl@0: Initial parameters for creating this object, not in use for the moment sl@0: @leave if out of memory sl@0: */ sl@0: CMMFCodec* CSBCEncoder::NewL(TAny* aInitParams) sl@0: { sl@0: CSBCEncoder* self = new(ELeave) CSBCEncoder(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aInitParams); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: This function is used for configuring the CSBCEncoder object. Should be called before encode sl@0: @internalComponent sl@0: @param aConfigType sl@0: Configuration UID, has to be set to KSBCConfigTypeUid sl@0: @param aConfigData sl@0: A package buffer which contains all the settings sl@0: @leave KErrNotSupported if configuration UID does't match or parameters setting is invalid. sl@0: */ sl@0: void CSBCEncoder::ConfigureL(TUid aConfigType, const TDesC8& aConfigData) sl@0: { sl@0: if (aConfigType != KSBCConfigTypeUid) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: const TSBCFrameParameters& param = sl@0: static_cast&>(aConfigData)(); sl@0: sl@0: if (param.Validate() != 0) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: iParameters = param; sl@0: sl@0: if (iPcmSampleCach) sl@0: { sl@0: delete iPcmSampleCach; sl@0: iPcmSampleCach = NULL; sl@0: } sl@0: sl@0: if (iSbcFrameEncoder) sl@0: { sl@0: // must call this whenever ConfigureL() is called to make sure CSBCFrameEncoder sl@0: // uses the new configuration, as we can change the configuration without creating sl@0: // a new CSBCFrameEncoder object sl@0: iSbcFrameEncoder->Configure(iParameters); sl@0: } sl@0: sl@0: iSbcFrameLength = iParameters.CalcFrameLength(); sl@0: iPcmFrameSize = sizeof(TInt16) * param.BlockLength() * param.Subbands() * param.Channels(); sl@0: } sl@0: sl@0: /** sl@0: This function encodes sbc audio stream with PCM16 audio source samples, and write processed sl@0: result to destination buffer. It also caches any less than one frame remaining audio samples. sl@0: @internalComponent sl@0: @param aSrc sl@0: Source buffer contains the PCM16 audio source samples sl@0: @param aDst sl@0: Destination buffer to contain the encoded sbc audio stream sl@0: @return processed result sl@0: @leave sl@0: KErrAbort if configuration is invalid, sl@0: KErrArgument if destination buffer size is smaller than one frame length, sl@0: KErrCorrupt if output bytes is not the same as frame length or sl@0: if we still have enough src and dst but the process stoped, sl@0: Or other errors e.g. out of memory error. sl@0: */ sl@0: TCodecProcessResult CSBCEncoder::ProcessL(const CMMFBuffer& aSrc, CMMFBuffer& aDst) sl@0: { sl@0: // check if ConfigureL gets called already sl@0: if (iParameters.Validate() != 0) sl@0: { sl@0: User::Leave(KErrAbort); sl@0: } sl@0: sl@0: // check if dst big enough to hold at least one frame sl@0: CMMFDataBuffer* dst = static_cast(&aDst); sl@0: const TUint dstMaxLen = dst->Data().MaxLength(); sl@0: sl@0: if (dstMaxLen < iSbcFrameLength) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: // process data sl@0: const CMMFDataBuffer* src = static_cast(&aSrc); sl@0: const TUint srcLen = src->Data().Length(); sl@0: TUint srcPos = src->Position(); sl@0: TUint dstPos = dst->Position(); sl@0: sl@0: const TUint8* srcPtr = src->Data().Ptr(); sl@0: TUint8* dstPtr = const_cast(dst->Data().Ptr() ); sl@0: TUint cachedSize = CachedSampleSize(); sl@0: sl@0: while (cachedSize + srcLen - srcPos >= iPcmFrameSize && dstMaxLen - dstPos >= iSbcFrameLength) sl@0: { sl@0: TPtrC8 srcDes(srcPtr + srcPos, iPcmFrameSize); sl@0: TPtr8 dstDes(dstPtr + dstPos, iSbcFrameLength); sl@0: sl@0: srcPos += EncodeFrameL(srcDes, dstDes); sl@0: dstPos += iSbcFrameLength; sl@0: cachedSize = 0; sl@0: } sl@0: sl@0: // check result sl@0: TCodecProcessResult result; sl@0: result.iStatus = TCodecProcessResult::EProcessComplete; sl@0: sl@0: if (dstMaxLen - dstPos >= iSbcFrameLength) // still enough dst buffer sl@0: { sl@0: result.iStatus = TCodecProcessResult::EDstNotFilled; sl@0: } sl@0: sl@0: // cach remaining src sl@0: if (CachedSampleSize() + srcLen - srcPos >= iPcmFrameSize) // still enough src sl@0: { sl@0: if (result.iStatus == TCodecProcessResult::EDstNotFilled) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: else sl@0: { sl@0: result.iStatus = TCodecProcessResult::EProcessIncomplete; sl@0: } sl@0: } sl@0: else if (srcLen - srcPos > 1) // remaining src less than one frame, cach it sl@0: { sl@0: srcPos += CachePcmSamplesL(*src, srcPos); sl@0: } sl@0: sl@0: // set new position for dst sl@0: dst->Data().SetLength(dstPos); sl@0: sl@0: // return result sl@0: result.iSrcBytesProcessed = srcPos - src->Position(); sl@0: result.iDstBytesAdded = dstPos - dst->Position(); sl@0: return result; sl@0: } sl@0: sl@0: /** sl@0: This function encodes one SBC frame with PCM16 audio source samples, and write processed sl@0: result to destination buffer. sl@0: @internalComponent sl@0: @param aSrc sl@0: Source buffer contains the PCM16 audio source samples sl@0: @param aDst sl@0: Destination buffer to contain the encoded sbc audio stream sl@0: @return the number of bytes the source has been processed sl@0: @leave if out of memory. sl@0: */ sl@0: TUint CSBCEncoder::EncodeFrameL(const TDesC8& aSrc, TDes8& aDst) sl@0: { sl@0: if (!iSbcFrameEncoder) sl@0: { sl@0: iSbcFrameEncoder = CSBCFrameEncoder::NewL(); sl@0: iSbcFrameEncoder->Configure(iParameters); sl@0: } sl@0: sl@0: if (CachedSampleSize() > 0) sl@0: { // encode one frame with cached samples and src sl@0: TUint appendBytes = iPcmFrameSize - CachedSampleSize(); sl@0: // append src to cach to make up one frame sl@0: iPcmSampleCach->Des().Append(aSrc.Ptr(), appendBytes); sl@0: // encode cach sl@0: iSbcFrameEncoder->EncodeFrameL(*iPcmSampleCach, aDst); sl@0: // empty cach sl@0: iPcmSampleCach->Des().Zero(); sl@0: // return bytes src processed sl@0: return appendBytes; sl@0: } sl@0: else sl@0: { sl@0: // encode one frame with src only sl@0: iSbcFrameEncoder->EncodeFrameL(aSrc, aDst); sl@0: // return bytes src processed sl@0: return iPcmFrameSize; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function caches any less than one frame remaining audio samples. sl@0: @internalComponent sl@0: @param aSrc sl@0: Source buffer contains the PCM16 audio source samples. sl@0: @param aSrcPos sl@0: Position from where the samples are cached. sl@0: @return the number of bytes the source has been cached sl@0: @leave if out of memory. sl@0: */ sl@0: TUint CSBCEncoder::CachePcmSamplesL(const CMMFDataBuffer& aSrc, TUint aSrcPos) sl@0: { sl@0: if (!iPcmSampleCach) sl@0: { sl@0: iPcmSampleCach = HBufC8::NewL(iPcmFrameSize); sl@0: } sl@0: sl@0: const TUint8* pSrc = aSrc.Data().Ptr() + aSrcPos; sl@0: const TUint cachSize = (aSrc.Data().Length() - aSrcPos) & 0xfffe; // take even number sl@0: sl@0: iPcmSampleCach->Des().Append(pSrc, cachSize); sl@0: sl@0: return cachSize; sl@0: } sl@0: sl@0: /** sl@0: This function gets the size of the cach. sl@0: @internalComponent sl@0: @return the cached samples size sl@0: */ sl@0: TUint CSBCEncoder::CachedSampleSize() sl@0: { sl@0: if (!iPcmSampleCach) sl@0: { sl@0: return 0; sl@0: } sl@0: return iPcmSampleCach->Des().Size(); sl@0: } sl@0: sl@0: /* ========================== class CSBCFrameEncoder ========================== */ sl@0: sl@0: /** sl@0: Constructor. sl@0: @internalComponent sl@0: */ sl@0: CSBCFrameEncoder::CSBCFrameEncoder() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Destructor. sl@0: @internalComponent sl@0: */ sl@0: CSBCFrameEncoder::~CSBCFrameEncoder() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Second phase constructor. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::ConstructL() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: This function creates a CSBCFrameEncoder object. sl@0: @internalComponent sl@0: @return pointer of the CSBCFrameEncoder object. sl@0: */ sl@0: CSBCFrameEncoder* CSBCFrameEncoder::NewL() sl@0: { sl@0: CSBCFrameEncoder* self = new(ELeave) CSBCFrameEncoder(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: /** sl@0: This function resets the analysis filter bank, this should be called everytime sl@0: when encoding a new sbc audio stream. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::Reset() sl@0: { sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: TInt16* analysisSamples = iAnalysisSamples[channel]; sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: *analysisSamples++ = 0; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function sets the configuration for SBC Frame Encoder and resets the analysis filter bank. sl@0: @internalComponent sl@0: @param aParameters sl@0: This contains all the parameters to set sl@0: */ sl@0: void CSBCFrameEncoder::Configure(const TSBCFrameParameters& aParameters) sl@0: { sl@0: iParameters = aParameters; sl@0: // has to call this whenever the configuration changed, this resets the Analyse Filter Bank sl@0: Reset(); sl@0: } sl@0: sl@0: /** sl@0: This function encodes one SBC frame with PCM16 source samples and output it to destination buffer. sl@0: @internalComponent sl@0: @param aSrc sl@0: Source buffer contains the source samples sl@0: @param aFrame sl@0: Destination buffer to contain the processed sbc audio stream sl@0: @leave if out of memory sl@0: */ sl@0: void CSBCFrameEncoder::EncodeFrameL(const TDesC8& aSrc, TDes8& aFrame) sl@0: { sl@0: // encode frame sl@0: Analyse(aSrc); sl@0: CalcScaleFactors(); sl@0: JoinSubbands(); sl@0: CalcBitAllocation(); sl@0: Quantize(); sl@0: sl@0: // output frame sl@0: WriteFrameL(aFrame); sl@0: } sl@0: sl@0: /** sl@0: This function does the analysis filtering, the analysed samples are used to encode sbc subbands. sl@0: @internalComponent sl@0: @param aSrc sl@0: Source buffer contains the source samples sl@0: */ sl@0: void CSBCFrameEncoder::Analyse(const TDesC8& aSrc) sl@0: { sl@0: const TUint8 channelMode = iParameters.ChannelMode(); sl@0: const TInt16* inputSamples = reinterpret_cast(aSrc.Ptr() ); sl@0: sl@0: if (channelMode == TSBCFrameParameters::EMono) sl@0: { sl@0: AnalyseMono(inputSamples); sl@0: } sl@0: else // two-channel modes sl@0: { sl@0: // two channel samples are interleavedly stored in the following order sl@0: // one left sample, one right sample, ... sl@0: AnalyseOneChannel(inputSamples, 0); sl@0: AnalyseOneChannel(inputSamples + 1, 1); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function analyses audio samples for Mono and Dual Channel modes. sl@0: @internalComponent sl@0: @param aInputSamples sl@0: Array of source samples sl@0: */ sl@0: void CSBCFrameEncoder::AnalyseMono(const TInt16 aInputSamples[]) sl@0: { sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: if (numSubbands == 4) sl@0: { sl@0: Analyse4Subbands(aInputSamples, block, 0); sl@0: } sl@0: else sl@0: { sl@0: Analyse8Subbands(aInputSamples, block, 0); sl@0: } sl@0: aInputSamples += numSubbands; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function analyses audio samples for Stereo and Joint Stereo modes. sl@0: @internalComponent sl@0: @param aInputSamples sl@0: Array of source samples sl@0: @param aChannel sl@0: The channel number to be analysed sl@0: */ sl@0: void CSBCFrameEncoder::AnalyseOneChannel(const TInt16 aInputSamples[], TUint8 aChannel) sl@0: { sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: sl@0: TInt16 inputSamples[KSbcMaxSubbands]; sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: inputSamples[subband] = *aInputSamples; sl@0: aInputSamples += 2; // 1 left sample, 1 right sample, ... sl@0: } sl@0: sl@0: if (numSubbands == 4) sl@0: { sl@0: Analyse4Subbands(inputSamples, block, aChannel); sl@0: } sl@0: else sl@0: { sl@0: Analyse8Subbands(inputSamples, block, aChannel); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: This function analyses 4 subbands for sbc frame with 4 subbands. sl@0: @internalComponent sl@0: @param aInputSamples sl@0: Array of source samples sl@0: @param aBlock sl@0: The block number to be analysed sl@0: @param aChannel sl@0: The channel number to be analysed sl@0: */ sl@0: void CSBCFrameEncoder::Analyse4Subbands(const TInt16 aInputSamples[], TUint8 aBlock, TUint8 aChannel) sl@0: { sl@0: // for easier understanding, this code is a copy from the A2DP spec, sl@0: // all the naming are kept. sl@0: TInt i = 0; sl@0: TInt k = 0; sl@0: TInt16* X = iAnalysisSamples[aChannel]; // 40 analyse samples sl@0: sl@0: for (i = 39; i >= 4; i--) sl@0: { sl@0: X[i] = X[i - 4]; sl@0: } sl@0: for (i = 3; i >= 0; i--) sl@0: { sl@0: X[i] = *aInputSamples++; sl@0: } sl@0: sl@0: TInt64 Y[8]; // partial calculation, see Figure 12.5 in A2DP spec for detail sl@0: for (i = 0; i < 8; i++) sl@0: { sl@0: TInt64 sum = 0; sl@0: for (k = 0; k <= 4; k++) sl@0: { sl@0: // for some strange reason, RVCT is not happy about converting sl@0: // TInt16 to TInt64 in the equation directly. sl@0: const TInt64 sample = X[i + (k << 3)]; sl@0: sum += KSBCProto4[i + (k << 3)] * sample; sl@0: } sl@0: Y[i] = sum >> (KSBCProtoBitsShift - 10); sl@0: } sl@0: sl@0: TInt32* outputSamples = iOutputSamples[aBlock][aChannel]; sl@0: for (i = 0; i < 4; i++) sl@0: { sl@0: const TInt32* M = KSBCAnalysisMatrix4[i]; sl@0: TInt64 sum = 0; sl@0: for (k = 0; k < 8; k++) sl@0: { sl@0: sum += M[k] * Y[k]; sl@0: } sl@0: sum >>= (KSBCAnalysisMatrixBitsShift + 9); sl@0: sum = (sum >> 1) + (sum & 0x1); sl@0: outputSamples[i] = static_cast(sum); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function analyses 8 subbands for sbc frame with 8 subbands. sl@0: @internalComponent sl@0: @param aInputSamples sl@0: Array of source samples sl@0: @param aBlock sl@0: The block number to be analysed sl@0: @param aChannel sl@0: The channel number to be analysed sl@0: */ sl@0: void CSBCFrameEncoder::Analyse8Subbands(const TInt16 aInputSamples[], TUint8 aBlock, TUint8 aChannel) sl@0: { sl@0: // for easier understanding, this code is a copy from the A2DP spec, sl@0: // all the naming are kept. sl@0: TInt i = 0; sl@0: TInt k = 0; sl@0: TInt16* X = iAnalysisSamples[aChannel]; // 80 analysis samples sl@0: sl@0: for (i = 79; i >= 8; i--) sl@0: { sl@0: X[i] = X[i - 8]; sl@0: } sl@0: for (i = 7; i >= 0; i--) sl@0: { sl@0: X[i] = *aInputSamples++; sl@0: } sl@0: sl@0: TInt64 Y[16]; // partial calculation, see Figure 12.5 in A2DP spec for detail sl@0: for (i = 0; i < 16; i++) sl@0: { sl@0: TInt64 sum = 0; sl@0: for (k = 0; k <= 4; k++) sl@0: { sl@0: // for some strange reason, RVCT is not happy about converting sl@0: // TInt16 to TInt64 in the equation directly. sl@0: const TInt64 sample = X[i + (k << 4)]; sl@0: sum += KSBCProto8[i + (k << 4)] * sample; sl@0: } sl@0: Y[i] = sum >> (KSBCProtoBitsShift - 10); sl@0: } sl@0: sl@0: TInt32* outputSamples = iOutputSamples[aBlock][aChannel]; sl@0: for (i = 0; i < 8; i++) sl@0: { sl@0: const TInt32* M = KSBCAnalysisMatrix8[i]; sl@0: TInt64 sum = 0; sl@0: for (k = 0; k < 16; k++) sl@0: { sl@0: sum += M[k] * Y[k]; sl@0: } sl@0: sum >>= (KSBCAnalysisMatrixBitsShift + 9); sl@0: sum = (sum >> 1) + (sum & 0x1); sl@0: outputSamples[i] = static_cast(sum); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function calculates the scale factor for one sample. sl@0: @internalComponent sl@0: @param aSample sl@0: A sample sl@0: @return scale factor of thie sample sl@0: */ sl@0: static inline TUint8 ScaleFactor(TInt32 aSample) sl@0: { sl@0: if (aSample < 0) sl@0: aSample = -aSample; sl@0: sl@0: // top bit of the sample is sign bit, ignore it sl@0: // start from the second high bit sl@0: TUint32 mask = 0x40000000; sl@0: for (TInt8 bit = 30; bit > 0; bit--) sl@0: { sl@0: if (aSample & mask) sl@0: { sl@0: return bit; sl@0: } sl@0: mask >>= 1; sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: /** sl@0: This function calculates the scale factors for all samples in one sbc frame. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::CalcScaleFactors() sl@0: { sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: TInt32 maxSubbandValues[KSbcMaxChannels][KSbcMaxSubbands]; sl@0: sl@0: // find all maximum values of each subband sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: const TInt32* samples = iOutputSamples[block][channel]; sl@0: TInt32* maxValues = maxSubbandValues[channel]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (block == 0 || Abs(*samples) > *maxValues) sl@0: { sl@0: *maxValues = Abs(*samples); sl@0: } sl@0: samples++; sl@0: maxValues++; sl@0: } sl@0: } sl@0: } sl@0: sl@0: // calculate scale factors for all subband sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: const TInt32* maxValues = maxSubbandValues[channel]; sl@0: TUint8* scale = iScaleFactors[channel]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: *scale++ = ScaleFactor(*maxValues++); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function joins two subband samples for Joint Stereo mode. sl@0: @internalComponent sl@0: @param aLeftSample sl@0: Left channel subband sample sl@0: @param aRightSample sl@0: Right channel subband sample sl@0: */ sl@0: static inline void JoinTwoSamples(TInt32& aLeftSample, TInt32& aRightSample) sl@0: { sl@0: aLeftSample = (aLeftSample + aRightSample) >> 1; // L1 = (L0 + R0) / 2 sl@0: aRightSample = aLeftSample - aRightSample; // R1 = L1 - R0 = (L0 - R0) / 2 sl@0: } sl@0: sl@0: /** sl@0: This function sets the join flats for all subbands for one frame, sl@0: and joins those subbands if needed for this frame. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::JoinSubbands() sl@0: { sl@0: if (iParameters.ChannelMode() != TSBCFrameParameters::EJointStereo) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: TInt32 maxJoinValues[2][KSbcMaxSubbands - 1]; // 2 channels sl@0: sl@0: // find maximum join subband values sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: const TInt32* leftSamples = iOutputSamples[block][0]; sl@0: const TInt32* rightSamples = iOutputSamples[block][1]; sl@0: sl@0: TInt32* maxLeftJoin = maxJoinValues[0]; sl@0: TInt32* maxRightJoin = maxJoinValues[1]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands - 1; subband++) sl@0: { sl@0: TInt32 leftJoin = *leftSamples++; sl@0: TInt32 rightJoin = *rightSamples++; sl@0: sl@0: JoinTwoSamples(leftJoin, rightJoin); sl@0: sl@0: if (block == 0 || Abs(leftJoin) > *maxLeftJoin) sl@0: { sl@0: *maxLeftJoin = Abs(leftJoin); sl@0: } sl@0: if (block == 0 || Abs(rightJoin) > *maxRightJoin) sl@0: { sl@0: *maxRightJoin = Abs(rightJoin); sl@0: } sl@0: maxLeftJoin++; sl@0: maxRightJoin++; sl@0: } sl@0: } sl@0: sl@0: // calculate scale factors for all join subbands sl@0: const TInt32* maxLeftJoin = maxJoinValues[0]; sl@0: const TInt32* maxRightJoin = maxJoinValues[1]; sl@0: sl@0: TUint8* leftScale = iScaleFactors[0]; sl@0: TUint8* rightScale = iScaleFactors[1]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands - 1; subband++) sl@0: { sl@0: const TUint8 leftJoinScale = ScaleFactor(*maxLeftJoin++); sl@0: const TUint8 rightJoinScale = ScaleFactor(*maxRightJoin++); sl@0: sl@0: iJoin[subband] = 0; sl@0: if (leftJoinScale + rightJoinScale < *leftScale + *rightScale) sl@0: { sl@0: iJoin[subband] = 1; sl@0: *leftScale = leftJoinScale; sl@0: *rightScale = rightJoinScale; sl@0: } sl@0: leftScale++; sl@0: rightScale++; sl@0: } sl@0: iJoin[numSubbands - 1] = 0; // join[subband - 1] is always 0 sl@0: sl@0: // now do the joining job sl@0: DoJoinSubbands(); sl@0: } sl@0: sl@0: /** sl@0: This function joins all subbands if needed for this frame. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::DoJoinSubbands() sl@0: { sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: TInt32* leftSamples = iOutputSamples[block][0]; sl@0: TInt32* rightSamples = iOutputSamples[block][1]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands - 1; subband++) sl@0: { sl@0: if (iJoin[subband]) sl@0: { sl@0: JoinTwoSamples(*leftSamples, *rightSamples); sl@0: } sl@0: leftSamples++; sl@0: rightSamples++; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function quantizes one sample according to: sl@0: sample = (sample / scale + 1.0) * level / 2.0 sl@0: scale = 2 ^ (scale_factor + 1) sl@0: level = (2 ^ bits) - 1 sl@0: @internalComponent sl@0: @param aSample sl@0: A sample to be quantized. sl@0: @param aScaleFactor sl@0: The scale factor value. sl@0: @param aBits sl@0: The number of bits for this sample sl@0: @panic if quantized sample overflow sl@0: */ sl@0: static void QuantizeOneSample(TInt32& aSample, TUint8 aScaleFactor, TUint8 aBits) sl@0: { sl@0: // output = sample + scale sl@0: TInt64 temp = (TInt)aSample + (0x1 << (aScaleFactor + 1) ); sl@0: // output = (sample + scale) * level / scale sl@0: temp = ( (temp << aBits) - temp) >> (aScaleFactor + 2); sl@0: sl@0: aSample = static_cast(temp); sl@0: sl@0: // check bounce sl@0: __ASSERT_DEBUG(aSample >= 0 && aSample <= (TInt32)0xffff, Panic(ESbcSampleOverflow) ); sl@0: // extra code to handle exception for URel version sl@0: if (aSample < 0) sl@0: { sl@0: aSample = 0; sl@0: } sl@0: if (aSample > (TInt32)0xffff) sl@0: { sl@0: aSample = (TInt32)0xffff; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function quantizes all samples in one sbc frame. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::Quantize() sl@0: { sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: const TUint8* bits = iBits[channel]; sl@0: const TUint8* scale = iScaleFactors[channel]; sl@0: TInt32* samples = iOutputSamples[block][channel]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: QuantizeOneSample(*samples++, *scale++, *bits++); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function calculates bit allocation for all samples in one sbc frame using scale factors. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::CalcBitAllocation() sl@0: { sl@0: switch (iParameters.ChannelMode()) sl@0: { sl@0: case TSBCFrameParameters::EMono: sl@0: case TSBCFrameParameters::EDualChannel: sl@0: CalcBitAllocIndependent(); sl@0: break; sl@0: sl@0: case TSBCFrameParameters::EStereo: sl@0: case TSBCFrameParameters::EJointStereo: sl@0: CalcBitAllocCombined(); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function calculates bit allocation for one channel for Mono and Dual Channel. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::CalcBitAllocIndependent() sl@0: { sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: TInt8 bitneed[KSbcMaxSubbands]; sl@0: CalcBitneedIndependent(bitneed, iScaleFactors[channel]); sl@0: DistributeBitsIndependent(bitneed, iBits[channel]); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function calculates bitneed for one channel for Mono and Dual Channel. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed to hold the result sl@0: @param aScaleFactors sl@0: The scale factors used for this calculation sl@0: */ sl@0: void CSBCFrameEncoder::CalcBitneedIndependent(TInt8 aBitneed[], const TUint8 aScaleFactors[]) sl@0: { sl@0: // see A2DP spec for reference sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: if (iParameters.AllocationMethod() == TSBCFrameParameters::ESNR) sl@0: { sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: *aBitneed++ = *aScaleFactors++; sl@0: } sl@0: } sl@0: else // Loudness sl@0: { sl@0: const TInt8* offset = NULL; sl@0: if (numSubbands == 4) sl@0: { sl@0: offset = KSBCOffset4[iParameters.SamplingFrequencyEnum()]; sl@0: } sl@0: else sl@0: { sl@0: offset = KSBCOffset8[iParameters.SamplingFrequencyEnum()]; sl@0: } sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*aScaleFactors == 0) sl@0: { sl@0: *aBitneed = -5; sl@0: } sl@0: else if ( (*aBitneed = static_cast(*aScaleFactors - *offset) ) > 0) sl@0: { sl@0: (*aBitneed) >>= 1; sl@0: } sl@0: aScaleFactors++; sl@0: aBitneed++; sl@0: offset++; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function gets the maximum bitneed in one channel for Mono and Dual Channel. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed. sl@0: */ sl@0: TInt8 CSBCFrameEncoder::MaxBitneedIndependent(const TInt8 aBitneed[]) sl@0: { sl@0: // see A2DP spec for reference sl@0: TInt8 maxBitneed = 0; sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*aBitneed > maxBitneed) sl@0: { sl@0: maxBitneed = *aBitneed; sl@0: } sl@0: aBitneed++; sl@0: } sl@0: sl@0: return maxBitneed; sl@0: } sl@0: sl@0: /** sl@0: This function calculates how many bitslices fit into the bitpool for one channel sl@0: for Mono and Dual Channel. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed. sl@0: @param aBitCount sl@0: The bit count, counts how many bits used sl@0: @return the number of bitslices sl@0: */ sl@0: TInt8 CSBCFrameEncoder::CalcBitSlicesIndependent(const TInt8 aBitneed[], TInt& aBitCount) sl@0: { sl@0: // see A2DP spec for reference sl@0: aBitCount = 0; sl@0: TInt8 sliceCount = 0; sl@0: TInt8 bitSlices = static_cast(MaxBitneedIndependent(aBitneed) + 1); sl@0: sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: const TUint8 bitpool = iParameters.Bitpool(); sl@0: sl@0: do { sl@0: bitSlices--; sl@0: aBitCount += sliceCount; sl@0: sliceCount = 0; sl@0: sl@0: const TInt8* bitneed = aBitneed; sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*bitneed > bitSlices + 1 && *bitneed < bitSlices + 16) sl@0: { sl@0: sliceCount++; sl@0: } sl@0: else if (*bitneed == bitSlices + 1) sl@0: { sl@0: sliceCount += 2; sl@0: } sl@0: bitneed++; sl@0: } sl@0: } while (aBitCount + sliceCount < bitpool); sl@0: sl@0: if (aBitCount + sliceCount == bitpool) sl@0: { sl@0: aBitCount += sliceCount; sl@0: bitSlices--; sl@0: } sl@0: sl@0: return bitSlices; sl@0: } sl@0: sl@0: /** sl@0: This function distributes number of bits to each subband for all samples sl@0: for Mono and Dual Channel. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed. sl@0: @param aBits sl@0: Bits allocated for each subbands sl@0: */ sl@0: void CSBCFrameEncoder::DistributeBitsIndependent(const TInt8 aBitneed[], TUint8 aBits[]) sl@0: { sl@0: // see A2DP spec for reference sl@0: TInt bitCount = 0; sl@0: TInt8 bitSlices = CalcBitSlicesIndependent(aBitneed, bitCount); sl@0: sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: // distribute bits until the last bitslice is reached sl@0: TUint8 subband = 0; sl@0: for (; subband < numSubbands; subband++) sl@0: { sl@0: if (aBitneed[subband] < bitSlices + 2) sl@0: { sl@0: aBits[subband] = 0; sl@0: } sl@0: else sl@0: { sl@0: aBits[subband] = static_cast(Min(aBitneed[subband] - bitSlices, 16) ); sl@0: } sl@0: } sl@0: sl@0: // distribute the remaining bits sl@0: const TUint8 bitpool = iParameters.Bitpool(); sl@0: sl@0: subband = 0; sl@0: while (bitCount < bitpool && subband < numSubbands) sl@0: { sl@0: if (aBits[subband] >= 2 && aBits[subband] < 16) sl@0: { sl@0: aBits[subband]++; sl@0: bitCount++; sl@0: } sl@0: else if (aBitneed[subband] == bitSlices + 1 && bitpool > bitCount + 1) sl@0: { sl@0: aBits[subband] += 2; // ? bits[ch][sb] = 2 in A2DP spec, a bug in the spec? sl@0: bitCount += 2; sl@0: } sl@0: subband++; sl@0: } sl@0: sl@0: subband = 0; sl@0: while (bitCount < bitpool && subband < numSubbands) sl@0: { sl@0: if (aBits[subband] < 16) sl@0: { sl@0: aBits[subband]++; sl@0: bitCount++; sl@0: } sl@0: subband++; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function calculates bit allocation for both channels for Stereo and Joint Stereo. sl@0: @internalComponent sl@0: */ sl@0: void CSBCFrameEncoder::CalcBitAllocCombined() sl@0: { sl@0: TInt8 bitneed[2][KSbcMaxSubbands]; sl@0: sl@0: CalcBitneedCombined(bitneed); sl@0: DistributeBitsCombined(bitneed); sl@0: } sl@0: sl@0: /** sl@0: This function calculates bitneed for both channels for Stereo and Joint Stereo. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed to hold the result sl@0: */ sl@0: void CSBCFrameEncoder::CalcBitneedCombined(TInt8 aBitneed[][KSbcMaxSubbands]) sl@0: { sl@0: // see A2DP spec for reference sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: if (iParameters.AllocationMethod() == TSBCFrameParameters::ESNR) sl@0: { sl@0: for (TInt8 channel = 0; channel < 2; channel++) sl@0: { sl@0: const TUint8* scaleFactor = iScaleFactors[channel]; sl@0: TInt8* bitneed = aBitneed[channel]; sl@0: for (TInt8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: *bitneed++ = *scaleFactor++; sl@0: } sl@0: } sl@0: } sl@0: else // Loudness sl@0: { sl@0: const TInt8* offset = NULL; sl@0: if (numSubbands == 4) sl@0: { sl@0: offset = KSBCOffset4[iParameters.SamplingFrequencyEnum()]; sl@0: } sl@0: else sl@0: { sl@0: offset = KSBCOffset8[iParameters.SamplingFrequencyEnum()]; sl@0: } sl@0: sl@0: for (TInt8 channel = 0; channel < 2; channel++) sl@0: { sl@0: const TUint8* scaleFactor = iScaleFactors[channel]; sl@0: TInt8* bitneed = aBitneed[channel]; sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*scaleFactor == 0) sl@0: { sl@0: *bitneed = -5; sl@0: } sl@0: else if ( (*bitneed = static_cast(*scaleFactor - offset[subband]) ) > 0) sl@0: { sl@0: (*bitneed) >>= 1; sl@0: } sl@0: scaleFactor++; sl@0: bitneed++; sl@0: } // for subband sl@0: } // for channel sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function gets the maximum bitneed of both channels subbands for Stereo and Joint Stereo. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed. sl@0: */ sl@0: TInt8 CSBCFrameEncoder::MaxBitneedCombined(const TInt8 aBitneed[][KSbcMaxSubbands]) sl@0: { sl@0: // see A2DP spec for reference sl@0: TInt8 maxBitneed = 0; sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TInt8 channel = 0; channel < 2; channel++) sl@0: { sl@0: const TInt8* bitneed = aBitneed[channel]; sl@0: for (TInt8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*bitneed > maxBitneed) sl@0: { sl@0: maxBitneed = *bitneed; sl@0: } sl@0: bitneed++; sl@0: } sl@0: } sl@0: return maxBitneed; sl@0: } sl@0: sl@0: /** sl@0: This function calculates how many bitslices fit into the bitpool for both channels sl@0: for Stereo and Joint Stereo. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed. sl@0: @param aBitCount sl@0: The bit count, counts how many bits used sl@0: @return the number of bitslices sl@0: */ sl@0: TInt8 CSBCFrameEncoder::CalcBitSlicesCombined(const TInt8 aBitneed[][KSbcMaxSubbands], TInt& aBitCount) sl@0: { sl@0: // see A2DP spec for reference sl@0: aBitCount = 0; sl@0: TInt8 sliceCount = 0; sl@0: TInt8 bitSlices = static_cast(MaxBitneedCombined(aBitneed) + 1); sl@0: sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: const TUint8 bitpool = iParameters.Bitpool(); sl@0: sl@0: do { sl@0: bitSlices--; sl@0: aBitCount += sliceCount; sl@0: sliceCount = 0; sl@0: sl@0: for (TInt8 channel = 0; channel < 2; channel++) sl@0: { sl@0: const TInt8* bitneed = aBitneed[channel]; sl@0: for (TInt8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*bitneed > bitSlices + 1 && *bitneed < bitSlices + 16) sl@0: { sl@0: sliceCount++; sl@0: } sl@0: else if (*bitneed == bitSlices + 1) sl@0: { sl@0: sliceCount += 2; sl@0: } sl@0: bitneed++; sl@0: } sl@0: } sl@0: } while (aBitCount + sliceCount < bitpool); sl@0: sl@0: if (aBitCount + sliceCount == bitpool) sl@0: { sl@0: aBitCount += sliceCount; sl@0: bitSlices--; sl@0: } sl@0: sl@0: return bitSlices; sl@0: } sl@0: sl@0: /** sl@0: This function distributes number of bits to each subband for all samples sl@0: for Stereo and Joint Stereo. sl@0: @internalComponent sl@0: @param aBitneed sl@0: Array of bitneed. sl@0: */ sl@0: void CSBCFrameEncoder::DistributeBitsCombined(const TInt8 aBitneed[][KSbcMaxSubbands]) sl@0: { sl@0: // see A2DP spec for reference sl@0: TInt bitCount = 0; sl@0: TInt bitSlices = CalcBitSlicesCombined(aBitneed, bitCount); sl@0: sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: const TUint8 bitpool = iParameters.Bitpool(); sl@0: sl@0: // distribute bits until the last bitslice is reached sl@0: TInt8 channel = 0; sl@0: TInt8 subband = 0; sl@0: for (; channel < 2; channel++) sl@0: { sl@0: const TInt8* bitneed = aBitneed[channel]; sl@0: TUint8* bits = iBits[channel]; sl@0: for (subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*bitneed < bitSlices + 2) sl@0: { sl@0: *bits = 0; sl@0: } sl@0: else sl@0: { sl@0: *bits = static_cast(Min(*bitneed - bitSlices, 16) ); sl@0: } sl@0: bitneed++; sl@0: bits++; sl@0: } sl@0: } sl@0: sl@0: // distribute the remaining bits sl@0: channel = 0; sl@0: subband = 0; sl@0: while (bitCount < bitpool && subband < numSubbands) sl@0: { sl@0: TUint8& bits = iBits[channel][subband]; sl@0: if (bits >= 2 && bits < 16) sl@0: { sl@0: bits++; sl@0: bitCount++; sl@0: } sl@0: else if (aBitneed[channel][subband] == bitSlices + 1 && bitpool > bitCount + 1) sl@0: { sl@0: bits += 2; // ? bits[ch][sb] = 2 in A2DP spec, a bug in the spec? sl@0: bitCount += 2; sl@0: } sl@0: sl@0: if (channel == 1) sl@0: { sl@0: channel = 0; sl@0: subband++; sl@0: } sl@0: else sl@0: { sl@0: channel = 1; sl@0: } sl@0: } sl@0: sl@0: channel = 0; sl@0: subband = 0; sl@0: while (bitCount < bitpool && subband < numSubbands) sl@0: { sl@0: TUint8& bits = iBits[channel][subband]; sl@0: if (bits < 16) sl@0: { sl@0: bits++; sl@0: bitCount++; sl@0: } sl@0: sl@0: if (channel == 1) sl@0: { sl@0: channel = 0 ; sl@0: subband++; sl@0: } sl@0: else sl@0: { sl@0: channel = 1; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function calculates the CRC code for sbc frame. sl@0: @internalComponent sl@0: @return sbc CRC value sl@0: */ sl@0: TUint8 CSBCFrameEncoder::CalcCRC() sl@0: { sl@0: CSbcCRCCalculator crc; sl@0: sl@0: crc.InputByte(iParameters.Parameters() ); // 5 parameters sl@0: crc.InputByte(iParameters.Bitpool() ); // bitpool sl@0: sl@0: // join[] & RFA bits sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: if (iParameters.ChannelMode() == TSBCFrameParameters::EJointStereo) sl@0: { sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: crc.InputBit(iJoin[subband]); sl@0: } sl@0: } sl@0: sl@0: // scale factors sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: const TUint8* scaleFactors = iScaleFactors[channel]; sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: crc.InputBits(4, *scaleFactors++); sl@0: } sl@0: } sl@0: sl@0: return crc.ShiftRegister(); sl@0: } sl@0: sl@0: /** sl@0: This function outputs the encoded sbc frame into the destination buffer. sl@0: @internalComponent sl@0: @param aFrame sl@0: The destination buffer sl@0: @leave if out of memory sl@0: */ sl@0: void CSBCFrameEncoder::WriteFrameL(TDes8& aFrame) sl@0: { sl@0: CBitStreamParser* parser = CBitStreamParser::NewLC(aFrame); sl@0: sl@0: WriteHeader(*parser); sl@0: WriteScaleFactors(*parser); sl@0: WriteData(*parser); sl@0: WritePaddingL(*parser); sl@0: sl@0: CleanupStack::PopAndDestroy(parser); sl@0: } sl@0: sl@0: /** sl@0: This function writes the sbc frame header into the destination buffer. sl@0: @internalComponent sl@0: @param aParser sl@0: The bit stream parser which manipulates the destination buffer bit stream sl@0: */ sl@0: void CSBCFrameEncoder::WriteHeader(CBitStreamParser& aParser) sl@0: { sl@0: // syncword sl@0: aParser.WriteByte(KSBCFrameSyncWord); sl@0: // sampling frequency, blocklength, channel mode, allocatin method, subbands sl@0: aParser.WriteByte(iParameters.Parameters() ); sl@0: // bitpool sl@0: aParser.WriteByte(iParameters.Bitpool() ); sl@0: // crc check sl@0: aParser.WriteByte(CalcCRC() ); sl@0: sl@0: if (iParameters.ChannelMode() == TSBCFrameParameters::EJointStereo) sl@0: { sl@0: // join[] & RFA sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: aParser.WriteBits(1, iJoin[subband]); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function writes the sbc frame scale factors into the destination buffer. sl@0: @internalComponent sl@0: @param aParser sl@0: The bit stream parser which manipulates the destination buffer bit stream sl@0: */ sl@0: void CSBCFrameEncoder::WriteScaleFactors(CBitStreamParser& aParser) sl@0: { sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: const TUint8* scaleFactors = iScaleFactors[channel]; sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: aParser.WriteBits(4, *scaleFactors++); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function writes one sbc subband sample into the destination buffer. sl@0: @internalComponent sl@0: @param aParser sl@0: The bit stream parser which manipulates the destination buffer bit stream sl@0: @param aBits sl@0: The number of bits to write sl@0: @param aSample sl@0: The sample value to write sl@0: */ sl@0: static void WriteOneSample(CBitStreamParser& aParser, TUint8 aBits, TInt32 aSample) sl@0: { sl@0: if (aBits >= 8) sl@0: { sl@0: aBits -= 8; sl@0: aParser.WriteByte(static_cast( (aSample >> aBits) & 0xff) ); sl@0: } sl@0: if (aBits > 0) sl@0: { sl@0: aParser.WriteBits(aBits, static_cast(aSample & 0xff) ); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function writes the sbc frame data into the destination buffer. sl@0: @internalComponent sl@0: @param aParser sl@0: The bit stream parser which manipulates the destination buffer bit stream sl@0: */ sl@0: void CSBCFrameEncoder::WriteData(CBitStreamParser& aParser) sl@0: { sl@0: const TUint8 numBlocks = iParameters.BlockLength(); sl@0: const TUint8 numChannels = iParameters.Channels(); sl@0: const TUint8 numSubbands = iParameters.Subbands(); sl@0: sl@0: for (TUint8 block = 0; block < numBlocks; block++) sl@0: { sl@0: for (TUint8 channel = 0; channel < numChannels; channel++) sl@0: { sl@0: const TUint8* bits = iBits[channel]; sl@0: const TInt32* samples = iOutputSamples[block][channel]; sl@0: sl@0: for (TUint8 subband = 0; subband < numSubbands; subband++) sl@0: { sl@0: if (*bits > 0) sl@0: { sl@0: WriteOneSample(aParser, *bits, *samples); sl@0: } sl@0: bits++; sl@0: samples++; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: This function writes the sbc frame padding bits into the destination buffer. sl@0: @internalComponent sl@0: @param aParser sl@0: The bit stream parser which manipulates the destination buffer bit stream sl@0: @panic if output frame length is not the same as expected sl@0: */ sl@0: void CSBCFrameEncoder::WritePaddingL(CBitStreamParser& aParser) sl@0: { sl@0: TUint byteOffset; sl@0: TUint8 bitOffset; sl@0: sl@0: aParser.Position(byteOffset, bitOffset); sl@0: sl@0: if (bitOffset != 0) sl@0: { sl@0: aParser.WriteBits(8 - bitOffset, 0); sl@0: byteOffset++; sl@0: } sl@0: sl@0: if (byteOffset != iParameters.CalcFrameLength() ) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: }