bluetoothappprofiles/avrcp/absolutevolumeapi/src/absolutevolumeapicontroller.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/absolutevolumeapi/src/absolutevolumeapicontroller.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,478 @@
+// Copyright (c) 2008-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:
+//
+
+
+
+/**
+ @file
+ @publishedAll
+ @released
+*/
+
+#include <e32def.h>
+#include <absolutevolumeapicontroller.h>
+#include <absolutevolumeapicontrollerobserver.h>
+#include <remconinterfaceselector.h>
+#include "absolutevolumesender.h"
+#include <absolutevolumeutils.h>
+#include <bluetooth/logger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCONABSOLUTEVOLUME);
+#endif
+
+#ifdef _DEBUG
+_LIT(KAbsoluteVolumeControllerFaultName, "AbsVolFault");
+// The panic codes associated with category KAbsoluteVolumeControllerFaultName are line numbers in this file.
+#endif
+
+/**
+Allocates and constructs a new CRemConAbsoluteVolumeController object
+
+@param aInterfaceSelector The interface selector. The client must have 
+       created one of these first.
+@param aObserver The observer. The client must have implemented the observer,
+       owned by the client.
+@param aMaxVolume The client maximum volume.
+@return A new CRemConAbsoluteVolumeController, owned by the interface selector
+@panic AbsoluteVolumeController 0 if aMaxVolume is zero.
+*/
+EXPORT_C 
+CRemConAbsoluteVolumeController* CRemConAbsoluteVolumeController::NewL(
+		CRemConInterfaceSelector& aInterfaceSelector, 
+		MRemConAbsoluteVolumeControllerObserver& aObserver,
+		TUint32 aMaxVolume)
+	{
+	LOG_STATIC_FUNC
+	
+	__ASSERT_ALWAYS(aMaxVolume > 0, 
+				User::Panic(KAbsoluteVolumeControllerPanicName, 
+						EControllerInvalidMaxVolume)
+				);
+				
+	CRemConAbsoluteVolumeController* self = 
+	new(ELeave) CRemConAbsoluteVolumeController(aInterfaceSelector, 
+			aObserver, aMaxVolume);
+	
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** 
+Constructor.
+
+@param aInterfaceSelector The interface selector.
+@param aObserver The observer.
+*/
+CRemConAbsoluteVolumeController::CRemConAbsoluteVolumeController(
+		CRemConInterfaceSelector& aInterfaceSelector, 
+		MRemConAbsoluteVolumeControllerObserver& aObserver,
+		TUint32 aMaxVolume)
+:	CRemConInterfaceBase(TUid::Uid(KRemConAbsoluteVolumeControllerApiUid), 
+		KAbsoluteVolumeResponseDataSize,
+		aInterfaceSelector,
+		ERemConClientTypeController),
+    iObserver(aObserver),
+    iClientMaxVolume(aMaxVolume),
+	iNotificationRequested(EFalse),
+	iAbsVolRequest(ENotInUse),
+	iNotifyRequest(ENotInUse)
+	{
+	LOG_FUNC
+	}
+
+EXPORT_C CRemConAbsoluteVolumeController::~CRemConAbsoluteVolumeController()
+    {
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	delete iAbsVolSender;
+    }
+
+void CRemConAbsoluteVolumeController::ConstructL()
+	{
+	LOG_FUNC
+	
+	iAbsVolSender = CAbsVolSender::NewL(InterfaceSelector(), *this);
+	BaseConstructL();
+	}
+
+/**
+Sets an absolute volume on the target device,
+Any responses will be returned via the observer interface.
+
+@pre The send of any previous SetAbsoluteVolume command has completed.
+@param aStatus Indicates the completion of the send request.  The client must
+			   not block execution by using User::WaitForRequest to await 
+			   completion of this send.
+@param aVolume The relative volume against the client max volume.
+@param aNumRemotes The number of remotes to which the command was sent.
+@panic AbsoluteVolumeController 1, if aVolume greater than the client 
+       max volume.
+*/
+EXPORT_C void CRemConAbsoluteVolumeController::SetAbsoluteVolume(
+		TRequestStatus& aStatus, 
+		TUint32 aVolume, 
+		TUint& aNumRemotes)
+	{
+	LOG_FUNC
+	LOG1(_L8("\taVolume = %d"), aVolume);
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	__ASSERT_ALWAYS(aVolume <= iClientMaxVolume, 
+			User::Panic(KAbsoluteVolumeControllerPanicName, 
+					EControllerVolumeBeyondMaxVolume)
+			);
+	__ASSERT_DEBUG(iAbsVolRequest == ENotInUse, User::Panic(KAbsoluteVolumeControllerPanicName, 
+				EMultipleSetAbsoluteVolumes));
+	
+	RRemConAbsoluteVolumeRequest setAbsVol;
+	setAbsVol.iVolume = aVolume;
+	setAbsVol.iMaxVolume = iClientMaxVolume;
+	TRAPD(err, setAbsVol.WriteL(iSetData));
+	if (err == KErrNone)
+		{
+		// Store the client's info so we can complete their request later
+		aStatus = KRequestPending;
+		iAbsVolRequest = EPending;
+		__ASSERT_DEBUG(iClientStatus == NULL, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+		iClientStatus = &aStatus;
+		__ASSERT_DEBUG(iClientNumRemotes == NULL, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+		iClientNumRemotes = &aNumRemotes;
+		KickOffSendIfNeeded();
+		}
+	else
+		{
+		iObserver.MrcavcoSetAbsoluteVolumeResponse(0, 0, err);
+		}
+	}
+
+EXPORT_C void CRemConAbsoluteVolumeController::CancelSetAbsoluteVolume()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	switch ( iAbsVolRequest )
+		{
+	case ENotInUse:
+		// Nothing to do.
+		break;
+	case ESending:
+		iAbsVolSender->Cancel();
+		SetAbsoluteVolumeSendComplete(KErrCancel);
+		break;
+	case EPending:
+		SetAbsoluteVolumeSendComplete(KErrCancel);
+		break;
+	default:
+		__ASSERT_DEBUG(EFalse, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+		break;
+		}
+	}
+
+/**
+Requests notification when the volume on the target device changes,
+Any responses will be returned via the observer interface.
+
+Volume changes will continue to be provided until either the 
+CancelAbsoluteVolumeNotification function is called, or MrcavcoCurrentVolume
+is called on the client with an error.
+
+@see MRemConAbsoluteVolumeControllerObserver::MrcavcoCurrentVolume
+@see CRemConAbsoluteVolumeController::CancelAbsoluteVolumeNotification
+@pre The client is not currently registered to receive absolute volume notifications.
+*/
+EXPORT_C 
+void CRemConAbsoluteVolumeController::RegisterAbsoluteVolumeNotification()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	// The request is outstanding, so not allowed to register again.
+	__ASSERT_DEBUG(!iNotificationRequested, User::Panic(KAbsoluteVolumeControllerPanicName, EAbsoluteVolumeNotificationAlreadyRegistered));
+	__ASSERT_DEBUG(iNotifyRequest == ENotInUse, User::Panic(KAbsoluteVolumeControllerPanicName, EMultipleNotifies));
+	
+	RRemConAbsoluteVolumeRequest absVol;
+	TRAPD(err, absVol.WriteL(iNotifyData));
+	if (err == KErrNone)
+		{
+		iNotifyRequest = EPending;
+		iNotificationRequested = ETrue;
+		KickOffSendIfNeeded();
+		}
+	else
+		{
+		iObserver.MrcavcoAbsoluteVolumeNotificationError();
+		}
+	}
+
+/**
+Called by the client to tell the controller that the client doesn't wish to 
+receicve the volume change notification
+until the client re-register again.
+*/
+EXPORT_C 
+void CRemConAbsoluteVolumeController::CancelAbsoluteVolumeNotification()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	if ( iNotifyRequest == ESending )
+		{
+		iAbsVolSender->Cancel();
+		}
+	
+	iNotificationRequested = EFalse;
+	RegisterNotifySendComplete();
+	}
+
+TAny* CRemConAbsoluteVolumeController::GetInterfaceIf(TUid aUid)
+    {
+	LOG_FUNC
+	
+	TAny* ret = NULL;
+	if ( aUid == TUid::Uid(KRemConInterfaceIf2) )
+		{
+		ret = reinterpret_cast<TAny*>(
+			static_cast<MRemConInterfaceIf2*>(this)
+			);
+		}
+	
+	return ret;
+    }
+
+void CRemConAbsoluteVolumeController::MrcibNewMessage(TUint aOperationId, 
+		const TDesC8& aData, 
+		TRemConMessageSubType aMessageSubType)
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	switch (aOperationId)
+	    {
+	case KRemConAbsoluteVolumeNotification:
+		HandleNotify(aData, aMessageSubType);
+	    break;
+	case KRemConSetAbsoluteVolume:
+    	HandleSetAbsoluteVolumeResponse(aData);
+	    break;
+	default:	   
+	    break;
+	    }
+	}
+
+/** 
+Process the 'volume changed notification response'
+
+@param aData The response data.
+@param aMessageSubType The RemCon submessage type.
+*/
+void CRemConAbsoluteVolumeController::HandleNotify(const TDesC8& aData,
+		TRemConMessageSubType aMessageSubType)
+    {
+	LOG_FUNC
+	
+    TInt err = KErrNone;
+    
+    if(iNotificationRequested)
+    	{
+	    RRemConAbsoluteVolumeResponse absVol;
+	    TRAP(err, absVol.ReadL(aData))
+	    if (err == KErrNone)
+	    	{
+	    	if (absVol.iError == KErrNone)
+	    		{
+	    		switch ( aMessageSubType )
+	    	        {
+	    	    case ERemConNotifyResponseInterim:
+	    	    	{
+	    	    	VolumeUpdate(absVol.iVolume, absVol.iMaxVolume);
+		    	    break;
+	    	    	}	    	    
+	    	    case ERemConNotifyResponseChanged:
+		    		{
+	    	    	VolumeUpdate(absVol.iVolume, absVol.iMaxVolume);
+
+		    		// Register notification again.
+		    		iNotificationRequested = EFalse;
+		    		RegisterAbsoluteVolumeNotification();
+		    	    break;
+		    		}	    			
+	    	    default:    	    
+	    	        break;
+	    	        }//switch
+	    		}
+	    	else //Error response
+	    		{
+	    		iNotificationRequested = EFalse;
+	    		iObserver.MrcavcoAbsoluteVolumeNotificationError();
+	    		}
+	    	}
+	    else
+	    	{
+    		iNotificationRequested = EFalse;
+    		iObserver.MrcavcoAbsoluteVolumeNotificationError();
+	    	}
+    	}
+    }
+
+/** 
+Process the 'set absolute volume response'
+@param aData The response data.
+*/
+void CRemConAbsoluteVolumeController::HandleSetAbsoluteVolumeResponse( 
+		const TDesC8& aData )
+    {
+	LOG_FUNC
+	
+    TInt err = KErrNone;
+    RRemConAbsoluteVolumeResponse absVol;
+    TRAP(err, absVol.ReadL(aData))
+    if (err == KErrNone)
+    	{
+    	iCurrentVolume = absVol.iVolume;
+    	iCurrentMaxVolume = absVol.iMaxVolume;
+    	iObserver.MrcavcoSetAbsoluteVolumeResponse(absVol.iVolume, 
+    			absVol.iMaxVolume,
+    			absVol.iError);
+    	}
+    else
+    	{
+    	iObserver.MrcavcoSetAbsoluteVolumeResponse(0, 
+    			0,
+    			err);
+    	}
+    }
+
+void CRemConAbsoluteVolumeController::MavsoSendComplete(TInt aResult)
+	{
+	LOG_FUNC
+	LOG1(_L8("\taResult = %d"), aResult);
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	if ( iAbsVolRequest == ESending )
+		{
+		__ASSERT_DEBUG(iNotifyRequest != ESending, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+		SetAbsoluteVolumeSendComplete(aResult);
+		}
+	else if ( iNotifyRequest == ESending )
+		{
+		// This updates our own state and kicks off any pending send. The 
+		// later client upcall (if there was an error) gives them a chance 
+		// to make further calls on us.
+		RegisterNotifySendComplete();
+
+		if(aResult != KErrNone)
+			{
+			iNotificationRequested = EFalse;
+			iObserver.MrcavcoAbsoluteVolumeNotificationError();
+			}
+		}
+	else
+		{
+		// Send complete with no send outstanding.
+		__ASSERT_DEBUG(EFalse, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+		}
+	}
+
+void CRemConAbsoluteVolumeController::KickOffSendIfNeeded()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	if ( iAbsVolRequest == ESending || iNotifyRequest == ESending )
+		{
+		// Any pending send will be kicked off when current send completes and this function is called again.
+		return;
+		}
+		
+	if ( iAbsVolRequest == EPending )
+		{
+		SendSetAbsoluteVolume();
+		}
+	else if ( iNotifyRequest == EPending )
+		{
+		SendNotify();
+		}
+	}
+
+void CRemConAbsoluteVolumeController::SetAbsoluteVolumeSendComplete(TInt aResult)
+	{
+	LOG_FUNC
+	LOG1(_L8("\taResult = %d"), aResult);
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	__ASSERT_DEBUG(iClientStatus, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+	User::RequestComplete(iClientStatus, aResult);
+	iClientStatus = NULL;
+	iClientNumRemotes = NULL;
+	iSetData.SetLength(0);
+	__ASSERT_DEBUG(iAbsVolRequest != ENotInUse, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+	iAbsVolRequest = ENotInUse;
+	
+	KickOffSendIfNeeded();
+	}
+
+void CRemConAbsoluteVolumeController::RegisterNotifySendComplete()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+
+	iNotifyData.SetLength(0);
+	// This method doesn't actually complete a client request so we don't bother asserting state.
+	iNotifyRequest = ENotInUse;
+	
+	KickOffSendIfNeeded();
+	}
+
+void CRemConAbsoluteVolumeController::VolumeUpdate(TUint32 aVolume, TUint32 aMaxVolume)
+	{
+	LOG_FUNC
+	LOG2(_L8("\taVolume = %d, aMaxVolume = %d"), aVolume, aMaxVolume);
+	
+	// Only update the client if the volume has changed
+    if (aVolume != iCurrentVolume || aMaxVolume != iCurrentMaxVolume)
+	    {
+	    iCurrentVolume = aVolume; //store the new value
+	    iCurrentMaxVolume = aMaxVolume;
+	    
+	    iObserver.MrcavcoCurrentVolume(aVolume,
+	    		aMaxVolume,
+	    		KErrNone);
+	    }
+	}
+
+void CRemConAbsoluteVolumeController::SendSetAbsoluteVolume()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	__ASSERT_DEBUG(iClientNumRemotes, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+	iAbsVolSender->SendSetAbsoluteVolume(*iClientNumRemotes, iSetData);
+	__ASSERT_DEBUG(iAbsVolRequest == EPending, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+	iAbsVolRequest = ESending;
+	}
+
+void CRemConAbsoluteVolumeController::SendNotify()
+	{
+	LOG_FUNC
+	LOG2(_L8("\tiAbsVolRequest = %d, iNotifyRequest = %d"), iAbsVolRequest, iNotifyRequest);
+	
+	iAbsVolSender->SendNotify(iNotifyData);
+	__ASSERT_DEBUG(iNotifyRequest == EPending, User::Panic(KAbsoluteVolumeControllerFaultName, __LINE__));
+	iNotifyRequest = ESending;
+	}