diff -r 000000000000 -r f63038272f30 bluetoothengine/btsac/src/btsacStreamerController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btsac/src/btsacStreamerController.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -0,0 +1,1358 @@ +/* +* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Implementation for CBTSACStreamerController class. This class constructs and +* communicates with 'BT Audio Streamer' component to do RTP streaming. +* +*/ + + +// INCLUDE FILES +#include "btsacStreamerController.h" +#include "debug.h" + +// Subband codec-specific values +// in bluetoothAV.h +using namespace SymbianSBC; + + +// CONSTANTS +_LIT(KBTAADLL, "btaudioadaptation.dll"); + +//const TInt KUpgradeTimerDelay = 120000000; // 2 minutes. How often we sill try to upgrade back to a better quality audio. +const TInt KRetryTimerDelay = 2000000; // 2 seconds. If something fails, how soon should we retry. +const TInt KStabilizationDelay = 2000000; // 2 seconds. Wait this long after bitpool change then start mononitor packet drops again +const TInt KDataCollectDelay = 600000; // Time (600ms) to collect packet drop data + +// All tables below have to formed such a way that highest max bitpool value has to be in position 0 and etc. +const TInt KMaxBitpoolValues[] = {59, 48, 40, 34}; // Max bitpool values +const TInt KDeviationValues[] = {1000, 100000, 300000, 300000}; // maximum time (ys) between first and last packet dropped event + +const TInt KNumOfBitpoolValues = sizeof(KMaxBitpoolValues)/sizeof(TInt); +#define MAXBITPOOLVALUEMAX KMaxBitpoolValues[0] +#define MAXBITPOOLVALUEMIN KMaxBitpoolValues[KNumOfBitpoolValues-1] + +const float KReconfigureLimitFactor = 0.02; // 2% of during KDataCollectDelay transferred data +const float KLimitCheckInterval = ((float)KDataCollectDelay/1000000.0); // Time (seconds) to collect packet drop data + +// MODULE DATA STRUCTURES + +// ================= MEMBER FUNCTIONS ======================= + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CBTSACStreamerController* CBTSACStreamerController::NewL(MBTAudioAdaptationObserver& aObserver ) + { + CBTSACStreamerController* self = new (ELeave) CBTSACStreamerController (aObserver); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +// ----------------------------------------------------------------------------- +// Destructor. +// ----------------------------------------------------------------------------- +// +CBTSACStreamerController::~CBTSACStreamerController() + { + TRACE_FUNC + Cancel(); + if(iAudioInput) + { + iAudioInput->Stop(); + iAudioInput->Disconnect(); + } + delete iPacketDropIoctl; + delete iEncoderCI; + delete iBTStreamer; + delete iAudioInput; + iLib.Close(); + iTimer.Close(); + iBitpoolData.Close(); + TRACE_INFO((_L("CBTSACStreamerController::~CBTSACStreamerController() completed"))) + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::CBTSACStreamerController +// C++ default constructor. +// ----------------------------------------------------------------------------- +// +CBTSACStreamerController::CBTSACStreamerController(MBTAudioAdaptationObserver& aObserver) + : CActive( EPriorityNormal ), iObserver(aObserver) + { + CActiveScheduler::Add(this); + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::ConstructL +// Symbian 2nd phase constructor. +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::ConstructL( ) + { + TRACE_FUNC + + User::LeaveIfError(iTimer.CreateLocal()); + iThread = RThread(); + + iBTStreamer = CBTAudioStreamer::NewL(); + + LEAVE_IF_ERROR( iLib.Load( KBTAADLL ) ); + typedef TInt (*TOurLibraryFunction2)(MBTAudioStreamObserver&, MBTAudioErrorObserver&); + TOurLibraryFunction2 newL2 = reinterpret_cast(iLib.Lookup(1)); + iAudioInput = (CBTAudioStreamInputBase*)newL2(*iBTStreamer, *this); + + TInt ret; + ret = iAudioInput->Connect(); + if (ret) + { + TRACE_INFO((_L("CBTSACStreamerController::ConstructL() Audio Input Connect Error %d"), ret)) + User::Leave(ret); + } + + ret = iAudioInput->SetFormat(KMMFFourCCCodeSBC); + if (ret) + { + TRACE_INFO((_L("CBTSACStreamerController::ConstructL() Audio Input SetFormat Error %d"), ret)) + User::Leave(ret); + } + + iEncoderCI = reinterpret_cast (iAudioInput->EncoderInterface(KUidSbcEncoderIntfc)); + User::LeaveIfNull(iEncoderCI); + + InitializeBitpoolDataL(); + iState = EStateIdle; + + TRACE_INFO((_L("CBTSACStreamerController::ConstructL() completed"))) + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::StartStream +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::StartStream(RSocket& aSocket, TInt aFrameLength ) + { + TRACE_FUNC + + if (!(iBTStreamer) || !(iAudioInput) ) + { + return KErrNotFound; + } + + if (iState == EStateError) + { + iState = EStateIdle; + TInt err = iAudioInput->Connect(); + if (!err) + { + err = iAudioInput->SetFormat(KMMFFourCCCodeSBC); + } + if (err) + { + TRACE_INFO((_L("CBTSACStreamerController::StartStream() Audio Input initialization Error %d"), err)) + return err; + } + } + + if (iState == EStateIdle) + { + TInt err = KErrNone; + TRAP( err, iBTStreamer->StartL(aSocket, aFrameLength, iAudioInput, iCurrentBitrate)); + + if ( err == KErrNone ) + { + err = iAudioInput->Start(); + } + + if ( err == KErrNone ) + { + TRACE_INFO((_L("CBTSACStreamerController::StartStream() Sending packet drop IOCTL"))) + TRAP( err, iPacketDropIoctl = CActivePacketDropIoctl::NewL(*this, aSocket)); + + if( err == KErrNone ) + { + iPacketDropDeviation = 0; + iTotalNbrOfDroppedPackets = 0; + iState = EStateStreaming; + + if(iCurrentBitpoolData->iMaxBitpoolValue < iMatchCap.MaxBitpoolValue()) + { + TRACE_INFO((_L("CBTSACStreamerController::StartStream(), upgrade bitrate."))) + // Streaming was stopped when the bitrate was lower than maximum, so upgrade it for starters. + // iPacketDropIoctl->Start will be called after self completion. + + // Update current bitpool data to be highest possible. Highest possible bitpool value can be found from position + iCurrentBitpoolData = GetBitpoolData(0); + if(iCurrentBitpoolData) + { + DoSelfComplete(EUpgradeBitrate, KErrNone); + } + else + { + err = KErrArgument; + } + } + else if(iMatchCap.MaxBitpoolValue() > iBitpoolData[iBitpoolData.Count() - 1].iMaxBitpoolValue) + { + // Don't start receive packet drop events if max bitpool value is not bigger than min + // bitpool value (we can't downgrade bitpool, we already have lowest possible value). + DoSelfComplete(EStartStabilizingTimer, KErrNone); + } + TRACE_INFO((_L("CBTSACStreamerController::StartStream() completed"))) + } + } + if( err ) + { + // In case someting went wrong stop both audio adaptation and streamer + TRACE_INFO((_L("CBTSACStreamerController::StartStream() *Error: %d"), err)) + iAudioInput->Stop(); + iAudioInput->Disconnect(); + iBTStreamer->Stop(); + + //make sure iAudioInput->Connect() & SetFormat() get called in StartStream() + iState = EStateError; + } + return err; + } + else + { + return KErrAlreadyExists; + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::StopStream +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::StopStream() + { + TRACE_FUNC + Cancel(); + if (!(iBTStreamer) || !(iAudioInput)) + { + return KErrNotFound; + } + else if (iState != EStateIdle ) + { + iAudioInput->Stop(); + iBTStreamer->Stop(); + delete iPacketDropIoctl; + iPacketDropIoctl = NULL; + iState = EStateIdle; + return KErrNone; + } + else + { + return KErrAlreadyExists; + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::ResetAudioInput +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::ResetAudioInput() + { + TRACE_FUNC + iAudioInput->Stop(); + iAudioInput->Disconnect(); + TInt err = iAudioInput->Connect(); + if (!err) + { + err = iAudioInput->SetFormat(KMMFFourCCCodeSBC); + } + if (err) + { + TRACE_INFO((_L("CBTSACStreamerController::ResetAudioInput() Audio Input initialization Error %d"), err)) + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::FillCapabilities +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::FillCapabilities( TSBCCodecCapabilities& aSbc ) + { + TRACE_FUNC + + TUint8 itemp = 0x00; + // Sampling Frequency + TInt ret; + RArray SupportedSamplingFrequencies; + ret = iEncoderCI->GetSupportedSamplingFrequencies(SupportedSamplingFrequencies); + if ( !ret) + { + itemp = 0x00; + + for (TInt i=0; i SupportedChannelModes; + ret = iEncoderCI->GetSupportedChannelModes(SupportedChannelModes); + if ( !ret ) + { + itemp = 0x00; + + for (TInt i=0; i SupportedNumOfBlocks; + ret = iEncoderCI->GetSupportedNumOfBlocks(SupportedNumOfBlocks); + if ( !ret ) + { + itemp = 0x00; + + for (TInt i=0; i SupportedNumOfSubbands; + ret = iEncoderCI->GetSupportedNumOfSubbands(SupportedNumOfSubbands); + if ( !ret ) + { + itemp = 0x0; + for (TInt i=0; i SupportedAllocationMethods; + ret = iEncoderCI->GetSupportedAllocationMethods(SupportedAllocationMethods); + if ( !ret ) + { + itemp = 0x0; + for (TInt i=0; iGetSupportedBitpoolRange(MinSupportedBitpoolSize, + MaxSupportedBitpoolSize); + if ( !ret ) + { + if (MaxSupportedBitpoolSize > MAXBITPOOLVALUEMAX) + { + MaxSupportedBitpoolSize = MAXBITPOOLVALUEMAX; + } + // TUint8 to TInt + aSbc.SetMaxBitpoolValue(MaxSupportedBitpoolSize); + TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Max bitpool: %d"), MaxSupportedBitpoolSize)) + aSbc.SetMinBitpoolValue(MinSupportedBitpoolSize); + TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Encoder Min bitpool: %d"), MinSupportedBitpoolSize)) + } + else + { + return ret; + } + + // save our local copy, 9 bytes on stack + iLocalCap = aSbc; + + TRACE_INFO((_L("CBTSACStreamerController::FillCapabilities() Return: %d"), ret)); + return ret; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::ConfigureSEP +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::ConfigureSEP( TSBCCodecCapabilities& aDec ) + { + TRACE_FUNC + TInt err = KErrNone; + TRAP(err, InitializeBitpoolDataL()); + if(err) + return err; + + err = GetMatchingCaps(aDec); + if(!err) + { + CheckAndAdjustBitpool(aDec); + // Save the matching Caps + iMatchCap = aDec; + ReorganizeBitpoolTable(iMatchCap.MaxBitpoolValue()); + err = SetCurrentBitpoolData(iMatchCap.MaxBitpoolValue()); + if(!err) + { + iEncoderCI->SetBitpoolSize(iMatchCap.MaxBitpoolValue()); + // configure encoder + err = iEncoderCI->ApplyConfig(); + } + } + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEP() return: %d"), err)) + return err; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::ConfigureSEPBitpool +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::ConfigureSEPBitpool(EOngoingAction aAction) + { + TRACE_FUNC + TInt err = KErrNone; + TSBCCodecCapabilities newDecConfiguration; + memset(&newDecConfiguration, 0, sizeof(newDecConfiguration)); + newDecConfiguration = iMatchCap; + TInt nextIndex = (aAction == EDowngradeBitrate) ? iCurrentBitpoolData->iDownBitpoolIndex : iCurrentBitpoolData->iUpBitpoolIndex; + if(!IndexValid(nextIndex)) + { + return KErrArgument; + } + TInt BitpoolValue = iBitpoolData[nextIndex].iMaxBitpoolValue; + newDecConfiguration.SetMaxBitpoolValue(BitpoolValue); + CheckAndAdjustBitpool(newDecConfiguration); + + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() Current FrameLength: %d"), iCurrentFrameLength)) + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() Current Bitrate: %d"), iCurrentBitrate)) + + err = iBTStreamer->SetNewFrameLength(iCurrentFrameLength, iCurrentBitrate); + if(!err) + { + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool(), Reconfiguring the encoder..."))) + iEncoderCI->SetBitpoolSize(newDecConfiguration.MaxBitpoolValue()); + // configure encoder + err = iEncoderCI->ApplyConfig(); + if(!err) + { + err = SetCurrentBitpoolData(newDecConfiguration.MaxBitpoolValue()); + if(!err) + { + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool(): Current BP: %d"), iCurrentBitpoolData->iMaxBitpoolValue)) + } + } + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() The encoder reconfigured."))) + } + TRACE_INFO((_L("CBTSACStreamerController::ConfigureSEPBitpool() return: %d"), err)) + return err; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::FrameLength +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::FrameLength() const + { + TRACE_INFO((_L("CBTSACStreamerController::FrameLength() = %d"), iCurrentFrameLength)) + return iCurrentFrameLength; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetMatchingCaps +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::GetMatchingCaps(TSBCCodecCapabilities& aCaps) + { + TRACE_FUNC + TInt ret = KErrNone; + TUint8 MatchingFreq, MatchingChnl, MatchingBlck, MatchingSub, MatchingAlloc; + + MatchingFreq = (iLocalCap.SamplingFrequencies() & aCaps.SamplingFrequencies()); + MatchingChnl = (iLocalCap.ChannelModes() & aCaps.ChannelModes()); + MatchingBlck = (iLocalCap.BlockLengths() & aCaps.BlockLengths()); + MatchingSub = (iLocalCap.Subbands() & aCaps.Subbands()); + MatchingAlloc = (iLocalCap.AllocationMethods() & aCaps.AllocationMethods()); + + if ( MatchingFreq && + MatchingChnl && + MatchingBlck && + MatchingSub && + MatchingAlloc && + ( iLocalCap.MinBitpoolValue() <= aCaps.MaxBitpoolValue() ) && + ( iLocalCap.MaxBitpoolValue() >= aCaps.MinBitpoolValue() ) ) + { + TRACE_INFO((_L("CBTSACStreamerController::GetMatchingCaps() accessory configuration suits us"))) + + // Choose highest possible values that are supported + + // Sampling Frequency + SetSamplingFrequency(aCaps, MatchingFreq); + // Channel mode + SetChannelMode(aCaps, MatchingChnl); + // Blocks + SetBlockLen(aCaps, MatchingBlck); + // Subbands + SetNumOfSubbands(aCaps, MatchingSub); + // Allocation method + SetAllocationMethod(aCaps, MatchingAlloc); + // Bitpool + SetBitpoolValues(aCaps); + } + else // no match + { + TRACE_INFO((_L("CBTSACStreamerController::GetMatchingCaps() **No Matching Capabilities**"))) + ret = KErrNotFound; + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::CheckAndAdjustBitpool +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::CheckAndAdjustBitpool(TSBCCodecCapabilities& aCap) + { + TRACE_FUNC + // ******* Adjust bitpool if necessary ***** + TInt targetbitrate; + TInt nChnls = GetNumOfChannels(aCap); + TInt nSbands = GetNumOfSubbands(aCap); + TInt nBlck = GetBlockLen(aCap); + TInt Freq = GetSamplingFrequency(aCap); + TInt frameLength = FrameLengthFormula(aCap); + // Note: this is the bitrate of the transmission. + TInt bitrateInt = 8 * frameLength * Freq / nSbands / nBlck; + + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), nChnls = %d"), nChnls)) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), nSbands = %d"), nSbands)) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), nBlck = %d"), nBlck)) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), Freq = %d"), Freq)) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), MaxBP = %d"), aCap.MaxBitpoolValue())) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), Frame length = %d"), frameLength)) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), Bitrate = %d"), bitrateInt)) + + // max bit rate: 320kb/s for mono, + // 512kb/s for two-channel modes + if (aCap.ChannelModes() & EMono) + { + if (bitrateInt <= 320000.0) + { + targetbitrate = bitrateInt; + } + else // target bitrate=320kbps + { + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool() Adjusting..."))) + targetbitrate = 320000.0; + TInt BP = ( ((targetbitrate*nSbands*nBlck)/Freq) - 32 - (4*nSbands*nChnls) ) / (nBlck*nChnls); + aCap.SetMaxBitpoolValue(BP); + } + } + else + { + if (bitrateInt <= 512000.0) + { + targetbitrate = bitrateInt; + } + else // target bitrate=512kbps + { + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool() Adjusting..."))) + targetbitrate = 512000.0; + TInt BP = 0; + if (aCap.ChannelModes() & EDualChannel) + { + BP = ( ((targetbitrate*nSbands*nBlck)/Freq) - 32 - (4*nSbands*nChnls) ) / (nBlck*nChnls); + } + else + { + TInt join = (aCap.ChannelModes() & EJointStereo) ? 1 : 0; + BP = ( ((targetbitrate*nSbands*nBlck)/Freq) - 32 - (4*nSbands*nChnls) - (nSbands*join) ) / (nBlck); + } + + aCap.SetMaxBitpoolValue(BP); + // Calculate new frame length + frameLength = FrameLengthFormula(aCap); + } + } + + iCurrentFrameLength = frameLength; + iCurrentBitrate = targetbitrate; + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), After Adjustment MaxBP: %d"), aCap.MaxBitpoolValue())) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), After Adjustment Frame length: %d"), iCurrentFrameLength)) + TRACE_INFO((_L("CBTSACStreamerController::CheckAndAdjustBitpool(), After Adjustment Bitrate: %d"), iCurrentBitrate)) + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::RunL +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::RunL() + { + TRACE_FUNC + switch(iStatus.Int()) + { + case KErrNone: + { + switch( iOngoingAction ) + { + case EErrorSending: + { + TRACE_INFO((_L("CBTSACStreamerController::RunL(), ErrorSending"))) + + TRACE_INFO((_L("CBTSACStreamerController::RunL(), TotalNbrOfDroppedPackets: %d"), iTotalNbrOfDroppedPackets)) + TInt TotalNbrOfDroppedBits = iTotalNbrOfDroppedPackets*8; + TRACE_INFO((_L("CBTSACStreamerController::RunL(), Total dropped bits: %d"), TotalNbrOfDroppedBits)) + TRACE_INFO((_L("CBTSACStreamerController::RunL(), Current Bitrate: %d"), iCurrentBitrate)) + TInt ReconfigureLimit = KLimitCheckInterval*iCurrentBitrate*KReconfigureLimitFactor; + TRACE_INFO((_L("CBTSACStreamerController::RunL(), Limit for reconfigure : %d bits"), ReconfigureLimit)) + TRACE_INFO((_L("CBTSACStreamerController::RunL(), PacketDropDeviation: %d (limit %d)"), iPacketDropDeviation, iCurrentBitpoolData->iMaxDeviation)) + + if((TotalNbrOfDroppedBits > ReconfigureLimit) && (iPacketDropDeviation >= iCurrentBitpoolData->iMaxDeviation)) + { + iPacketDropIoctl->Cancel(); + + if(iCurrentBitpoolData->iMinimumMaxBitpool) + { + TRACE_INFO((_L("CBTSACStreamerController::RunL(), Minimum max bitpool reached."))) + TRACE_INFO((_L("CBTSACStreamerController::RunL(), Stop receive packet drops."))) + return; + } + + // Initialize values for upgrade timer. Only if setting min bitpool value fails, start retry timer. + TInt delay = KStabilizationDelay; + iOngoingAction = EStabilize; + TInt err = ConfigureSEPBitpool(EDowngradeBitrate); + if(err) + { + iOngoingAction = EDowngradeBitrate; + delay = KRetryTimerDelay; + } + + iTimer.After(iStatus, delay); + SetActive(); + } + + iPacketDropDeviation = 0; + iTotalNbrOfDroppedPackets = 0; + break; + } + + case EStabilize: + // Start receive overflow indications again + TRACE_INFO((_L("CBTSACStreamerController::RunL(), stabilize timer expired."))) + iPacketDropIoctl->Start(); + break; + + case EDowngradeBitrate: + case EUpgradeBitrate: + case EStartStabilizingTimer: + { + TRACE_INFO((_L("CBTSACStreamerController::RunL(), Action = %d"), iOngoingAction)) + TInt err = KErrNone; + TInt delay = KStabilizationDelay; + if(iOngoingAction != EStartStabilizingTimer) + { + err = ConfigureSEPBitpool(iOngoingAction); + } + if(err) + { + delay = KRetryTimerDelay; + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::RunL(), stabilize timer started"))) + iOngoingAction = EStabilize; + } + + iTimer.After(iStatus, delay); + SetActive(); + break; + } + } + break; + } + + case KErrGeneral: // We have received error from audio adaptation + { + TRACE_INFO((_L("CBTSACStreamerController::RunL(), KErrGeneral"))) + iAudioInput->Stop(); + iAudioInput->Disconnect(); + iObserver.NotifyError(KErrGeneral); + break; + } + + default: + TRACE_INFO((_L("CBTSACStreamerController::RunL(), #default"))) + break; + } + TRACE_INFO((_L("CBTSACStreamerController::RunL() completed"))) + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::DoCancel +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::DoCancel() + { + TRACE_FUNC + iTimer.Cancel(); + TRACE_INFO((_L("CBTSACStreamerController::DoCancel() completed"))) + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::RunError +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::RunError(TInt /*aError*/) + { + TRACE_FUNC + return 0; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::Error +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::Error(const TInt aError) + { + TRACE_INFO((_L("CBTSACStreamerController::Error() %d"), aError)) + TInt ret = KErrNone; + switch(aError) + { + case KErrOverflow: + case KErrUnderflow: + { + DoSelfComplete(EErrorSending, KErrNone); + break; + } + case KErrGeneral: + { + if(iState != EStateError) + { + iState = EStateError; + DoSelfComplete(iOngoingAction, KErrGeneral); + } + break; + } + default: + { + ret = KErrUnknown; + break; + } + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetCaps +// ----------------------------------------------------------------------------- +// +TSBCCodecCapabilities& CBTSACStreamerController::GetCaps() + { + return iLocalCap; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetBlockLen +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::SetBlockLen(TSBCCodecCapabilities& aCap, TUint8 aBlockLen) + { + // Set Block Lenght, select highest one + if ( aBlockLen & EBlockLenSixteen ) + { + iEncoderCI->SetNumOfBlocks(TUint(16)); + aCap.SetBlockLengths(EBlockLenSixteen); + TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenSixteen"))) + } + else if ( aBlockLen & EBlockLenTwelve ) + { + iEncoderCI->SetNumOfBlocks(TUint(12)); + aCap.SetBlockLengths(EBlockLenTwelve); + TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenTwelve"))) + } + else if ( aBlockLen & EBlockLenEight ) + { + iEncoderCI->SetNumOfBlocks(TUint(8)); + aCap.SetBlockLengths(EBlockLenEight); + TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenEight"))) + } + else if ( aBlockLen & EBlockLenFour ) + { + iEncoderCI->SetNumOfBlocks(TUint(4)); + aCap.SetBlockLengths(EBlockLenFour); + TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), BlockLength: EBlockLenFour"))) + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::SetBlockLen(), No matching Block Length"))) + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetBlockLen +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::GetBlockLen(TSBCCodecCapabilities& aCap) const + { + TInt nBlck = 0; + switch( aCap.BlockLengths() ) + { + case EBlockLenSixteen: + nBlck = 16; + break; + case EBlockLenTwelve: + nBlck = 12; + break; + case EBlockLenEight: + nBlck = 8; + break; + case EBlockLenFour: + nBlck = 4; + break; + default: + TRACE_INFO((_L("CBTSACStreamerController::GetBlockLen(), #default"))) + nBlck = 16; + break; + } + return nBlck; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetBitpoolValues +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::SetBitpoolValues(TSBCCodecCapabilities& aCap) + { + // Define max bitpool + TInt MaxBP = 0; + TBool ProperMaxBitpoolFound = EFalse; + for(TInt i = 0 ; i < KNumOfBitpoolValues ; i++) + { + if(aCap.MaxBitpoolValue() >= KMaxBitpoolValues[i]) + { + MaxBP = KMaxBitpoolValues[i]; + ProperMaxBitpoolFound = ETrue; + break; + } + } + if(!ProperMaxBitpoolFound) + { + // None of our proposed max bitpool values weren't suitable for accessory. + // Let's use the one which was proposed by the accessory. + MaxBP = aCap.MaxBitpoolValue(); + } + + // Define min bitpool. This bitpool value is negotiated with sink. + TInt MinBP = (iLocalCap.MinBitpoolValue() < aCap.MinBitpoolValue()) ? aCap.MinBitpoolValue() : iLocalCap.MinBitpoolValue(); + + // Define bitpool which is used for medium quality streaming (when streaming is interfered for some reason). + // This is real lowest bitpool value which is used for streaming. + + // Check if selected max bitpool value is smaller than our default min bitpool value, if it is, set + // minimum max bitpool value to be same as max value otherwise just update it with our default min value. + if(MaxBP < MAXBITPOOLVALUEMIN) + { + // Update the minumum bitpool data + iBitpoolData[iBitpoolData.Count()-1].iMaxBitpoolValue = MaxBP; + } + else if(MAXBITPOOLVALUEMIN < MinBP) // Check also that minimum max bitpool value is not smaller than bitpool which is negotiated for the link. + { + iBitpoolData[iBitpoolData.Count()-1].iMaxBitpoolValue = MinBP; + } + + TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Remote Max Bitpool: %d"), aCap.MaxBitpoolValue())) + TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Remote Min Bitpool: %d"), aCap.MinBitpoolValue())) + + aCap.SetMaxBitpoolValue(MaxBP); + TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Max Bitpool: %d"), MaxBP)) + aCap.SetMinBitpoolValue(MinBP); + TRACE_INFO((_L("CBTSACStreamerController::SetBitpoolValues(), Min Bitpool: %d"), MinBP)) + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetAllocationMethod +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::SetAllocationMethod(TSBCCodecCapabilities& aCap, TUint8 aAllocationMethod) + { + // Set Allocation Method, select highest one + if ( aAllocationMethod & ELoudness ) + { + iEncoderCI->SetAllocationMethod(CSbcEncoderIntfc::ESbcAllocationLoudness); + aCap.SetAllocationMethods(ELoudness); + TRACE_INFO((_L("CBTSACStreamerController::SetAllocationMethod(), AllocationMethod: ELoudness"))) + } + else if ( aAllocationMethod & ESNR ) + { + iEncoderCI->SetAllocationMethod(CSbcEncoderIntfc::ESbcAllocationSNR); + aCap.SetAllocationMethods(ESNR); + TRACE_INFO((_L("CBTSACStreamerController::SetAllocationMethod(), AllocationMethod: ESNR"))) + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::SetAllocationMethod(), No matching Allocation Method"))) + } + } +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetChannelMode +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::SetChannelMode(TSBCCodecCapabilities& aCap, TUint8 aChannelMode) + { + // Set Channel mode, select highest one + if ( aChannelMode & EJointStereo ) + { + iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelJointStereo); + aCap.SetChannelModes(EJointStereo); + TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EJointStereo"))) + } + else if ( aChannelMode & EStereo ) + { + iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelStereo); + aCap.SetChannelModes(EStereo); + TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EStereo"))) + } + else if ( aChannelMode & EDualChannel ) + { + iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelDual); + aCap.SetChannelModes(EDualChannel); + TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EDualChannel"))) + } + else if ( aChannelMode & EMono ) + { + iEncoderCI->SetChannelMode(CSbcEncoderIntfc::ESbcChannelMono); + aCap.SetChannelModes(EMono); + TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), ChannelMode: EMono"))) + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::SetChannelMode(), No matching Channel Mode"))) + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetSamplingFrequency +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::SetSamplingFrequency(TSBCCodecCapabilities& aCap, TUint8 aFrequency) + { + // Set Sampling Frequency, select highest one + if ( aFrequency & E48kHz ) + { + iEncoderCI->SetSamplingFrequency(TUint(48000)); + aCap.SetSamplingFrequencies(E48kHz); + TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E48kHz"))) + } + else if ( aFrequency & E44100Hz ) + { + iEncoderCI->SetSamplingFrequency(TUint(44100)); + aCap.SetSamplingFrequencies(E44100Hz); + TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E44100Hz"))) + } + else if ( aFrequency & E32kHz ) + { + iEncoderCI->SetSamplingFrequency(TUint(32000)); + aCap.SetSamplingFrequencies(E32kHz); + TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E32kHz"))) + } + else if ( aFrequency & E16kHz ) + { + iEncoderCI->SetSamplingFrequency(TUint(16000)); + aCap.SetSamplingFrequencies(E16kHz); + TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), Sampling Frequency: E16kHz"))) + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::SetSamplingFrequency(), No matching Sampling Frequency"))) + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetSamplingFrequency +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::GetSamplingFrequency(TSBCCodecCapabilities& aCap) const + { + TInt Freq = 0; + switch( aCap.SamplingFrequencies() ) + { + case E48kHz: + Freq = 48000; + break; + case E44100Hz: + Freq = 44100; + break; + case E32kHz: + Freq = 32000; + break; + case E16kHz: + Freq = 16000; + break; + default: + TRACE_INFO((_L("CBTSACStreamerController::GetSamplingFrequency(), #default"))) + Freq = 48000; + break; + } + return Freq; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetNumOfChannels +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::GetNumOfChannels(TSBCCodecCapabilities& aCap) const + { + TInt nChnls = (aCap.ChannelModes() & EMono) ? 1 : 2; + return nChnls; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetNumOfSubbands +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::SetNumOfSubbands(TSBCCodecCapabilities& aCap, TUint8 aNumOfSubbands) + { + // Set Number of Subbands, select highest one + if ( aNumOfSubbands & EEightSubbands ) + { + iEncoderCI->SetNumOfSubbands(TUint(8)); + aCap.SetSubbands(EEightSubbands); + TRACE_INFO((_L("CBTSACStreamerController::SetNumOfSubbands(), Subband: EEightSubbands"))) + } + else if ( aNumOfSubbands & EFourSubbands ) + { + iEncoderCI->SetNumOfSubbands(TUint(4)); + aCap.SetSubbands(EFourSubbands); + TRACE_INFO((_L("CBTSACStreamerController::SetNumOfSubbands(), Subband: EFourSubbands"))) + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::SetNumOfSubbands(), No matching Subband"))) + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetNumOfSubbands +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::GetNumOfSubbands(TSBCCodecCapabilities& aCap) const + { + TInt nSbands = (aCap.Subbands() & EEightSubbands) ? 8 : 4; + return nSbands; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::FrameLengthFormula +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::FrameLengthFormula(TSBCCodecCapabilities& aCap) const + { + TInt join = ( aCap.ChannelModes() & EJointStereo ) ? 1 : 0; + TInt nChnls = GetNumOfChannels(aCap); + TInt nSbands = GetNumOfSubbands(aCap); + TInt nBlck = GetBlockLen(aCap); + + // For mono (and dual channel) mode the formula is slightly differend than for stereo mode(s). + TInt frameLength = + ( (aCap.ChannelModes() & EMono) || (aCap.ChannelModes() & EDualChannel) ) ? + 4 + ((4 * nSbands * nChnls) / 8) + ( (nBlck * nChnls * aCap.MaxBitpoolValue()) / 8): + 4 + ((4 * nSbands * nChnls) / 8) + ( (join * nSbands + nBlck * aCap.MaxBitpoolValue()) / 8)/* + join*/; + + // Note: last "+ join" in latter version of the formula is for joint stereo. + // Otherwise the formula doesn't calculate the extra byte that's in the header. + return frameLength; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::PacketsDropped +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::PacketsDropped(TInt aError) + { + TRACE_FUNC + if(!iTotalNbrOfDroppedPackets) + { + // This is first packet drop indication after previous sample interval + iFirstPacketDropTime.UniversalTime(); + } + TTime timeNow; + timeNow.UniversalTime(); + iPacketDropDeviation = static_cast(timeNow.MicroSecondsFrom(iFirstPacketDropTime).Int64()); + + iTotalNbrOfDroppedPackets += aError; + + if(!IsActive()) + { + iOngoingAction = EErrorSending; + iTimer.After(iStatus, KDataCollectDelay); + SetActive(); + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::SetCurrentBitpoolData +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::SetCurrentBitpoolData(TInt aBitpool) + { + TRACE_FUNC + TInt err = KErrNone; + TInt Index = GetIndex(aBitpool); + if(Index >= 0) + { + iCurrentBitpoolData = GetBitpoolData(Index); + } + else + { + err = KErrNotFound; + } + return err; + } +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetIndex +// ----------------------------------------------------------------------------- +// +TInt CBTSACStreamerController::GetIndex(TInt aBitpool) + { + TInt Bitpool = aBitpool; + if(aBitpool > iMatchCap.MaxBitpoolValue()) + { + Bitpool = iMatchCap.MaxBitpoolValue(); + } + for(TInt i = 0 ; i < iBitpoolData.Count() ; i++) + { + if(Bitpool == iBitpoolData[i].iMaxBitpoolValue) + { + return i; + } + } + return KErrNotFound; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::IndexValid +// ----------------------------------------------------------------------------- +// +TBool CBTSACStreamerController::IndexValid(TInt aIndex) + { + if(aIndex >= 0 && aIndex < iBitpoolData.Count()) + return ETrue; + else + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::InitializeBitpoolData +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::InitializeBitpoolDataL() + { + TRACE_FUNC + TBitpoolData data; + iBitpoolData.Reset(); + for(TInt i = 0 ; i < KNumOfBitpoolValues ; i++) + { + data.iMaxBitpoolValue = KMaxBitpoolValues[i]; + data.iMaxDeviation = KDeviationValues[i]; + //data.iUpgradeDelay = KUpgradeDelays[i]; + data.iUpBitpoolIndex = (i == 0) ? i : i - 1; + data.iIndex = i; + data.iDownBitpoolIndex = (i == KNumOfBitpoolValues - 1) ? i : i + 1; + data.iMinimumMaxBitpool = (i == KNumOfBitpoolValues - 1) ? ETrue : EFalse; + iBitpoolData.AppendL(data); + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::GetBitpoolData +// ----------------------------------------------------------------------------- +// +TBitpoolData* CBTSACStreamerController::GetBitpoolData(TInt aIndex) + { + if(aIndex < 0 || aIndex >= iBitpoolData.Count()) + return NULL; + + return &iBitpoolData[aIndex]; + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::ReorganizeBitpoolTable +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::ReorganizeBitpoolTable(TInt aNegotiatedMaxBitpool) + { + TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Negotiated Max Bitpool %d"), aNegotiatedMaxBitpool)) + // Start checking from the lowest possible bitpool value + for(TInt i = (KNumOfBitpoolValues - 1) ; i > 0 ; i--) + { + if(aNegotiatedMaxBitpool <= KMaxBitpoolValues[i]) + { + TInt ii; + for(ii = 0 ; ii < i ; ii++) + { + iBitpoolData.Remove(0); + } + TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Tables removed: %d"), ii)) + for(TInt j = 0 ; j < iBitpoolData.Count() ; j++) + { + if(j == 0) + { + iBitpoolData[j].iMaxBitpoolValue = aNegotiatedMaxBitpool; + } + iBitpoolData[j].iIndex = j; + iBitpoolData[j].iUpBitpoolIndex = (j == 0) ? j : j - 1; + iBitpoolData[j].iDownBitpoolIndex = (j == iBitpoolData.Count() - 1) ? j : j + 1; + } + break; + } + } + TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Tables left: %d"), iBitpoolData.Count())) + for(TInt k = 0 ; k < iBitpoolData.Count() ; k++) + { + TRACE_INFO((_L("CBTSACStreamerController::ReorganizeBitpoolTable(), Table[%d] MaxBP: %d"), k, iBitpoolData[k].iMaxBitpoolValue)) + } + } + +// ----------------------------------------------------------------------------- +// CBTSACStreamerController::DoSelfComplete +// ----------------------------------------------------------------------------- +// +void CBTSACStreamerController::DoSelfComplete(EOngoingAction aAction, TInt aError) + { + TRACE_FUNC + if (IsActive()) + { + // Stop timer + Cancel(); + } + if (!IsActive()) + { + // Just self complete here, handle error in RunL + iOngoingAction = aAction; + TRequestStatus *status = &iStatus; + iStatus = KRequestPending; + iThread.RequestComplete(status, aError); + SetActive(); + } + else + { + TRACE_INFO((_L("CBTSACStreamerController::DoSelfComplete((), Couldn't do self complete"))) + } + } +// End of File