bluetoothappprofiles/avrcp/nowplayingapi/src/remconnowplayingtargetbase.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/nowplayingapi/src/remconnowplayingtargetbase.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,472 @@
+// 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
+ @internalComponent
+ @released
+*/
+
+#include <remconmediabrowsetypes.h>
+#include <remcondatabaseawarenowplayingtargetobserver.h>
+#include <remcondatabaseunawarenowplayingtargetobserver.h>
+#include <remcon/remconnowplayingtargetbase.h>
+#include <remcon/avrcpspec.h>
+#include <remconinterfaceselector.h>
+#include <bluetooth/logger.h>
+
+#include "mediabrowse.h"
+#include "nowplaying.h"
+#include "remconnowplayingfault.h"
+#include "remconqueuemessage.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_REMCONNOWPLAYINGAPI);
+_LIT8(KLogFormat, "Operation Id = 0x%x, Data Lengh = %d");
+#endif
+
+CRemConNowPlayingTargetBase::CRemConNowPlayingTargetBase(
+	CRemConInterfaceSelector& aInterfaceSelector,
+	MRemConDatabaseAwareNowPlayingTargetObserver& aObserver)
+	: CRemConInterfaceBase(
+	TUid::Uid(KRemConNowPlayingApiUid),
+	KMaxLengthNowPlayingMsg,
+	aInterfaceSelector,
+	ERemConClientTypeTarget), 
+	iDaObserver(&aObserver),
+	iInterfaceSelector(aInterfaceSelector),
+	iInProgress(EFalse)
+	{
+	}
+		
+CRemConNowPlayingTargetBase::CRemConNowPlayingTargetBase(
+	CRemConInterfaceSelector& aInterfaceSelector,
+	MRemConDatabaseUnawareNowPlayingTargetObserver& aObserver)
+	: CRemConInterfaceBase(
+	TUid::Uid(KRemConNowPlayingApiUid),
+	KMaxLengthNowPlayingMsg,
+	aInterfaceSelector,
+	ERemConClientTypeTarget), 
+	iDuObserver(&aObserver),
+	iInterfaceSelector(aInterfaceSelector),
+	iInProgress(EFalse)
+	{
+	}
+	
+void CRemConNowPlayingTargetBase::BaseConstructL()
+	{
+	iMsgQueue = new(ELeave)TRemConMessageQueue;
+	TCallBack cb(&NextMessageCb, this);
+	iNextMessageCallBack = new (ELeave) CAsyncCallBack(cb,
+			CActive::EPriorityStandard);
+		
+	iOutBuf.CreateL(KMaxLengthNowPlayingMsg);
+	
+    // Mandate the following features supported.
+	RRemConInterfaceFeatures features;
+	User::LeaveIfError(features.Open());
+	CleanupClosePushL(features);
+
+	features.AddOperationL(EPlayItem);
+	features.AddOperationL(EAddToNowPlaying);
+	features.AddOperationL(ERegisterNotification);
+	
+    CRemConInterfaceBase::BaseConstructL(features);
+    CleanupStack::PopAndDestroy(&features);
+	}
+	
+
+EXPORT_C CRemConNowPlayingTargetBase::~CRemConNowPlayingTargetBase()
+	{
+	iOutBuf.Close();
+
+	iNextMessageCallBack->Cancel();
+	delete iNextMessageCallBack;
+	
+	iMsgQueue->Reset();
+	delete iMsgQueue;
+	}
+
+/** 
+@internalComponent
+@released
+
+Gets a pointer to a specific interface version.
+
+@return A pointer to the interface, NULL if not supported.
+*/
+TAny* CRemConNowPlayingTargetBase::GetInterfaceIf(TUid aUid)
+	{
+	TAny* ret = NULL;
+	if ( aUid == TUid::Uid(KRemConInterfaceIf2) )
+		{
+		ret = reinterpret_cast<TAny*>(
+			static_cast<MRemConInterfaceIf2*>(this)
+			);
+		}
+
+	return ret;
+	}
+
+/**
+Provide a response to the play item command. For database aware clients this 
+would have been called via MrcdanptoPlayItem(). For database unaware client
+this would have been called via MrcdunptoPlayItem()
+
+The client must call NowPlayingContentChanged() if the content of the now 
+playing list has been changed after the client successfully plays the item
+and provides the response with KErrNone through this function.
+
+@param aErr The result of play item operation.
+     - KErrNone if the operation was successful.
+     - KErrInvalidMediaLibraryStateCookie if the client is able to maintain 
+       unique UIDs accross the entire virtual filesystem, but the media 
+       library state cookie provided does not match the client's state cookie.
+     - KErrInvalidUid if the uid of the item provided does not refer to any 
+       valid item.
+     - KErrNowPlayingUidIsADirectory if the uid of the item provided refers to
+       a directory which can not be handled by this media player.
+     - KErrNowPlayingMediaInUse if the item is in use and can not be played.
+     - System wide error code otherwise.
+
+@see NowPlayingContentChanged()
+*/
+EXPORT_C void CRemConNowPlayingTargetBase::PlayItemResponse(TInt aErr)
+	{
+	TUint8 status = RAvrcpIPC::SymbianErrToStatus(aErr);
+	SendResponse(status, EPlayItem);
+	
+	iInProgress = EFalse;		
+	if (!iMsgQueue->IsEmpty())
+		{
+		iNextMessageCallBack->CallBack();
+		}
+	}
+
+/**
+Sends the response for the request MrcnptoAddToNowPlaying()
+
+The client must call NowPlayingContentChanged() if the content of the now 
+playing list has been changed after the client successfully adds the item
+to the now playing list and provides the response with KErrNone through 
+this function.
+
+param aErr The result of add to now playing operation.
+    - KErrNone if the operation was successful.
+    - KErrInvalidMediaLibraryStateCookie if the client is able to maintain 
+      unique UIDs accross the entire virtual filesystem, but the media 
+      library state cookie provided does not match the client's state cookie.
+    - KErrInvalidUid if the uid of the item provided does not 
+      refer to any valid item.
+    - KErrNowPlayingUidIsADirectory if the uid of the item provided refers to
+      a directory which can not be handled by this media player.
+    - KErrNowPlayingMediaInUse if the item is in use and can not be added to 
+      now playing list.
+    - KErrNowPlayingListFull if the now playing list if full and no more items
+      can be added.
+    - System wide error code otherwise.
+
+@see NowPlayingContentChanged()
+*/
+EXPORT_C void CRemConNowPlayingTargetBase::AddToNowPlayingResponse(TInt aErr)
+	{
+	TUint8 status = RAvrcpIPC::SymbianErrToStatus(aErr);
+	SendResponse(status, EAddToNowPlaying);
+
+	iInProgress = EFalse;		
+	if (!iMsgQueue->IsEmpty())
+		{
+		iNextMessageCallBack->CallBack();
+		}
+	}
+
+/**
+Called by the client in the case that the now playing content changed.
+
+@see PlayItemResponse()
+@see AddToNowPlayingResponse()
+*/
+EXPORT_C void CRemConNowPlayingTargetBase::NowPlayingContentChanged()
+	{
+	if(iNotificationPending)
+		{
+		iNotificationPending = EFalse;
+		SendNotificationResponse(ERemConNotifyResponseChanged);
+		}
+	}
+
+void CRemConNowPlayingTargetBase::SendResponse(TUint8 aStatus, TUint aOperationId)
+	{
+	TInt error = KErrNone;
+
+	// Formats the response in a RRemConNowPlayingResponse
+	RRemConNowPlayingResponse response;
+	response.iStatus = aStatus;
+	
+	TRAP(error, response.WriteL(iOutBuf));
+	if (error == KErrNone)
+		{
+		// Send the response back to the CT
+		error = InterfaceSelector().SendUnreliable(
+				TUid::Uid(KRemConNowPlayingApiUid),
+				aOperationId, ERemConResponse, iOutBuf );
+		}
+
+	}
+
+void CRemConNowPlayingTargetBase::SendError(TInt aError, TUint aOperationId)
+	{
+	TInt error = KErrNone;	
+	RAvrcpIPCError response;
+	response.iError = RAvrcpIPC::SymbianErrorCheck(aError);
+	TRAP(error, response.WriteL(iOutBuf));
+	if (error == KErrNone)
+		{
+		InterfaceSelector().SendUnreliable(TUid::Uid(KRemConNowPlayingApiUid),
+				aOperationId, ERemConResponse, iOutBuf);
+		}
+	}
+
+// From MRemConInterfaceIf2
+void CRemConNowPlayingTargetBase::MrcibNewMessage(
+		TUint aOperationId, 
+		const TDesC8& aData, 
+		TRemConMessageSubType aMsgSubType)
+	{
+	LOG_FUNC
+	LOG2(KLogFormat, aOperationId, aData.Length());
+
+	TMetadataTransferPDU currentOp =
+	RAvrcpIPC::GetPDUIdFromIPCOperationId(aOperationId);
+	switch(currentOp)
+		{
+	case EPlayItem:
+		if ( !iInProgress && 
+			 !iMsgQueue->Find(TUid::Uid(KRemConNowPlayingApiUid), EPlayItem))
+			{
+			ProcessPlayItem(aData);
+			}
+		else
+			{
+			AddToOperationQueue(EPlayItem, aData);
+			}
+		break;
+	case EAddToNowPlaying:
+		if ( !iInProgress && 
+			 !iMsgQueue->Find(TUid::Uid(KRemConNowPlayingApiUid), EAddToNowPlaying))
+			{
+			ProcessAddToNowPlaying(aData);
+			}
+		else
+			{
+			AddToOperationQueue(EAddToNowPlaying, aData);
+			}
+		break;
+	case ERegisterNotification:
+		{
+		// obtain eventId from aOperationId
+		TRegisterNotificationEvent eventId = 
+		RAvrcpIPC::GetEventIdFromIPCOperationId(aOperationId);
+		
+		// If asserted here, must something wrong occured in the 
+		// remconbearer handling
+		__ASSERT_DEBUG(eventId == ERegisterNotificationNowPlayingContentChanged
+				, NowPlayingFault::Fault(EInvalidEventId));
+        
+		// register for Notifications
+		if (aMsgSubType == ERemConNotifyCommandAwaitingInterim)
+			{
+			ProcessGetStatusAndBeginObserving();
+			}
+		else if (aMsgSubType == ERemConNotifyCommandAwaitingChanged)
+			{
+			ProcessGetStatus();
+			}
+	 	break;
+		}
+	default:
+		break;
+		};
+	}
+	
+void CRemConNowPlayingTargetBase::ProcessPlayItem(const TDesC8& aData)
+	{
+	TUint64 item;
+	TRemConFolderScope scope;
+	TUint16 uidCounter;
+	
+	if (!ProcessNowPlaying(aData, EPlayItem, item, scope, uidCounter))
+		{
+		return;
+		}
+	
+	iInProgress = ETrue;
+	if (iDaObserver && (uidCounter > 0))	
+		{
+		iDaObserver->MrcdanptoPlayItem(item, scope, uidCounter);
+		}
+	else if (!iDaObserver && (0 == uidCounter))
+		{
+		iDuObserver->MrcdunptoPlayItem(item, scope);
+		}
+	else
+		{
+		PlayItemResponse(KErrAvrcpAirInvalidParameter);
+		}
+	}
+
+void CRemConNowPlayingTargetBase::ProcessAddToNowPlaying(const TDesC8& aData)
+	{
+	TUint64 item;
+	TRemConFolderScope scope;
+	TUint16 uidCounter;
+	
+	if (!ProcessNowPlaying(aData, EAddToNowPlaying, item, scope, uidCounter))
+		{
+		return;
+		}
+
+	iInProgress = ETrue;
+	if (iDaObserver && (uidCounter > 0))
+		{
+		iDaObserver->MrcdanptoAddToNowPlaying(item, scope, uidCounter);
+		}
+	else if (!iDaObserver && (0 == uidCounter))
+		{
+		iDuObserver->MrcdunptoAddToNowPlaying(item, scope);
+		}
+	else
+		{
+		AddToNowPlayingResponse(KErrAvrcpAirInvalidParameter);
+		}
+	}
+
+TBool CRemConNowPlayingTargetBase::ProcessNowPlaying(
+		const TDesC8& aData, 
+		TUint aOperationId,
+		TUint64& aItem, 
+		TRemConFolderScope& aScope, 
+		TUint16& aMediaLibraryStateCookie)
+	{
+	RRemConNowPlayingRequest request;
+	TRAPD(error, request.ReadL(aData))
+	if (error != KErrNone)
+		{
+		// Nothing in packet
+		SendError(KErrAvrcpMetadataParameterNotFound, aOperationId);
+		return EFalse;
+		}
+    
+	aItem = request.iElement;
+	aScope = request.iScope;
+	aMediaLibraryStateCookie = request.iUidCounter;
+	
+	//Does not allow invalid scope
+	if (   aScope != EBrowseFolder 
+		&& aScope != ESearchResultFolder
+		&& aScope != ENowPlayingFolder )
+		{
+		SendError(KErrAvrcpAirInvalidScope, aOperationId);
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+void CRemConNowPlayingTargetBase::ProcessGetStatusAndBeginObserving()
+	{
+	// and request another notification (if there is not one already pending)
+	// on the next state change  
+	iNotificationPending = ETrue;
+		
+	// send the current status
+	SendNotificationResponse(ERemConNotifyResponseInterim);
+	}
+
+void CRemConNowPlayingTargetBase::ProcessGetStatus()
+	{
+	// send the current value
+	SendNotificationResponse(ERemConNotifyResponseChanged);
+	}
+
+void CRemConNowPlayingTargetBase::SendNotificationResponse(
+		TRemConMessageSubType aMsgSubType)
+	{
+	LOG_FUNC
+
+	TInt error = KErrNone;
+
+	// No extra data needed
+	RAvrcpIPCError response;
+	response.iError = KErrNone;
+	TRAP(error, response.WriteL(iOutBuf));
+
+	if (error == KErrNone)
+		{
+		// send the response back to the CT
+		TUint operationId = 
+		RAvrcpIPC::SetIPCOperationIdFromEventId(
+				ERegisterNotificationNowPlayingContentChanged);
+		
+		error = InterfaceSelector().SendUnreliable(
+				TUid::Uid(KRemConNowPlayingApiUid),
+				operationId, ERemConResponse, aMsgSubType, iOutBuf);
+		}
+	}
+
+TInt CRemConNowPlayingTargetBase::NextMessageCb(TAny* aThis)
+	{
+	static_cast<CRemConNowPlayingTargetBase*>(aThis)->DoNextMessage();
+	return KErrNone;
+	}
+
+void CRemConNowPlayingTargetBase::DoNextMessage()
+	{
+	CRemConQueuedMessage* msg = iMsgQueue->First();
+	iMsgQueue->Remove(*msg);
+	
+	switch (msg->iOperationId)
+		{
+		case EPlayItem:
+			ProcessPlayItem(msg->Data());
+			break;
+		case EAddToNowPlaying:
+			ProcessAddToNowPlaying(msg->Data());
+			break;
+		default:
+			// Never come here.
+			ASSERT(NULL);
+			break;
+		}
+	delete msg;
+	}
+
+void CRemConNowPlayingTargetBase::AddToOperationQueue(TInt aOperationId, 
+		const TDesC8& aData)
+	{
+	CRemConQueuedMessage* msg = NULL;
+	TRAPD(err, msg = CRemConQueuedMessage::NewL(
+			TUid::Uid(KRemConNowPlayingApiUid), aData, aOperationId));			
+	if (err == KErrNone)
+		{
+		iMsgQueue->AddLast(*msg);
+		}
+	else
+		{
+		SendError(KErrAvrcpMetadataInternalError, aOperationId);
+		}
+	}
+