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