diff -r 000000000000 -r f63038272f30 bluetoothengine/btsac/btrcc/src/btrccLegacyVolumeLevelController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btsac/btrcc/src/btrccLegacyVolumeLevelController.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -0,0 +1,411 @@ +/* +* 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: This class implements legacy volume control of AVRCP Controller. +* +* +*/ + +// INCLUDE FILES +#include // KRemConBearerAvrcpImplementationUid = 0x1020685f +#include +#include +#include +#include +#include + +#include "btrccLegacyVolumeLevelController.h" +#include "debug.h" + +const TInt KVolumeNotSynchronized = -1; +const TInt KLegacyVolumeLevelSetServiceId = 0x03; + +const TInt KVolumeSyncRecheckTimer = 500000; // 0.5 second +const TInt KVolumeCommandInterval = 50000; // 0.05 second + +const TInt KVolumeScaleMax = 15; + +// MODULE DATA STRUCTURES + +// ================= MEMBER FUNCTIONS ======================= + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CBTRCCLegacyVolumeLevelController* CBTRCCLegacyVolumeLevelController::NewL(CRemConInterfaceSelector& aInterfaceSelector, MBTRCCVolumeControllerObserver& aObserver) + { + CBTRCCLegacyVolumeLevelController* self = new (ELeave) CBTRCCLegacyVolumeLevelController(aObserver); + CleanupStack::PushL(self); + self->ConstructL(aInterfaceSelector); + CleanupStack::Pop(self); + return self; + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::CBTRCCVolumeLevelController +// C++ constructor. +// ----------------------------------------------------------------------------- +// +CBTRCCLegacyVolumeLevelController::CBTRCCLegacyVolumeLevelController(MBTRCCVolumeControllerObserver& aObserver) + : CBTRCCVolumeLevelControllerBase(aObserver), iState(EStateWaitingForVolumeLevelChanges), iPhoneVolume(KVolumeNotSynchronized), + iCurrentPhoneVolume(KVolumeNotSynchronized), iCurrentRemoteVolume(KVolumeNotSynchronized) + { + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::ConstructL +// Symbian 2nd phase constructor. +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::ConstructL(CRemConInterfaceSelector& aInterfaceSelector) + { + TRACE_FUNC + CBTRCCVolumeLevelControllerBase::ConstructL(); + iInterfaceSelector = &aInterfaceSelector; + iRemConVolController = CRemConCoreApiController::NewL(aInterfaceSelector, *this); + TRACE_INFO((_L("CRemConCoreApiController created"))) + iBtrccLegacyVolumeActive = CBTRCCActive::NewL(*this, KLegacyVolumeLevelSetServiceId); + TRACE_INFO((_L("CBTRCCActive created"))) + iCtrlRTimer.CreateLocal(); + TRACE_INFO((_L("RTimer created"))) + iLocalMaxVolume = GetLocalMaxVolume(); + } + +// ----------------------------------------------------------------------------- +// Destructor. +// ----------------------------------------------------------------------------- +// +CBTRCCLegacyVolumeLevelController::~CBTRCCLegacyVolumeLevelController() + { + TRACE_FUNC + delete iBtrccLegacyVolumeActive; + iCtrlRTimer.Close(); + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::DoStart +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::DoStart(TInt aInitialVolume) + { + TRACE_FUNC + AdjustRemoteVolume(aInitialVolume); + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::DoStop +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::DoStop() + { + TRACE_FUNC + iBtrccLegacyVolumeActive->Cancel(); + iState = EStateWaitingForVolumeLevelChanges; + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::DoReset +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::DoReset() + { + TRACE_FUNC + iBtrccLegacyVolumeActive->Cancel(); + iCurrentRemoteVolume = KVolumeNotSynchronized; + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::AdjustRemoteVolume +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::AdjustRemoteVolume(TInt aVolume) + { + // A call to this is made when PS Key changes. + TRACE_INFO((_L("CBTRCCLegacyVolumeLevelController::AdjustRemoteVolume, volume %d, state %d"), aVolume, iState)) + iPhoneVolume = aVolume; + + if(iCurrentRemoteVolume == KVolumeNotSynchronized) + { + // We set current phone volume level as the reference synchronization point + // if we haven't done it yet. Otherwise we synchronize remote to the current level. + // Just synchronize volumes and return, there is nothing else to do at this point. + iCurrentRemoteVolume = iPhoneVolume; + return; + } + + switch(iState) + { + case EStateWaitingForVolumeLevelChanges: + // Just break here. + break; + case EStateDelay: + // Sharp volume jump handling is ongoing. In this case we want to update + // new volume level immediately. + if( iBtrccLegacyVolumeActive->IsActive() ) + { + iBtrccLegacyVolumeActive->Cancel(); + } + break; + default: + // We are middle of timing or volume up/down processing. New value + // is stored, just return here. New value is updated after previous + // job is done. + return; + } + + DoRemoteControl(); + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::DoRemoteControl +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::DoRemoteControl() + { + TRACE_INFO((_L("target volume level %d"), iPhoneVolume)) + TRACE_INFO((_L("phone current volume level %d"), iCurrentPhoneVolume)) + TRACE_INFO((_L("remote current volume level %d"), iCurrentRemoteVolume)) + + TState preState = iState; + iState = EStateWaitingForVolumeLevelChanges; + + if ( iPhoneVolume != iCurrentRemoteVolume ) + { + TInt prevPhoneVolume = iCurrentPhoneVolume; + iCurrentPhoneVolume = iPhoneVolume; + + if ( iCurrentPhoneVolume == 0 && prevPhoneVolume > 1 ) + { + // A sharp volume jump, most probably caused by audio stream switching. + // Delay the starting of audio adjustment for 0.5 seconds. + iState = EStateDelay; + } + else if (iCurrentPhoneVolume > iCurrentRemoteVolume) + { + iState = preState == EStateVolumeUpTiming ? EStateVolumeUp : EStateVolumeUpTiming; + } + else if (iCurrentPhoneVolume < iCurrentRemoteVolume) + { + iState = preState == EStateVolumeDownTiming ? EStateVolumeDown : EStateVolumeDownTiming; + } + } + + switch (iState) + { + case EStateVolumeUpTiming: + { + TRACE_INFO(_L("Volume up timing")) + StartTimer(KVolumeCommandInterval); + break; + } + case EStateVolumeUp: + { + TRACE_INFO(_L("Volume up")) + SendVolumeCommand(EStateVolumeUp); + break; + } + case EStateVolumeDownTiming: + { + TRACE_INFO(_L("Volume down timing")) + StartTimer(KVolumeCommandInterval); + break; + } + case EStateVolumeDown: + { + TRACE_INFO(_L("Volume down")) + SendVolumeCommand(EStateVolumeDown); + break; + } + case EStateDelay: + { + TRACE_INFO(_L("Delay before updating volume")) + StartTimer( KVolumeSyncRecheckTimer ); + break; + } + case EStateWaitingForVolumeLevelChanges: + { + TRACE_INFO(_L("Waiting volume change")) + break; + } + default: + { + // Not possible + } + } + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::GetPhoneVolume +// ----------------------------------------------------------------------------- +// +TInt CBTRCCLegacyVolumeLevelController::GetPhoneVolume(TInt &aVol) + { + TRACE_FUNC + TInt err = CBTRCCVolumeLevelControllerBase::GetPhoneVolume(aVol); + + // Converts volume level scale used in DevSound Audio (0 - 10000) into 0 - KVolumeScaleMax. + if( aVol <= 0 ) + { + // 0 level and -1 (no stream) don't need adjustment. + return err; + } + + TReal tgt; + TReal src(aVol); + TReal maxScale(KVolumeScaleMax); + TReal maxDevSound(iLocalMaxVolume); + TReal scale = maxScale/maxDevSound; + Math::Round( tgt, src*scale, 0); + + if( TInt(tgt) == 0 ) + { + // Only aVol value 0 is real zero (muted). All other scaled zero + // values have to be upgraded to level 1. + tgt = 1; + } + TRACE_INFO((_L("Volume scaled: original %d, scaled %d"), aVol, TInt(tgt))) + aVol = TInt(tgt); + return err; + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::RequestCompletedL +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::RequestCompletedL(CBTRCCActive& aActive, TInt aErr) + { + TRACE_FUNC + if( aActive.ServiceId() == KLegacyVolumeLevelSetServiceId ) + { + TRACE_INFO( (_L("CBTRCCLegacyVolumeLevelController iState: %d"), iState ) ) + if ( aErr != KErrNone ) + { + // Something wrong happened, could be e.g. the connection has + // been released while we are changing volume on remote device. + iState = EStateWaitingForVolumeLevelChanges; + return; + } + switch(iState) + { + case EStateVolumeUp: + { + ++iCurrentRemoteVolume; + break; + } + case EStateVolumeDown: + { + --iCurrentRemoteVolume; + break; + } + case EStateDelay: + case EStateWaitingForVolumeLevelChanges: + case EStateVolumeUpTiming: + case EStateVolumeDownTiming: + break; + default: + // Impossible to happen. + break; + } + DoRemoteControl(); + } + else + { + // This is something the base class can handle. + CBTRCCVolumeLevelControllerBase::RequestCompletedL(aActive, aErr); + } + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::CancelRequest +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::CancelRequest(TInt aServiceId) + { + TRACE_FUNC + if( aServiceId == KLegacyVolumeLevelSetServiceId ) + { + // Cancel possible active timers + iCtrlRTimer.Cancel(); + + if (iState == EStateVolumeUp) + { + ++iCurrentRemoteVolume; + } + else if (iState == EStateVolumeDown) + { + --iCurrentRemoteVolume; + } + } + else + { + // This is something the base class can handle. + CBTRCCVolumeLevelControllerBase::CancelRequest(aServiceId); + } + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::StartTimer +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::StartTimer(TInt aInterval) + { + TRACE_FUNC + if( !iBtrccLegacyVolumeActive->IsActive() ) + { + iCtrlRTimer.After(iBtrccLegacyVolumeActive->iStatus, aInterval); + iBtrccLegacyVolumeActive->GoActive(); + } + else + { + TRACE_INFO(_L("CBTRCCLegacyVolumeLevelController::StartTimer() ERR, timer already active!")) + } + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::SendVolumeCommand +// ----------------------------------------------------------------------------- +// +void CBTRCCLegacyVolumeLevelController::SendVolumeCommand(TInt aDirection) + { + TRACE_FUNC + if( !iBtrccLegacyVolumeActive->IsActive() ) + { + if( aDirection == EStateVolumeUp ) + { + iRemConVolController->VolumeUp(iBtrccLegacyVolumeActive->iStatus, iNumRemotes, ERemConCoreApiButtonClick); + } + else + { + iRemConVolController->VolumeDown(iBtrccLegacyVolumeActive->iStatus, iNumRemotes, ERemConCoreApiButtonClick); + } + iBtrccLegacyVolumeActive->GoActive(); + } + else + { + TRACE_INFO(_L("CBTRCCLegacyVolumeLevelController::DoRemConControl() ERR, previous action ongoing!")) + } + } + +// ----------------------------------------------------------------------------- +// CBTRCCLegacyVolumeLevelController::MrccacoResponse() +// ----------------------------------------------------------------------------- +// +TInt CBTRCCLegacyVolumeLevelController::MrccacoResponse() + { + TRACE_FUNC + return 0; + } + +// End of File