1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/sounddevbt/src/Plugin/Codec/SBCEncoder/BtSBCEncoder.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1792 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "mmfSBCCodecImplementationUIDs.hrh" // KMmfUidSBCConfigure
1.20 +
1.21 +#include "BtSBCEncoder.h"
1.22 +#include "BtSBCConst.h"
1.23 +#include "BtSBCFrameParameters.h"
1.24 +#include "../../MmfBtFileDependencyUtil.h"
1.25 +
1.26 +/**
1.27 +The sbc configuration UID, used to identify configuration type,
1.28 +have to use this to configure any sbc codec.
1.29 +*/
1.30 +const TUid KSBCConfigTypeUid = { KMmfUidSBCConfigure };
1.31 +
1.32 +/**
1.33 +SBC CRC shift register initial value for SBC CRC calculation
1.34 +*/
1.35 +const TUint8 KSbcCRCShiftRegisterInit = 0x0f;
1.36 +/**
1.37 +SBC CRC XOR mask, derived from polynomial G(X) = X^8 + X^4 + X^3 + X^2 + 1
1.38 +*/
1.39 +const TUint8 KSbcCRCShiftRegisterXorMask = 0x1d;
1.40 +
1.41 +#ifdef _DEBUG
1.42 +
1.43 +enum
1.44 + {
1.45 + ESbcBitstreamPosErr,
1.46 + ESbcSampleOverflow
1.47 + };
1.48 +
1.49 +_LIT(KSBCEncoderPanicCategory, "CSBCEncoder");
1.50 +
1.51 +static inline void Panic(TInt aError)
1.52 + {
1.53 + User::Panic(KSBCEncoderPanicCategory, aError);
1.54 + }
1.55 +
1.56 +#endif
1.57 +
1.58 +/* ========================= class CBitStreamParser ========================= */
1.59 +
1.60 +/**
1.61 +class CBitStreamParser constructor
1.62 +@internalComponent
1.63 +@param aBitStream
1.64 +The bit stream buffer to be parsed
1.65 +*/
1.66 +CBitStreamParser::CBitStreamParser(TDes8& aBitStream) : iBitStream(aBitStream),
1.67 + iByteOffset(0), iBitOffset(0)
1.68 + {
1.69 + iPtr = const_cast<TUint8*>(aBitStream.Ptr() );
1.70 + }
1.71 +
1.72 +/**
1.73 +class CBitStreamParser destructor
1.74 +@internalComponent
1.75 +*/
1.76 +CBitStreamParser::~CBitStreamParser()
1.77 + {
1.78 + }
1.79 +
1.80 +/**
1.81 +class CBitStreamParser second phase constructor
1.82 +@internalComponent
1.83 +*/
1.84 +void CBitStreamParser::ConstructL()
1.85 + {
1.86 + }
1.87 +
1.88 +/**
1.89 +This function creates a new CBitStreamParser object and push it into CleanupStack.
1.90 +@internalComponent
1.91 +@param aBitStream
1.92 +The bit stream buffer to be parsed
1.93 +@return pointer to the new CBitStreamParser object
1.94 +@leave if out of memory
1.95 +*/
1.96 +CBitStreamParser* CBitStreamParser::NewLC(TDes8& aBitStream)
1.97 + {
1.98 + CBitStreamParser* self = new(ELeave) CBitStreamParser(aBitStream);
1.99 + CleanupStack::PushL(self);
1.100 + self->ConstructL();
1.101 + return self;
1.102 + }
1.103 +
1.104 +/**
1.105 +This function reset the internal bit position of CBitStreamParser
1.106 +@internalComponent
1.107 +*/
1.108 +void CBitStreamParser::Reset()
1.109 + {
1.110 + iPtr = const_cast<TUint8*>(iBitStream.Ptr() );
1.111 + iByteOffset = 0;
1.112 + iBitOffset = 0;
1.113 + }
1.114 +
1.115 +/**
1.116 +This function reads a number of bits from bit stream buffer at current bit position
1.117 +and change the bit position to then end of the last bit read.
1.118 +@internalComponent
1.119 +@param aBitsToRead
1.120 +Number of bits to read, at most 8 bits
1.121 +@return the bits value in byte
1.122 +@panic if bit position is outside of the stream buffer
1.123 +*/
1.124 +TUint8 CBitStreamParser::ReadBits(TInt aBitsToRead)
1.125 + {
1.126 + TUint8 result = 0;
1.127 + if (aBitsToRead >= 8 - iBitOffset)
1.128 + {
1.129 + __ASSERT_DEBUG(iByteOffset < static_cast<TUint>(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) );
1.130 + // extra code to handle exception for URel version
1.131 + if (iByteOffset >= static_cast<TUint>(iBitStream.MaxLength() ) )
1.132 + {
1.133 + return 0;
1.134 + }
1.135 +
1.136 + aBitsToRead -= (8 - iBitOffset);
1.137 + result = static_cast<TUint8>( (*iPtr & (0xff >> iBitOffset) ) << aBitsToRead);
1.138 +
1.139 + iPtr++;
1.140 + iByteOffset++;
1.141 + iBitOffset = 0;
1.142 + }
1.143 + if (aBitsToRead > 0)
1.144 + {
1.145 + __ASSERT_DEBUG(iByteOffset < static_cast<TUint>(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) );
1.146 + // extra code to handle exception for URel version
1.147 + if (iByteOffset >= static_cast<TUint>(iBitStream.MaxLength() ) )
1.148 + {
1.149 + return 0;
1.150 + }
1.151 +
1.152 + result |= static_cast<TUint8>( (*iPtr & (0xff >> iBitOffset) ) >> (8 - iBitOffset - aBitsToRead) );
1.153 + iBitOffset = static_cast<TUint8>(iBitOffset + aBitsToRead);
1.154 + }
1.155 + return result;
1.156 + }
1.157 +
1.158 +/**
1.159 +This function writes a number of bits to the bit stream buffer at current bit position
1.160 +and change the bit position to then end of the last bit written.
1.161 +@internalComponent
1.162 +@param aBitsToWrite
1.163 +Number of bits to write, at most 8 bits
1.164 +@param aBitsValue
1.165 +The bits value to write in byte
1.166 +@panic if bit position is outside of the stream buffer
1.167 +*/
1.168 +void CBitStreamParser::WriteBits(TInt aBitsToWrite, TUint8 aBitsValue)
1.169 + {
1.170 + if (aBitsToWrite >= 8 - iBitOffset)
1.171 + {
1.172 + __ASSERT_DEBUG(iByteOffset < static_cast<TUint>(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) );
1.173 + // extra code to handle exception for URel version
1.174 + if (iByteOffset >= static_cast<TUint>(iBitStream.MaxLength() ) )
1.175 + {
1.176 + return;
1.177 + }
1.178 +
1.179 + aBitsToWrite -= (8 - iBitOffset);
1.180 + *iPtr &= ~(0xff >> iBitOffset); // clear bits
1.181 + *iPtr |= (aBitsValue >> aBitsToWrite) & (0xff >> iBitOffset); // set bits
1.182 +
1.183 + iPtr++;
1.184 + iByteOffset++;
1.185 + iBitOffset = 0;
1.186 + }
1.187 + if (aBitsToWrite > 0)
1.188 + {
1.189 + __ASSERT_DEBUG(iByteOffset < static_cast<TUint>(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) );
1.190 + // extra code to handle exception for URel version
1.191 + if (iByteOffset >= static_cast<TUint>(iBitStream.MaxLength() ) )
1.192 + {
1.193 + return;
1.194 + }
1.195 +
1.196 + *iPtr &= (0xff << (8 - iBitOffset) ) | (0xff >> (iBitOffset + aBitsToWrite) ); // clear bits
1.197 + *iPtr |= (aBitsValue << (8 - iBitOffset - aBitsToWrite) ) & (0xff >> iBitOffset); // set bits
1.198 + iBitOffset = static_cast<TUint8>(iBitOffset + aBitsToWrite);
1.199 + }
1.200 + }
1.201 +
1.202 +/**
1.203 +This function reads 8 bits from bit stream buffer at current bit position
1.204 +and change the bit position to then end of the last bit read.
1.205 +@internalComponent
1.206 +@return the bits value in byte
1.207 +*/
1.208 +TUint8 CBitStreamParser::ReadByte()
1.209 + {
1.210 + return ReadBits(8);
1.211 + }
1.212 +
1.213 +/**
1.214 +This function writes 8 bits to the bit stream buffer at current bit position
1.215 +and change the bit position to then end of the last bit written.
1.216 +@internalComponent
1.217 +@param aByteValue
1.218 +The byte value to write
1.219 +*/
1.220 +void CBitStreamParser::WriteByte(TUint8 aByteValue)
1.221 + {
1.222 + WriteBits(8, aByteValue);
1.223 + }
1.224 +
1.225 +/**
1.226 +This function sets the bit position to a specific position.
1.227 +@internalComponent
1.228 +@param aByteOffset
1.229 +New byte position to set
1.230 +@param aBitOffset
1.231 +New bit position to set
1.232 +@panic if bit position is outside of the stream buffer
1.233 +*/
1.234 +void CBitStreamParser::SetPosition(TUint aByteOffset, TUint8 aBitOffset)
1.235 + {
1.236 + while (aBitOffset >= 8)
1.237 + {
1.238 + aBitOffset -= 8;
1.239 + iByteOffset++;
1.240 + }
1.241 +
1.242 + __ASSERT_DEBUG(iByteOffset < static_cast<TUint>(iBitStream.MaxLength() ), Panic(ESbcBitstreamPosErr) );
1.243 + // extra code to handle exception for URel version
1.244 + if (iByteOffset >= static_cast<TUint>(iBitStream.MaxLength() ) )
1.245 + {
1.246 + aBitOffset = 0;
1.247 + iByteOffset = iBitStream.MaxLength();
1.248 + }
1.249 +
1.250 + iPtr = const_cast<TUint8*>(iBitStream.Ptr() ) + aByteOffset;
1.251 + iByteOffset = aByteOffset;
1.252 + iBitOffset = aBitOffset;
1.253 + }
1.254 +
1.255 +/**
1.256 +This function gets the bit position.
1.257 +@internalComponent
1.258 +@param aByteOffset
1.259 +Read byte position
1.260 +@param aBitOffset
1.261 +Read bit position
1.262 +*/
1.263 +void CBitStreamParser::Position(TUint& aByteOffset, TUint8& aBitOffset) const
1.264 + {
1.265 + aByteOffset = iByteOffset;
1.266 + aBitOffset = iBitOffset;
1.267 + }
1.268 +
1.269 +/* ========================= class CSbcCRCCalculator ========================= */
1.270 +
1.271 +/**
1.272 +Constructor
1.273 +@internalComponent
1.274 +*/
1.275 +CSbcCRCCalculator::CSbcCRCCalculator() : iShiftRegister(KSbcCRCShiftRegisterInit)
1.276 + {
1.277 + }
1.278 +
1.279 +/**
1.280 +This function resets the shift register value to intial SBC CRC value
1.281 +@internalComponent
1.282 +*/
1.283 +void CSbcCRCCalculator::Reset()
1.284 + {
1.285 + iShiftRegister = KSbcCRCShiftRegisterInit;
1.286 + }
1.287 +
1.288 +/**
1.289 +This function inputs one bit into the shift register
1.290 +@internalComponent
1.291 +@param aBit
1.292 +The lowest bit contains the bit to input.
1.293 +*/
1.294 +void CSbcCRCCalculator::InputBit(TUint8 aBit)
1.295 + {
1.296 + TUint8 inputBit = static_cast<TUint8>( (iShiftRegister >> 7) ^ (aBit & 0x1) );
1.297 + iShiftRegister <<= 1;
1.298 +
1.299 + if (inputBit)
1.300 + {
1.301 + iShiftRegister ^= KSbcCRCShiftRegisterXorMask;
1.302 + }
1.303 + }
1.304 +
1.305 +/**
1.306 +This function inputs a number of bits into the shift register
1.307 +@internalComponent
1.308 +@param aBits
1.309 +The number of bits to input, at most 8 bits.
1.310 +@param aValue
1.311 +The input bits value.
1.312 +*/
1.313 +void CSbcCRCCalculator::InputBits(TUint8 aBits, TUint8 aValue)
1.314 + {
1.315 + for (TInt bit = aBits - 1; bit >= 0; bit--)
1.316 + {
1.317 + InputBit(static_cast<TUint8>(aValue >> bit) );
1.318 + }
1.319 + }
1.320 +
1.321 +/**
1.322 +This function inputs 8 bits into the shift register.
1.323 +@internalComponent
1.324 +@param aValue
1.325 +The input byte value.
1.326 +*/
1.327 +void CSbcCRCCalculator::InputByte(TUint8 aByte)
1.328 + {
1.329 + InputBit(static_cast<TUint8>(aByte >> 7) );
1.330 + InputBit(static_cast<TUint8>(aByte >> 6) );
1.331 + InputBit(static_cast<TUint8>(aByte >> 5) );
1.332 + InputBit(static_cast<TUint8>(aByte >> 4) );
1.333 + InputBit(static_cast<TUint8>(aByte >> 3) );
1.334 + InputBit(static_cast<TUint8>(aByte >> 2) );
1.335 + InputBit(static_cast<TUint8>(aByte >> 1) );
1.336 + InputBit(aByte);
1.337 + }
1.338 +
1.339 +/**
1.340 +This function gets the shift register value.
1.341 +@internalComponent
1.342 +@return the shift register value.
1.343 +*/
1.344 +TUint8 CSbcCRCCalculator::ShiftRegister()
1.345 + {
1.346 + return iShiftRegister;
1.347 + }
1.348 +
1.349 +/* ============================ class CSBCEncoder ============================ */
1.350 +
1.351 +/**
1.352 +Constructor.
1.353 +@internalComponent
1.354 +*/
1.355 +CSBCEncoder::CSBCEncoder()
1.356 + {
1.357 + }
1.358 +
1.359 +/**
1.360 +Destructor.
1.361 +@internalComponent
1.362 +*/
1.363 +CSBCEncoder::~CSBCEncoder()
1.364 + {
1.365 + delete iSbcFrameEncoder;
1.366 + delete iPcmSampleCach; // this is used to cache any remaining samples less than on frame
1.367 + }
1.368 +
1.369 +/**
1.370 +Second phase constructor.
1.371 +@internalComponent
1.372 +@param aInitParams
1.373 +Initial parameters for creating this object, not in use for the moment
1.374 +@leave never
1.375 +*/
1.376 +void CSBCEncoder::ConstructL(TAny* /*aInitParams*/)
1.377 + {
1.378 + }
1.379 +
1.380 +/**
1.381 +This function resets any existing audio samples from the cach.
1.382 +@internalComponent
1.383 +@leave never
1.384 +*/
1.385 +void CSBCEncoder::ResetL()
1.386 + {
1.387 + if (iPcmSampleCach)
1.388 + {
1.389 + iPcmSampleCach->Des().Zero();
1.390 + }
1.391 + }
1.392 +
1.393 +/**
1.394 +This function creates a new CSBCEncoder object.
1.395 +@internalComponent
1.396 +@param aInitParams
1.397 +Initial parameters for creating this object, not in use for the moment
1.398 +@leave if out of memory
1.399 +*/
1.400 +CMMFCodec* CSBCEncoder::NewL(TAny* aInitParams)
1.401 + {
1.402 + CSBCEncoder* self = new(ELeave) CSBCEncoder();
1.403 + CleanupStack::PushL(self);
1.404 + self->ConstructL(aInitParams);
1.405 + CleanupStack::Pop();
1.406 + return self;
1.407 + }
1.408 +
1.409 +/**
1.410 +This function is used for configuring the CSBCEncoder object. Should be called before encode
1.411 +@internalComponent
1.412 +@param aConfigType
1.413 +Configuration UID, has to be set to KSBCConfigTypeUid
1.414 +@param aConfigData
1.415 +A package buffer which contains all the settings
1.416 +@leave KErrNotSupported if configuration UID does't match or parameters setting is invalid.
1.417 +*/
1.418 +void CSBCEncoder::ConfigureL(TUid aConfigType, const TDesC8& aConfigData)
1.419 + {
1.420 + if (aConfigType != KSBCConfigTypeUid)
1.421 + {
1.422 + User::Leave(KErrNotSupported);
1.423 + }
1.424 +
1.425 + const TSBCFrameParameters& param =
1.426 + static_cast<const TPckgBuf<TSBCFrameParameters>&>(aConfigData)();
1.427 +
1.428 + if (param.Validate() != 0)
1.429 + {
1.430 + User::Leave(KErrArgument);
1.431 + }
1.432 +
1.433 + iParameters = param;
1.434 +
1.435 + if (iPcmSampleCach)
1.436 + {
1.437 + delete iPcmSampleCach;
1.438 + iPcmSampleCach = NULL;
1.439 + }
1.440 +
1.441 + if (iSbcFrameEncoder)
1.442 + {
1.443 + // must call this whenever ConfigureL() is called to make sure CSBCFrameEncoder
1.444 + // uses the new configuration, as we can change the configuration without creating
1.445 + // a new CSBCFrameEncoder object
1.446 + iSbcFrameEncoder->Configure(iParameters);
1.447 + }
1.448 +
1.449 + iSbcFrameLength = iParameters.CalcFrameLength();
1.450 + iPcmFrameSize = sizeof(TInt16) * param.BlockLength() * param.Subbands() * param.Channels();
1.451 + }
1.452 +
1.453 +/**
1.454 +This function encodes sbc audio stream with PCM16 audio source samples, and write processed
1.455 +result to destination buffer. It also caches any less than one frame remaining audio samples.
1.456 +@internalComponent
1.457 +@param aSrc
1.458 +Source buffer contains the PCM16 audio source samples
1.459 +@param aDst
1.460 +Destination buffer to contain the encoded sbc audio stream
1.461 +@return processed result
1.462 +@leave
1.463 + KErrAbort if configuration is invalid,
1.464 + KErrArgument if destination buffer size is smaller than one frame length,
1.465 + KErrCorrupt if output bytes is not the same as frame length or
1.466 + if we still have enough src and dst but the process stoped,
1.467 + Or other errors e.g. out of memory error.
1.468 +*/
1.469 +TCodecProcessResult CSBCEncoder::ProcessL(const CMMFBuffer& aSrc, CMMFBuffer& aDst)
1.470 + {
1.471 + // check if ConfigureL gets called already
1.472 + if (iParameters.Validate() != 0)
1.473 + {
1.474 + User::Leave(KErrAbort);
1.475 + }
1.476 +
1.477 + // check if dst big enough to hold at least one frame
1.478 + CMMFDataBuffer* dst = static_cast<CMMFDataBuffer*>(&aDst);
1.479 + const TUint dstMaxLen = dst->Data().MaxLength();
1.480 +
1.481 + if (dstMaxLen < iSbcFrameLength)
1.482 + {
1.483 + User::Leave(KErrArgument);
1.484 + }
1.485 +
1.486 + // process data
1.487 + const CMMFDataBuffer* src = static_cast<const CMMFDataBuffer*>(&aSrc);
1.488 + const TUint srcLen = src->Data().Length();
1.489 + TUint srcPos = src->Position();
1.490 + TUint dstPos = dst->Position();
1.491 +
1.492 + const TUint8* srcPtr = src->Data().Ptr();
1.493 + TUint8* dstPtr = const_cast<TUint8*>(dst->Data().Ptr() );
1.494 + TUint cachedSize = CachedSampleSize();
1.495 +
1.496 + while (cachedSize + srcLen - srcPos >= iPcmFrameSize && dstMaxLen - dstPos >= iSbcFrameLength)
1.497 + {
1.498 + TPtrC8 srcDes(srcPtr + srcPos, iPcmFrameSize);
1.499 + TPtr8 dstDes(dstPtr + dstPos, iSbcFrameLength);
1.500 +
1.501 + srcPos += EncodeFrameL(srcDes, dstDes);
1.502 + dstPos += iSbcFrameLength;
1.503 + cachedSize = 0;
1.504 + }
1.505 +
1.506 + // check result
1.507 + TCodecProcessResult result;
1.508 + result.iStatus = TCodecProcessResult::EProcessComplete;
1.509 +
1.510 + if (dstMaxLen - dstPos >= iSbcFrameLength) // still enough dst buffer
1.511 + {
1.512 + result.iStatus = TCodecProcessResult::EDstNotFilled;
1.513 + }
1.514 +
1.515 + // cach remaining src
1.516 + if (CachedSampleSize() + srcLen - srcPos >= iPcmFrameSize) // still enough src
1.517 + {
1.518 + if (result.iStatus == TCodecProcessResult::EDstNotFilled)
1.519 + {
1.520 + User::Leave(KErrCorrupt);
1.521 + }
1.522 + else
1.523 + {
1.524 + result.iStatus = TCodecProcessResult::EProcessIncomplete;
1.525 + }
1.526 + }
1.527 + else if (srcLen - srcPos > 1) // remaining src less than one frame, cach it
1.528 + {
1.529 + srcPos += CachePcmSamplesL(*src, srcPos);
1.530 + }
1.531 +
1.532 + // set new position for dst
1.533 + dst->Data().SetLength(dstPos);
1.534 +
1.535 + // return result
1.536 + result.iSrcBytesProcessed = srcPos - src->Position();
1.537 + result.iDstBytesAdded = dstPos - dst->Position();
1.538 + return result;
1.539 + }
1.540 +
1.541 +/**
1.542 +This function encodes one SBC frame with PCM16 audio source samples, and write processed
1.543 +result to destination buffer.
1.544 +@internalComponent
1.545 +@param aSrc
1.546 +Source buffer contains the PCM16 audio source samples
1.547 +@param aDst
1.548 +Destination buffer to contain the encoded sbc audio stream
1.549 +@return the number of bytes the source has been processed
1.550 +@leave if out of memory.
1.551 +*/
1.552 +TUint CSBCEncoder::EncodeFrameL(const TDesC8& aSrc, TDes8& aDst)
1.553 + {
1.554 + if (!iSbcFrameEncoder)
1.555 + {
1.556 + iSbcFrameEncoder = CSBCFrameEncoder::NewL();
1.557 + iSbcFrameEncoder->Configure(iParameters);
1.558 + }
1.559 +
1.560 + if (CachedSampleSize() > 0)
1.561 + { // encode one frame with cached samples and src
1.562 + TUint appendBytes = iPcmFrameSize - CachedSampleSize();
1.563 + // append src to cach to make up one frame
1.564 + iPcmSampleCach->Des().Append(aSrc.Ptr(), appendBytes);
1.565 + // encode cach
1.566 + iSbcFrameEncoder->EncodeFrameL(*iPcmSampleCach, aDst);
1.567 + // empty cach
1.568 + iPcmSampleCach->Des().Zero();
1.569 + // return bytes src processed
1.570 + return appendBytes;
1.571 + }
1.572 + else
1.573 + {
1.574 + // encode one frame with src only
1.575 + iSbcFrameEncoder->EncodeFrameL(aSrc, aDst);
1.576 + // return bytes src processed
1.577 + return iPcmFrameSize;
1.578 + }
1.579 + }
1.580 +
1.581 +/**
1.582 +This function caches any less than one frame remaining audio samples.
1.583 +@internalComponent
1.584 +@param aSrc
1.585 +Source buffer contains the PCM16 audio source samples.
1.586 +@param aSrcPos
1.587 +Position from where the samples are cached.
1.588 +@return the number of bytes the source has been cached
1.589 +@leave if out of memory.
1.590 +*/
1.591 +TUint CSBCEncoder::CachePcmSamplesL(const CMMFDataBuffer& aSrc, TUint aSrcPos)
1.592 + {
1.593 + if (!iPcmSampleCach)
1.594 + {
1.595 + iPcmSampleCach = HBufC8::NewL(iPcmFrameSize);
1.596 + }
1.597 +
1.598 + const TUint8* pSrc = aSrc.Data().Ptr() + aSrcPos;
1.599 + const TUint cachSize = (aSrc.Data().Length() - aSrcPos) & 0xfffe; // take even number
1.600 +
1.601 + iPcmSampleCach->Des().Append(pSrc, cachSize);
1.602 +
1.603 + return cachSize;
1.604 + }
1.605 +
1.606 +/**
1.607 +This function gets the size of the cach.
1.608 +@internalComponent
1.609 +@return the cached samples size
1.610 +*/
1.611 +TUint CSBCEncoder::CachedSampleSize()
1.612 + {
1.613 + if (!iPcmSampleCach)
1.614 + {
1.615 + return 0;
1.616 + }
1.617 + return iPcmSampleCach->Des().Size();
1.618 + }
1.619 +
1.620 +/* ========================== class CSBCFrameEncoder ========================== */
1.621 +
1.622 +/**
1.623 +Constructor.
1.624 +@internalComponent
1.625 +*/
1.626 +CSBCFrameEncoder::CSBCFrameEncoder()
1.627 + {
1.628 + }
1.629 +
1.630 +/**
1.631 +Destructor.
1.632 +@internalComponent
1.633 +*/
1.634 +CSBCFrameEncoder::~CSBCFrameEncoder()
1.635 + {
1.636 + }
1.637 +
1.638 +/**
1.639 +Second phase constructor.
1.640 +@internalComponent
1.641 +*/
1.642 +void CSBCFrameEncoder::ConstructL()
1.643 + {
1.644 + }
1.645 +
1.646 +/**
1.647 +This function creates a CSBCFrameEncoder object.
1.648 +@internalComponent
1.649 +@return pointer of the CSBCFrameEncoder object.
1.650 +*/
1.651 +CSBCFrameEncoder* CSBCFrameEncoder::NewL()
1.652 + {
1.653 + CSBCFrameEncoder* self = new(ELeave) CSBCFrameEncoder();
1.654 + CleanupStack::PushL(self);
1.655 + self->ConstructL();
1.656 + CleanupStack::Pop();
1.657 + return self;
1.658 + }
1.659 +
1.660 +/**
1.661 +This function resets the analysis filter bank, this should be called everytime
1.662 +when encoding a new sbc audio stream.
1.663 +@internalComponent
1.664 +*/
1.665 +void CSBCFrameEncoder::Reset()
1.666 + {
1.667 + const TUint8 numChannels = iParameters.Channels();
1.668 + const TUint8 numSubbands = iParameters.Subbands();
1.669 +
1.670 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.671 + {
1.672 + TInt16* analysisSamples = iAnalysisSamples[channel];
1.673 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.674 + {
1.675 + *analysisSamples++ = 0;
1.676 + }
1.677 + }
1.678 + }
1.679 +
1.680 +/**
1.681 +This function sets the configuration for SBC Frame Encoder and resets the analysis filter bank.
1.682 +@internalComponent
1.683 +@param aParameters
1.684 +This contains all the parameters to set
1.685 +*/
1.686 +void CSBCFrameEncoder::Configure(const TSBCFrameParameters& aParameters)
1.687 + {
1.688 + iParameters = aParameters;
1.689 + // has to call this whenever the configuration changed, this resets the Analyse Filter Bank
1.690 + Reset();
1.691 + }
1.692 +
1.693 +/**
1.694 +This function encodes one SBC frame with PCM16 source samples and output it to destination buffer.
1.695 +@internalComponent
1.696 +@param aSrc
1.697 +Source buffer contains the source samples
1.698 +@param aFrame
1.699 +Destination buffer to contain the processed sbc audio stream
1.700 +@leave if out of memory
1.701 +*/
1.702 +void CSBCFrameEncoder::EncodeFrameL(const TDesC8& aSrc, TDes8& aFrame)
1.703 + {
1.704 + // encode frame
1.705 + Analyse(aSrc);
1.706 + CalcScaleFactors();
1.707 + JoinSubbands();
1.708 + CalcBitAllocation();
1.709 + Quantize();
1.710 +
1.711 + // output frame
1.712 + WriteFrameL(aFrame);
1.713 + }
1.714 +
1.715 +/**
1.716 +This function does the analysis filtering, the analysed samples are used to encode sbc subbands.
1.717 +@internalComponent
1.718 +@param aSrc
1.719 +Source buffer contains the source samples
1.720 +*/
1.721 +void CSBCFrameEncoder::Analyse(const TDesC8& aSrc)
1.722 + {
1.723 + const TUint8 channelMode = iParameters.ChannelMode();
1.724 + const TInt16* inputSamples = reinterpret_cast<const TInt16*>(aSrc.Ptr() );
1.725 +
1.726 + if (channelMode == TSBCFrameParameters::EMono)
1.727 + {
1.728 + AnalyseMono(inputSamples);
1.729 + }
1.730 + else // two-channel modes
1.731 + {
1.732 + // two channel samples are interleavedly stored in the following order
1.733 + // one left sample, one right sample, ...
1.734 + AnalyseOneChannel(inputSamples, 0);
1.735 + AnalyseOneChannel(inputSamples + 1, 1);
1.736 + }
1.737 + }
1.738 +
1.739 +/**
1.740 +This function analyses audio samples for Mono and Dual Channel modes.
1.741 +@internalComponent
1.742 +@param aInputSamples
1.743 +Array of source samples
1.744 +*/
1.745 +void CSBCFrameEncoder::AnalyseMono(const TInt16 aInputSamples[])
1.746 + {
1.747 + const TUint8 numSubbands = iParameters.Subbands();
1.748 + const TUint8 numBlocks = iParameters.BlockLength();
1.749 +
1.750 + for (TUint8 block = 0; block < numBlocks; block++)
1.751 + {
1.752 + if (numSubbands == 4)
1.753 + {
1.754 + Analyse4Subbands(aInputSamples, block, 0);
1.755 + }
1.756 + else
1.757 + {
1.758 + Analyse8Subbands(aInputSamples, block, 0);
1.759 + }
1.760 + aInputSamples += numSubbands;
1.761 + }
1.762 + }
1.763 +
1.764 +/**
1.765 +This function analyses audio samples for Stereo and Joint Stereo modes.
1.766 +@internalComponent
1.767 +@param aInputSamples
1.768 +Array of source samples
1.769 +@param aChannel
1.770 +The channel number to be analysed
1.771 +*/
1.772 +void CSBCFrameEncoder::AnalyseOneChannel(const TInt16 aInputSamples[], TUint8 aChannel)
1.773 + {
1.774 + const TUint8 numSubbands = iParameters.Subbands();
1.775 + const TUint8 numBlocks = iParameters.BlockLength();
1.776 +
1.777 + TInt16 inputSamples[KSbcMaxSubbands];
1.778 + for (TUint8 block = 0; block < numBlocks; block++)
1.779 + {
1.780 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.781 + {
1.782 + inputSamples[subband] = *aInputSamples;
1.783 + aInputSamples += 2; // 1 left sample, 1 right sample, ...
1.784 + }
1.785 +
1.786 + if (numSubbands == 4)
1.787 + {
1.788 + Analyse4Subbands(inputSamples, block, aChannel);
1.789 + }
1.790 + else
1.791 + {
1.792 + Analyse8Subbands(inputSamples, block, aChannel);
1.793 + }
1.794 + }
1.795 + }
1.796 +
1.797 +
1.798 +/**
1.799 +This function analyses 4 subbands for sbc frame with 4 subbands.
1.800 +@internalComponent
1.801 +@param aInputSamples
1.802 +Array of source samples
1.803 +@param aBlock
1.804 +The block number to be analysed
1.805 +@param aChannel
1.806 +The channel number to be analysed
1.807 +*/
1.808 +void CSBCFrameEncoder::Analyse4Subbands(const TInt16 aInputSamples[], TUint8 aBlock, TUint8 aChannel)
1.809 + {
1.810 + // for easier understanding, this code is a copy from the A2DP spec,
1.811 + // all the naming are kept.
1.812 + TInt i = 0;
1.813 + TInt k = 0;
1.814 + TInt16* X = iAnalysisSamples[aChannel]; // 40 analyse samples
1.815 +
1.816 + for (i = 39; i >= 4; i--)
1.817 + {
1.818 + X[i] = X[i - 4];
1.819 + }
1.820 + for (i = 3; i >= 0; i--)
1.821 + {
1.822 + X[i] = *aInputSamples++;
1.823 + }
1.824 +
1.825 + TInt64 Y[8]; // partial calculation, see Figure 12.5 in A2DP spec for detail
1.826 + for (i = 0; i < 8; i++)
1.827 + {
1.828 + TInt64 sum = 0;
1.829 + for (k = 0; k <= 4; k++)
1.830 + {
1.831 + // for some strange reason, RVCT is not happy about converting
1.832 + // TInt16 to TInt64 in the equation directly.
1.833 + const TInt64 sample = X[i + (k << 3)];
1.834 + sum += KSBCProto4[i + (k << 3)] * sample;
1.835 + }
1.836 + Y[i] = sum >> (KSBCProtoBitsShift - 10);
1.837 + }
1.838 +
1.839 + TInt32* outputSamples = iOutputSamples[aBlock][aChannel];
1.840 + for (i = 0; i < 4; i++)
1.841 + {
1.842 + const TInt32* M = KSBCAnalysisMatrix4[i];
1.843 + TInt64 sum = 0;
1.844 + for (k = 0; k < 8; k++)
1.845 + {
1.846 + sum += M[k] * Y[k];
1.847 + }
1.848 + sum >>= (KSBCAnalysisMatrixBitsShift + 9);
1.849 + sum = (sum >> 1) + (sum & 0x1);
1.850 + outputSamples[i] = static_cast<TInt32>(sum);
1.851 + }
1.852 + }
1.853 +
1.854 +/**
1.855 +This function analyses 8 subbands for sbc frame with 8 subbands.
1.856 +@internalComponent
1.857 +@param aInputSamples
1.858 +Array of source samples
1.859 +@param aBlock
1.860 +The block number to be analysed
1.861 +@param aChannel
1.862 +The channel number to be analysed
1.863 +*/
1.864 +void CSBCFrameEncoder::Analyse8Subbands(const TInt16 aInputSamples[], TUint8 aBlock, TUint8 aChannel)
1.865 + {
1.866 + // for easier understanding, this code is a copy from the A2DP spec,
1.867 + // all the naming are kept.
1.868 + TInt i = 0;
1.869 + TInt k = 0;
1.870 + TInt16* X = iAnalysisSamples[aChannel]; // 80 analysis samples
1.871 +
1.872 + for (i = 79; i >= 8; i--)
1.873 + {
1.874 + X[i] = X[i - 8];
1.875 + }
1.876 + for (i = 7; i >= 0; i--)
1.877 + {
1.878 + X[i] = *aInputSamples++;
1.879 + }
1.880 +
1.881 + TInt64 Y[16]; // partial calculation, see Figure 12.5 in A2DP spec for detail
1.882 + for (i = 0; i < 16; i++)
1.883 + {
1.884 + TInt64 sum = 0;
1.885 + for (k = 0; k <= 4; k++)
1.886 + {
1.887 + // for some strange reason, RVCT is not happy about converting
1.888 + // TInt16 to TInt64 in the equation directly.
1.889 + const TInt64 sample = X[i + (k << 4)];
1.890 + sum += KSBCProto8[i + (k << 4)] * sample;
1.891 + }
1.892 + Y[i] = sum >> (KSBCProtoBitsShift - 10);
1.893 + }
1.894 +
1.895 + TInt32* outputSamples = iOutputSamples[aBlock][aChannel];
1.896 + for (i = 0; i < 8; i++)
1.897 + {
1.898 + const TInt32* M = KSBCAnalysisMatrix8[i];
1.899 + TInt64 sum = 0;
1.900 + for (k = 0; k < 16; k++)
1.901 + {
1.902 + sum += M[k] * Y[k];
1.903 + }
1.904 + sum >>= (KSBCAnalysisMatrixBitsShift + 9);
1.905 + sum = (sum >> 1) + (sum & 0x1);
1.906 + outputSamples[i] = static_cast<TInt32>(sum);
1.907 + }
1.908 + }
1.909 +
1.910 +/**
1.911 +This function calculates the scale factor for one sample.
1.912 +@internalComponent
1.913 +@param aSample
1.914 +A sample
1.915 +@return scale factor of thie sample
1.916 +*/
1.917 +static inline TUint8 ScaleFactor(TInt32 aSample)
1.918 + {
1.919 + if (aSample < 0)
1.920 + aSample = -aSample;
1.921 +
1.922 + // top bit of the sample is sign bit, ignore it
1.923 + // start from the second high bit
1.924 + TUint32 mask = 0x40000000;
1.925 + for (TInt8 bit = 30; bit > 0; bit--)
1.926 + {
1.927 + if (aSample & mask)
1.928 + {
1.929 + return bit;
1.930 + }
1.931 + mask >>= 1;
1.932 + }
1.933 + return 0;
1.934 + }
1.935 +
1.936 +/**
1.937 +This function calculates the scale factors for all samples in one sbc frame.
1.938 +@internalComponent
1.939 +*/
1.940 +void CSBCFrameEncoder::CalcScaleFactors()
1.941 + {
1.942 + const TUint8 numBlocks = iParameters.BlockLength();
1.943 + const TUint8 numChannels = iParameters.Channels();
1.944 + const TUint8 numSubbands = iParameters.Subbands();
1.945 +
1.946 + TInt32 maxSubbandValues[KSbcMaxChannels][KSbcMaxSubbands];
1.947 +
1.948 + // find all maximum values of each subband
1.949 + for (TUint8 block = 0; block < numBlocks; block++)
1.950 + {
1.951 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.952 + {
1.953 + const TInt32* samples = iOutputSamples[block][channel];
1.954 + TInt32* maxValues = maxSubbandValues[channel];
1.955 +
1.956 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.957 + {
1.958 + if (block == 0 || Abs(*samples) > *maxValues)
1.959 + {
1.960 + *maxValues = Abs(*samples);
1.961 + }
1.962 + samples++;
1.963 + maxValues++;
1.964 + }
1.965 + }
1.966 + }
1.967 +
1.968 + // calculate scale factors for all subband
1.969 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.970 + {
1.971 + const TInt32* maxValues = maxSubbandValues[channel];
1.972 + TUint8* scale = iScaleFactors[channel];
1.973 +
1.974 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.975 + {
1.976 + *scale++ = ScaleFactor(*maxValues++);
1.977 + }
1.978 + }
1.979 + }
1.980 +
1.981 +/**
1.982 +This function joins two subband samples for Joint Stereo mode.
1.983 +@internalComponent
1.984 +@param aLeftSample
1.985 +Left channel subband sample
1.986 +@param aRightSample
1.987 +Right channel subband sample
1.988 +*/
1.989 +static inline void JoinTwoSamples(TInt32& aLeftSample, TInt32& aRightSample)
1.990 + {
1.991 + aLeftSample = (aLeftSample + aRightSample) >> 1; // L1 = (L0 + R0) / 2
1.992 + aRightSample = aLeftSample - aRightSample; // R1 = L1 - R0 = (L0 - R0) / 2
1.993 + }
1.994 +
1.995 +/**
1.996 +This function sets the join flats for all subbands for one frame,
1.997 +and joins those subbands if needed for this frame.
1.998 +@internalComponent
1.999 +*/
1.1000 +void CSBCFrameEncoder::JoinSubbands()
1.1001 + {
1.1002 + if (iParameters.ChannelMode() != TSBCFrameParameters::EJointStereo)
1.1003 + {
1.1004 + return;
1.1005 + }
1.1006 +
1.1007 + const TUint8 numBlocks = iParameters.BlockLength();
1.1008 + const TUint8 numSubbands = iParameters.Subbands();
1.1009 +
1.1010 + TInt32 maxJoinValues[2][KSbcMaxSubbands - 1]; // 2 channels
1.1011 +
1.1012 + // find maximum join subband values
1.1013 + for (TUint8 block = 0; block < numBlocks; block++)
1.1014 + {
1.1015 + const TInt32* leftSamples = iOutputSamples[block][0];
1.1016 + const TInt32* rightSamples = iOutputSamples[block][1];
1.1017 +
1.1018 + TInt32* maxLeftJoin = maxJoinValues[0];
1.1019 + TInt32* maxRightJoin = maxJoinValues[1];
1.1020 +
1.1021 + for (TUint8 subband = 0; subband < numSubbands - 1; subband++)
1.1022 + {
1.1023 + TInt32 leftJoin = *leftSamples++;
1.1024 + TInt32 rightJoin = *rightSamples++;
1.1025 +
1.1026 + JoinTwoSamples(leftJoin, rightJoin);
1.1027 +
1.1028 + if (block == 0 || Abs(leftJoin) > *maxLeftJoin)
1.1029 + {
1.1030 + *maxLeftJoin = Abs(leftJoin);
1.1031 + }
1.1032 + if (block == 0 || Abs(rightJoin) > *maxRightJoin)
1.1033 + {
1.1034 + *maxRightJoin = Abs(rightJoin);
1.1035 + }
1.1036 + maxLeftJoin++;
1.1037 + maxRightJoin++;
1.1038 + }
1.1039 + }
1.1040 +
1.1041 + // calculate scale factors for all join subbands
1.1042 + const TInt32* maxLeftJoin = maxJoinValues[0];
1.1043 + const TInt32* maxRightJoin = maxJoinValues[1];
1.1044 +
1.1045 + TUint8* leftScale = iScaleFactors[0];
1.1046 + TUint8* rightScale = iScaleFactors[1];
1.1047 +
1.1048 + for (TUint8 subband = 0; subband < numSubbands - 1; subband++)
1.1049 + {
1.1050 + const TUint8 leftJoinScale = ScaleFactor(*maxLeftJoin++);
1.1051 + const TUint8 rightJoinScale = ScaleFactor(*maxRightJoin++);
1.1052 +
1.1053 + iJoin[subband] = 0;
1.1054 + if (leftJoinScale + rightJoinScale < *leftScale + *rightScale)
1.1055 + {
1.1056 + iJoin[subband] = 1;
1.1057 + *leftScale = leftJoinScale;
1.1058 + *rightScale = rightJoinScale;
1.1059 + }
1.1060 + leftScale++;
1.1061 + rightScale++;
1.1062 + }
1.1063 + iJoin[numSubbands - 1] = 0; // join[subband - 1] is always 0
1.1064 +
1.1065 + // now do the joining job
1.1066 + DoJoinSubbands();
1.1067 + }
1.1068 +
1.1069 +/**
1.1070 +This function joins all subbands if needed for this frame.
1.1071 +@internalComponent
1.1072 +*/
1.1073 +void CSBCFrameEncoder::DoJoinSubbands()
1.1074 + {
1.1075 + const TUint8 numBlocks = iParameters.BlockLength();
1.1076 + const TUint8 numSubbands = iParameters.Subbands();
1.1077 +
1.1078 + for (TUint8 block = 0; block < numBlocks; block++)
1.1079 + {
1.1080 + TInt32* leftSamples = iOutputSamples[block][0];
1.1081 + TInt32* rightSamples = iOutputSamples[block][1];
1.1082 +
1.1083 + for (TUint8 subband = 0; subband < numSubbands - 1; subband++)
1.1084 + {
1.1085 + if (iJoin[subband])
1.1086 + {
1.1087 + JoinTwoSamples(*leftSamples, *rightSamples);
1.1088 + }
1.1089 + leftSamples++;
1.1090 + rightSamples++;
1.1091 + }
1.1092 + }
1.1093 + }
1.1094 +
1.1095 +/**
1.1096 +This function quantizes one sample according to:
1.1097 + sample = (sample / scale + 1.0) * level / 2.0
1.1098 + scale = 2 ^ (scale_factor + 1)
1.1099 + level = (2 ^ bits) - 1
1.1100 +@internalComponent
1.1101 +@param aSample
1.1102 +A sample to be quantized.
1.1103 +@param aScaleFactor
1.1104 +The scale factor value.
1.1105 +@param aBits
1.1106 +The number of bits for this sample
1.1107 +@panic if quantized sample overflow
1.1108 +*/
1.1109 +static void QuantizeOneSample(TInt32& aSample, TUint8 aScaleFactor, TUint8 aBits)
1.1110 + {
1.1111 + // output = sample + scale
1.1112 + TInt64 temp = (TInt)aSample + (0x1 << (aScaleFactor + 1) );
1.1113 + // output = (sample + scale) * level / scale
1.1114 + temp = ( (temp << aBits) - temp) >> (aScaleFactor + 2);
1.1115 +
1.1116 + aSample = static_cast<TInt32>(temp);
1.1117 +
1.1118 + // check bounce
1.1119 + __ASSERT_DEBUG(aSample >= 0 && aSample <= (TInt32)0xffff, Panic(ESbcSampleOverflow) );
1.1120 + // extra code to handle exception for URel version
1.1121 + if (aSample < 0)
1.1122 + {
1.1123 + aSample = 0;
1.1124 + }
1.1125 + if (aSample > (TInt32)0xffff)
1.1126 + {
1.1127 + aSample = (TInt32)0xffff;
1.1128 + }
1.1129 + }
1.1130 +
1.1131 +/**
1.1132 +This function quantizes all samples in one sbc frame.
1.1133 +@internalComponent
1.1134 +*/
1.1135 +void CSBCFrameEncoder::Quantize()
1.1136 + {
1.1137 + const TUint8 numBlocks = iParameters.BlockLength();
1.1138 + const TUint8 numChannels = iParameters.Channels();
1.1139 + const TUint8 numSubbands = iParameters.Subbands();
1.1140 +
1.1141 + for (TUint8 block = 0; block < numBlocks; block++)
1.1142 + {
1.1143 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.1144 + {
1.1145 + const TUint8* bits = iBits[channel];
1.1146 + const TUint8* scale = iScaleFactors[channel];
1.1147 + TInt32* samples = iOutputSamples[block][channel];
1.1148 +
1.1149 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1150 + {
1.1151 + QuantizeOneSample(*samples++, *scale++, *bits++);
1.1152 + }
1.1153 + }
1.1154 + }
1.1155 + }
1.1156 +
1.1157 +/**
1.1158 +This function calculates bit allocation for all samples in one sbc frame using scale factors.
1.1159 +@internalComponent
1.1160 +*/
1.1161 +void CSBCFrameEncoder::CalcBitAllocation()
1.1162 + {
1.1163 + switch (iParameters.ChannelMode())
1.1164 + {
1.1165 + case TSBCFrameParameters::EMono:
1.1166 + case TSBCFrameParameters::EDualChannel:
1.1167 + CalcBitAllocIndependent();
1.1168 + break;
1.1169 +
1.1170 + case TSBCFrameParameters::EStereo:
1.1171 + case TSBCFrameParameters::EJointStereo:
1.1172 + CalcBitAllocCombined();
1.1173 + break;
1.1174 + }
1.1175 + }
1.1176 +
1.1177 +/**
1.1178 +This function calculates bit allocation for one channel for Mono and Dual Channel.
1.1179 +@internalComponent
1.1180 +*/
1.1181 +void CSBCFrameEncoder::CalcBitAllocIndependent()
1.1182 + {
1.1183 + const TUint8 numChannels = iParameters.Channels();
1.1184 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.1185 + {
1.1186 + TInt8 bitneed[KSbcMaxSubbands];
1.1187 + CalcBitneedIndependent(bitneed, iScaleFactors[channel]);
1.1188 + DistributeBitsIndependent(bitneed, iBits[channel]);
1.1189 + }
1.1190 + }
1.1191 +
1.1192 +/**
1.1193 +This function calculates bitneed for one channel for Mono and Dual Channel.
1.1194 +@internalComponent
1.1195 +@param aBitneed
1.1196 +Array of bitneed to hold the result
1.1197 +@param aScaleFactors
1.1198 +The scale factors used for this calculation
1.1199 +*/
1.1200 +void CSBCFrameEncoder::CalcBitneedIndependent(TInt8 aBitneed[], const TUint8 aScaleFactors[])
1.1201 + {
1.1202 + // see A2DP spec for reference
1.1203 + const TUint8 numSubbands = iParameters.Subbands();
1.1204 +
1.1205 + if (iParameters.AllocationMethod() == TSBCFrameParameters::ESNR)
1.1206 + {
1.1207 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1208 + {
1.1209 + *aBitneed++ = *aScaleFactors++;
1.1210 + }
1.1211 + }
1.1212 + else // Loudness
1.1213 + {
1.1214 + const TInt8* offset = NULL;
1.1215 + if (numSubbands == 4)
1.1216 + {
1.1217 + offset = KSBCOffset4[iParameters.SamplingFrequencyEnum()];
1.1218 + }
1.1219 + else
1.1220 + {
1.1221 + offset = KSBCOffset8[iParameters.SamplingFrequencyEnum()];
1.1222 + }
1.1223 +
1.1224 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1225 + {
1.1226 + if (*aScaleFactors == 0)
1.1227 + {
1.1228 + *aBitneed = -5;
1.1229 + }
1.1230 + else if ( (*aBitneed = static_cast<TUint8>(*aScaleFactors - *offset) ) > 0)
1.1231 + {
1.1232 + (*aBitneed) >>= 1;
1.1233 + }
1.1234 + aScaleFactors++;
1.1235 + aBitneed++;
1.1236 + offset++;
1.1237 + }
1.1238 + }
1.1239 + }
1.1240 +
1.1241 +/**
1.1242 +This function gets the maximum bitneed in one channel for Mono and Dual Channel.
1.1243 +@internalComponent
1.1244 +@param aBitneed
1.1245 +Array of bitneed.
1.1246 +*/
1.1247 +TInt8 CSBCFrameEncoder::MaxBitneedIndependent(const TInt8 aBitneed[])
1.1248 + {
1.1249 + // see A2DP spec for reference
1.1250 + TInt8 maxBitneed = 0;
1.1251 + const TUint8 numSubbands = iParameters.Subbands();
1.1252 +
1.1253 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1254 + {
1.1255 + if (*aBitneed > maxBitneed)
1.1256 + {
1.1257 + maxBitneed = *aBitneed;
1.1258 + }
1.1259 + aBitneed++;
1.1260 + }
1.1261 +
1.1262 + return maxBitneed;
1.1263 + }
1.1264 +
1.1265 +/**
1.1266 +This function calculates how many bitslices fit into the bitpool for one channel
1.1267 +for Mono and Dual Channel.
1.1268 +@internalComponent
1.1269 +@param aBitneed
1.1270 +Array of bitneed.
1.1271 +@param aBitCount
1.1272 +The bit count, counts how many bits used
1.1273 +@return the number of bitslices
1.1274 +*/
1.1275 +TInt8 CSBCFrameEncoder::CalcBitSlicesIndependent(const TInt8 aBitneed[], TInt& aBitCount)
1.1276 + {
1.1277 + // see A2DP spec for reference
1.1278 + aBitCount = 0;
1.1279 + TInt8 sliceCount = 0;
1.1280 + TInt8 bitSlices = static_cast<TInt8>(MaxBitneedIndependent(aBitneed) + 1);
1.1281 +
1.1282 + const TUint8 numSubbands = iParameters.Subbands();
1.1283 + const TUint8 bitpool = iParameters.Bitpool();
1.1284 +
1.1285 + do {
1.1286 + bitSlices--;
1.1287 + aBitCount += sliceCount;
1.1288 + sliceCount = 0;
1.1289 +
1.1290 + const TInt8* bitneed = aBitneed;
1.1291 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1292 + {
1.1293 + if (*bitneed > bitSlices + 1 && *bitneed < bitSlices + 16)
1.1294 + {
1.1295 + sliceCount++;
1.1296 + }
1.1297 + else if (*bitneed == bitSlices + 1)
1.1298 + {
1.1299 + sliceCount += 2;
1.1300 + }
1.1301 + bitneed++;
1.1302 + }
1.1303 + } while (aBitCount + sliceCount < bitpool);
1.1304 +
1.1305 + if (aBitCount + sliceCount == bitpool)
1.1306 + {
1.1307 + aBitCount += sliceCount;
1.1308 + bitSlices--;
1.1309 + }
1.1310 +
1.1311 + return bitSlices;
1.1312 + }
1.1313 +
1.1314 +/**
1.1315 +This function distributes number of bits to each subband for all samples
1.1316 +for Mono and Dual Channel.
1.1317 +@internalComponent
1.1318 +@param aBitneed
1.1319 +Array of bitneed.
1.1320 +@param aBits
1.1321 +Bits allocated for each subbands
1.1322 +*/
1.1323 +void CSBCFrameEncoder::DistributeBitsIndependent(const TInt8 aBitneed[], TUint8 aBits[])
1.1324 + {
1.1325 + // see A2DP spec for reference
1.1326 + TInt bitCount = 0;
1.1327 + TInt8 bitSlices = CalcBitSlicesIndependent(aBitneed, bitCount);
1.1328 +
1.1329 + const TUint8 numSubbands = iParameters.Subbands();
1.1330 +
1.1331 + // distribute bits until the last bitslice is reached
1.1332 + TUint8 subband = 0;
1.1333 + for (; subband < numSubbands; subband++)
1.1334 + {
1.1335 + if (aBitneed[subband] < bitSlices + 2)
1.1336 + {
1.1337 + aBits[subband] = 0;
1.1338 + }
1.1339 + else
1.1340 + {
1.1341 + aBits[subband] = static_cast<TUint8>(Min(aBitneed[subband] - bitSlices, 16) );
1.1342 + }
1.1343 + }
1.1344 +
1.1345 + // distribute the remaining bits
1.1346 + const TUint8 bitpool = iParameters.Bitpool();
1.1347 +
1.1348 + subband = 0;
1.1349 + while (bitCount < bitpool && subband < numSubbands)
1.1350 + {
1.1351 + if (aBits[subband] >= 2 && aBits[subband] < 16)
1.1352 + {
1.1353 + aBits[subband]++;
1.1354 + bitCount++;
1.1355 + }
1.1356 + else if (aBitneed[subband] == bitSlices + 1 && bitpool > bitCount + 1)
1.1357 + {
1.1358 + aBits[subband] += 2; // ? bits[ch][sb] = 2 in A2DP spec, a bug in the spec?
1.1359 + bitCount += 2;
1.1360 + }
1.1361 + subband++;
1.1362 + }
1.1363 +
1.1364 + subband = 0;
1.1365 + while (bitCount < bitpool && subband < numSubbands)
1.1366 + {
1.1367 + if (aBits[subband] < 16)
1.1368 + {
1.1369 + aBits[subband]++;
1.1370 + bitCount++;
1.1371 + }
1.1372 + subband++;
1.1373 + }
1.1374 + }
1.1375 +
1.1376 +/**
1.1377 +This function calculates bit allocation for both channels for Stereo and Joint Stereo.
1.1378 +@internalComponent
1.1379 +*/
1.1380 +void CSBCFrameEncoder::CalcBitAllocCombined()
1.1381 + {
1.1382 + TInt8 bitneed[2][KSbcMaxSubbands];
1.1383 +
1.1384 + CalcBitneedCombined(bitneed);
1.1385 + DistributeBitsCombined(bitneed);
1.1386 + }
1.1387 +
1.1388 +/**
1.1389 +This function calculates bitneed for both channels for Stereo and Joint Stereo.
1.1390 +@internalComponent
1.1391 +@param aBitneed
1.1392 +Array of bitneed to hold the result
1.1393 +*/
1.1394 +void CSBCFrameEncoder::CalcBitneedCombined(TInt8 aBitneed[][KSbcMaxSubbands])
1.1395 + {
1.1396 + // see A2DP spec for reference
1.1397 + const TUint8 numSubbands = iParameters.Subbands();
1.1398 +
1.1399 + if (iParameters.AllocationMethod() == TSBCFrameParameters::ESNR)
1.1400 + {
1.1401 + for (TInt8 channel = 0; channel < 2; channel++)
1.1402 + {
1.1403 + const TUint8* scaleFactor = iScaleFactors[channel];
1.1404 + TInt8* bitneed = aBitneed[channel];
1.1405 + for (TInt8 subband = 0; subband < numSubbands; subband++)
1.1406 + {
1.1407 + *bitneed++ = *scaleFactor++;
1.1408 + }
1.1409 + }
1.1410 + }
1.1411 + else // Loudness
1.1412 + {
1.1413 + const TInt8* offset = NULL;
1.1414 + if (numSubbands == 4)
1.1415 + {
1.1416 + offset = KSBCOffset4[iParameters.SamplingFrequencyEnum()];
1.1417 + }
1.1418 + else
1.1419 + {
1.1420 + offset = KSBCOffset8[iParameters.SamplingFrequencyEnum()];
1.1421 + }
1.1422 +
1.1423 + for (TInt8 channel = 0; channel < 2; channel++)
1.1424 + {
1.1425 + const TUint8* scaleFactor = iScaleFactors[channel];
1.1426 + TInt8* bitneed = aBitneed[channel];
1.1427 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1428 + {
1.1429 + if (*scaleFactor == 0)
1.1430 + {
1.1431 + *bitneed = -5;
1.1432 + }
1.1433 + else if ( (*bitneed = static_cast<TUint8>(*scaleFactor - offset[subband]) ) > 0)
1.1434 + {
1.1435 + (*bitneed) >>= 1;
1.1436 + }
1.1437 + scaleFactor++;
1.1438 + bitneed++;
1.1439 + } // for subband
1.1440 + } // for channel
1.1441 + }
1.1442 + }
1.1443 +
1.1444 +/**
1.1445 +This function gets the maximum bitneed of both channels subbands for Stereo and Joint Stereo.
1.1446 +@internalComponent
1.1447 +@param aBitneed
1.1448 +Array of bitneed.
1.1449 +*/
1.1450 +TInt8 CSBCFrameEncoder::MaxBitneedCombined(const TInt8 aBitneed[][KSbcMaxSubbands])
1.1451 + {
1.1452 + // see A2DP spec for reference
1.1453 + TInt8 maxBitneed = 0;
1.1454 + const TUint8 numSubbands = iParameters.Subbands();
1.1455 +
1.1456 + for (TInt8 channel = 0; channel < 2; channel++)
1.1457 + {
1.1458 + const TInt8* bitneed = aBitneed[channel];
1.1459 + for (TInt8 subband = 0; subband < numSubbands; subband++)
1.1460 + {
1.1461 + if (*bitneed > maxBitneed)
1.1462 + {
1.1463 + maxBitneed = *bitneed;
1.1464 + }
1.1465 + bitneed++;
1.1466 + }
1.1467 + }
1.1468 + return maxBitneed;
1.1469 + }
1.1470 +
1.1471 +/**
1.1472 +This function calculates how many bitslices fit into the bitpool for both channels
1.1473 +for Stereo and Joint Stereo.
1.1474 +@internalComponent
1.1475 +@param aBitneed
1.1476 +Array of bitneed.
1.1477 +@param aBitCount
1.1478 +The bit count, counts how many bits used
1.1479 +@return the number of bitslices
1.1480 +*/
1.1481 +TInt8 CSBCFrameEncoder::CalcBitSlicesCombined(const TInt8 aBitneed[][KSbcMaxSubbands], TInt& aBitCount)
1.1482 + {
1.1483 + // see A2DP spec for reference
1.1484 + aBitCount = 0;
1.1485 + TInt8 sliceCount = 0;
1.1486 + TInt8 bitSlices = static_cast<TUint8>(MaxBitneedCombined(aBitneed) + 1);
1.1487 +
1.1488 + const TUint8 numSubbands = iParameters.Subbands();
1.1489 + const TUint8 bitpool = iParameters.Bitpool();
1.1490 +
1.1491 + do {
1.1492 + bitSlices--;
1.1493 + aBitCount += sliceCount;
1.1494 + sliceCount = 0;
1.1495 +
1.1496 + for (TInt8 channel = 0; channel < 2; channel++)
1.1497 + {
1.1498 + const TInt8* bitneed = aBitneed[channel];
1.1499 + for (TInt8 subband = 0; subband < numSubbands; subband++)
1.1500 + {
1.1501 + if (*bitneed > bitSlices + 1 && *bitneed < bitSlices + 16)
1.1502 + {
1.1503 + sliceCount++;
1.1504 + }
1.1505 + else if (*bitneed == bitSlices + 1)
1.1506 + {
1.1507 + sliceCount += 2;
1.1508 + }
1.1509 + bitneed++;
1.1510 + }
1.1511 + }
1.1512 + } while (aBitCount + sliceCount < bitpool);
1.1513 +
1.1514 + if (aBitCount + sliceCount == bitpool)
1.1515 + {
1.1516 + aBitCount += sliceCount;
1.1517 + bitSlices--;
1.1518 + }
1.1519 +
1.1520 + return bitSlices;
1.1521 + }
1.1522 +
1.1523 +/**
1.1524 +This function distributes number of bits to each subband for all samples
1.1525 +for Stereo and Joint Stereo.
1.1526 +@internalComponent
1.1527 +@param aBitneed
1.1528 +Array of bitneed.
1.1529 +*/
1.1530 +void CSBCFrameEncoder::DistributeBitsCombined(const TInt8 aBitneed[][KSbcMaxSubbands])
1.1531 + {
1.1532 + // see A2DP spec for reference
1.1533 + TInt bitCount = 0;
1.1534 + TInt bitSlices = CalcBitSlicesCombined(aBitneed, bitCount);
1.1535 +
1.1536 + const TUint8 numSubbands = iParameters.Subbands();
1.1537 + const TUint8 bitpool = iParameters.Bitpool();
1.1538 +
1.1539 + // distribute bits until the last bitslice is reached
1.1540 + TInt8 channel = 0;
1.1541 + TInt8 subband = 0;
1.1542 + for (; channel < 2; channel++)
1.1543 + {
1.1544 + const TInt8* bitneed = aBitneed[channel];
1.1545 + TUint8* bits = iBits[channel];
1.1546 + for (subband = 0; subband < numSubbands; subband++)
1.1547 + {
1.1548 + if (*bitneed < bitSlices + 2)
1.1549 + {
1.1550 + *bits = 0;
1.1551 + }
1.1552 + else
1.1553 + {
1.1554 + *bits = static_cast<TUint8>(Min(*bitneed - bitSlices, 16) );
1.1555 + }
1.1556 + bitneed++;
1.1557 + bits++;
1.1558 + }
1.1559 + }
1.1560 +
1.1561 + // distribute the remaining bits
1.1562 + channel = 0;
1.1563 + subband = 0;
1.1564 + while (bitCount < bitpool && subband < numSubbands)
1.1565 + {
1.1566 + TUint8& bits = iBits[channel][subband];
1.1567 + if (bits >= 2 && bits < 16)
1.1568 + {
1.1569 + bits++;
1.1570 + bitCount++;
1.1571 + }
1.1572 + else if (aBitneed[channel][subband] == bitSlices + 1 && bitpool > bitCount + 1)
1.1573 + {
1.1574 + bits += 2; // ? bits[ch][sb] = 2 in A2DP spec, a bug in the spec?
1.1575 + bitCount += 2;
1.1576 + }
1.1577 +
1.1578 + if (channel == 1)
1.1579 + {
1.1580 + channel = 0;
1.1581 + subband++;
1.1582 + }
1.1583 + else
1.1584 + {
1.1585 + channel = 1;
1.1586 + }
1.1587 + }
1.1588 +
1.1589 + channel = 0;
1.1590 + subband = 0;
1.1591 + while (bitCount < bitpool && subband < numSubbands)
1.1592 + {
1.1593 + TUint8& bits = iBits[channel][subband];
1.1594 + if (bits < 16)
1.1595 + {
1.1596 + bits++;
1.1597 + bitCount++;
1.1598 + }
1.1599 +
1.1600 + if (channel == 1)
1.1601 + {
1.1602 + channel = 0 ;
1.1603 + subband++;
1.1604 + }
1.1605 + else
1.1606 + {
1.1607 + channel = 1;
1.1608 + }
1.1609 + }
1.1610 + }
1.1611 +
1.1612 +/**
1.1613 +This function calculates the CRC code for sbc frame.
1.1614 +@internalComponent
1.1615 +@return sbc CRC value
1.1616 +*/
1.1617 +TUint8 CSBCFrameEncoder::CalcCRC()
1.1618 + {
1.1619 + CSbcCRCCalculator crc;
1.1620 +
1.1621 + crc.InputByte(iParameters.Parameters() ); // 5 parameters
1.1622 + crc.InputByte(iParameters.Bitpool() ); // bitpool
1.1623 +
1.1624 + // join[] & RFA bits
1.1625 + const TUint8 numSubbands = iParameters.Subbands();
1.1626 + if (iParameters.ChannelMode() == TSBCFrameParameters::EJointStereo)
1.1627 + {
1.1628 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1629 + {
1.1630 + crc.InputBit(iJoin[subband]);
1.1631 + }
1.1632 + }
1.1633 +
1.1634 + // scale factors
1.1635 + const TUint8 numChannels = iParameters.Channels();
1.1636 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.1637 + {
1.1638 + const TUint8* scaleFactors = iScaleFactors[channel];
1.1639 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1640 + {
1.1641 + crc.InputBits(4, *scaleFactors++);
1.1642 + }
1.1643 + }
1.1644 +
1.1645 + return crc.ShiftRegister();
1.1646 + }
1.1647 +
1.1648 +/**
1.1649 +This function outputs the encoded sbc frame into the destination buffer.
1.1650 +@internalComponent
1.1651 +@param aFrame
1.1652 +The destination buffer
1.1653 +@leave if out of memory
1.1654 +*/
1.1655 +void CSBCFrameEncoder::WriteFrameL(TDes8& aFrame)
1.1656 + {
1.1657 + CBitStreamParser* parser = CBitStreamParser::NewLC(aFrame);
1.1658 +
1.1659 + WriteHeader(*parser);
1.1660 + WriteScaleFactors(*parser);
1.1661 + WriteData(*parser);
1.1662 + WritePaddingL(*parser);
1.1663 +
1.1664 + CleanupStack::PopAndDestroy(parser);
1.1665 + }
1.1666 +
1.1667 +/**
1.1668 +This function writes the sbc frame header into the destination buffer.
1.1669 +@internalComponent
1.1670 +@param aParser
1.1671 +The bit stream parser which manipulates the destination buffer bit stream
1.1672 +*/
1.1673 +void CSBCFrameEncoder::WriteHeader(CBitStreamParser& aParser)
1.1674 + {
1.1675 + // syncword
1.1676 + aParser.WriteByte(KSBCFrameSyncWord);
1.1677 + // sampling frequency, blocklength, channel mode, allocatin method, subbands
1.1678 + aParser.WriteByte(iParameters.Parameters() );
1.1679 + // bitpool
1.1680 + aParser.WriteByte(iParameters.Bitpool() );
1.1681 + // crc check
1.1682 + aParser.WriteByte(CalcCRC() );
1.1683 +
1.1684 + if (iParameters.ChannelMode() == TSBCFrameParameters::EJointStereo)
1.1685 + {
1.1686 + // join[] & RFA
1.1687 + const TUint8 numSubbands = iParameters.Subbands();
1.1688 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1689 + {
1.1690 + aParser.WriteBits(1, iJoin[subband]);
1.1691 + }
1.1692 + }
1.1693 + }
1.1694 +
1.1695 +/**
1.1696 +This function writes the sbc frame scale factors into the destination buffer.
1.1697 +@internalComponent
1.1698 +@param aParser
1.1699 +The bit stream parser which manipulates the destination buffer bit stream
1.1700 +*/
1.1701 +void CSBCFrameEncoder::WriteScaleFactors(CBitStreamParser& aParser)
1.1702 + {
1.1703 + const TUint8 numChannels = iParameters.Channels();
1.1704 + const TUint8 numSubbands = iParameters.Subbands();
1.1705 +
1.1706 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.1707 + {
1.1708 + const TUint8* scaleFactors = iScaleFactors[channel];
1.1709 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1710 + {
1.1711 + aParser.WriteBits(4, *scaleFactors++);
1.1712 + }
1.1713 + }
1.1714 + }
1.1715 +
1.1716 +/**
1.1717 +This function writes one sbc subband sample into the destination buffer.
1.1718 +@internalComponent
1.1719 +@param aParser
1.1720 +The bit stream parser which manipulates the destination buffer bit stream
1.1721 +@param aBits
1.1722 +The number of bits to write
1.1723 +@param aSample
1.1724 +The sample value to write
1.1725 +*/
1.1726 +static void WriteOneSample(CBitStreamParser& aParser, TUint8 aBits, TInt32 aSample)
1.1727 + {
1.1728 + if (aBits >= 8)
1.1729 + {
1.1730 + aBits -= 8;
1.1731 + aParser.WriteByte(static_cast<TUint8>( (aSample >> aBits) & 0xff) );
1.1732 + }
1.1733 + if (aBits > 0)
1.1734 + {
1.1735 + aParser.WriteBits(aBits, static_cast<TUint8>(aSample & 0xff) );
1.1736 + }
1.1737 + }
1.1738 +
1.1739 +/**
1.1740 +This function writes the sbc frame data into the destination buffer.
1.1741 +@internalComponent
1.1742 +@param aParser
1.1743 +The bit stream parser which manipulates the destination buffer bit stream
1.1744 +*/
1.1745 +void CSBCFrameEncoder::WriteData(CBitStreamParser& aParser)
1.1746 + {
1.1747 + const TUint8 numBlocks = iParameters.BlockLength();
1.1748 + const TUint8 numChannels = iParameters.Channels();
1.1749 + const TUint8 numSubbands = iParameters.Subbands();
1.1750 +
1.1751 + for (TUint8 block = 0; block < numBlocks; block++)
1.1752 + {
1.1753 + for (TUint8 channel = 0; channel < numChannels; channel++)
1.1754 + {
1.1755 + const TUint8* bits = iBits[channel];
1.1756 + const TInt32* samples = iOutputSamples[block][channel];
1.1757 +
1.1758 + for (TUint8 subband = 0; subband < numSubbands; subband++)
1.1759 + {
1.1760 + if (*bits > 0)
1.1761 + {
1.1762 + WriteOneSample(aParser, *bits, *samples);
1.1763 + }
1.1764 + bits++;
1.1765 + samples++;
1.1766 + }
1.1767 + }
1.1768 + }
1.1769 + }
1.1770 +
1.1771 +/**
1.1772 +This function writes the sbc frame padding bits into the destination buffer.
1.1773 +@internalComponent
1.1774 +@param aParser
1.1775 +The bit stream parser which manipulates the destination buffer bit stream
1.1776 +@panic if output frame length is not the same as expected
1.1777 +*/
1.1778 +void CSBCFrameEncoder::WritePaddingL(CBitStreamParser& aParser)
1.1779 + {
1.1780 + TUint byteOffset;
1.1781 + TUint8 bitOffset;
1.1782 +
1.1783 + aParser.Position(byteOffset, bitOffset);
1.1784 +
1.1785 + if (bitOffset != 0)
1.1786 + {
1.1787 + aParser.WriteBits(8 - bitOffset, 0);
1.1788 + byteOffset++;
1.1789 + }
1.1790 +
1.1791 + if (byteOffset != iParameters.CalcFrameLength() )
1.1792 + {
1.1793 + User::Leave(KErrCorrupt);
1.1794 + }
1.1795 + }