--- /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;
+ }