bluetoothengine/btsac/btrcc/src/btrccLegacyVolumeLevelController.cpp
changeset 0 f63038272f30
child 21 53b7818cd282
--- /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 <remconbeareravrcp.h> //	KRemConBearerAvrcpImplementationUid = 0x1020685f
+#include <MediaStreamPropertiesPSKeys.h>
+#include <remconinterfaceselector.h> 
+#include <remconcoreapicontroller.h> 
+#include <remconaddress.h>
+#include <e32math.h>
+
+#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