remotecontrol/avrcp/mediainformationapi/src/mediainformationapi.cpp
changeset 51 20ac952a623c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotecontrol/avrcp/mediainformationapi/src/mediainformationapi.cpp	Wed Oct 13 16:20:29 2010 +0300
@@ -0,0 +1,371 @@
+// 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 <bluetooth/logger.h>
+#include <remcon/avrcpspec.h>
+#include <remconmediainformationtarget.h>
+#include <remconmediainformationtargetobserver.h>
+#include <remconinterfaceselector.h>
+#include <avcframe.h>
+
+#include "mediainformation.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVRCP_MEDIA_INFO);
+#endif
+
+EXPORT_C CRemConMediaInformationTarget* CRemConMediaInformationTarget::NewL(CRemConInterfaceSelector& aInterfaceSelector, 
+		MRemConMediaInformationTargetObserver& aObserver)
+	{
+	LOG_STATIC_FUNC
+
+	CRemConMediaInformationTarget* self = new(ELeave) CRemConMediaInformationTarget(aInterfaceSelector, aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CRemConMediaInformationTarget::CRemConMediaInformationTarget(CRemConInterfaceSelector& aInterfaceSelector, 
+		MRemConMediaInformationTargetObserver& aObserver)
+:	CRemConInterfaceBase(TUid::Uid(KRemConMediaInformationApiUid), 
+						 KMaxLengthMediaInformationMsg, 
+						 aInterfaceSelector,
+						 ERemConClientTypeTarget), 
+	iObserver(aObserver),
+	iAttributeIterator(iMediaAttributeIDs),
+	iMsgQueue(_FOFF(CRemConMediaInformationQueuedMessage, iLink))
+	{
+	}
+	
+void CRemConMediaInformationTarget::ConstructL()
+	{
+	iResponse = new(ELeave)RRemConGetElementAttributesResponse();
+	TCallBack cb(&NextMessageCb, this);
+	iNextMessageCallBack = new (ELeave) CAsyncCallBack(cb, CActive::EPriorityStandard);
+	BaseConstructL();
+	}
+	
+
+/** Destructor.
+
+@publishedAll
+@released
+*/
+EXPORT_C CRemConMediaInformationTarget::~CRemConMediaInformationTarget()
+	{
+	iMediaAttributeIDs.Close();
+	iResponse->Close();
+	delete iResponse;
+	iNextMessageCallBack->Cancel();
+	delete iNextMessageCallBack;
+	TSglQueIter<CRemConMediaInformationQueuedMessage> iter(iMsgQueue);
+	CRemConMediaInformationQueuedMessage* msg;
+	iter.SetToFirst();
+	while ((msg = iter++) != NULL)
+		{
+		iMsgQueue.Remove(*msg);
+		delete msg;
+		}
+	}
+
+/** Gets a pointer to a specific interface version.
+
+@return A pointer to the interface, NULL if not supported.
+@internalComponent
+@released
+*/
+TAny* CRemConMediaInformationTarget::GetInterfaceIf(TUid aUid)
+	{
+	TAny* ret = NULL;
+	if ( aUid == TUid::Uid(KRemConInterfaceIf1) )
+		{
+		ret = reinterpret_cast<TAny*>(
+			static_cast<MRemConInterfaceIf*>(this)
+			);
+		}
+
+	return ret;
+	}
+
+EXPORT_C TInt CRemConMediaInformationTarget::AttributeValue( TMediaAttributeId aAttributeId, TDesC8& aAttributeData )
+	{
+	// check that the values supplied were requested
+	if ( KErrNotFound == iMediaAttributeIDs.Find( aAttributeId ) )
+		{
+		return KErrNotFound;
+		}
+		
+	REAResponse resp;
+	resp.iAttributeId = aAttributeId;
+	resp.iCharset = KUtf8MibEnum;
+	resp.iStringLen = aAttributeData.Length();
+	resp.iString = aAttributeData.Alloc();
+	if (resp.iString == NULL)
+		{
+		return KErrNoMemory;
+		}
+	TInt status = iResponse->iAttributes.Append(resp);
+	if (status != KErrNone)
+		{
+		resp.Close();  // make sure heap string is de-allocated
+		}
+	return status;
+	}
+
+// from MRemConInterfaceIf
+void CRemConMediaInformationTarget::SendError(TInt aError)
+	{
+	RBuf8 outBuf;
+	if (outBuf.Create(KAVCFrameMaxLength) != KErrNone)
+		{
+		// On OOM drop the message
+		return;
+		}
+	
+	TInt error = 0;
+	RAvrcpIPCError response;
+	response.iError = aError;
+	TRAP(error, response.WriteL(outBuf));   // Don't send error if OOM
+	if (error == KErrNone)
+		{
+		InterfaceSelector().SendUnreliable(TUid::Uid(KRemConMediaInformationApiUid),
+							EGetElementAttributes, ERemConResponse, outBuf);
+		}
+	outBuf.Close();
+	}
+
+// from MRemConInterfaceIf
+void CRemConMediaInformationTarget::MrcibNewMessage(TUint aOperationId, const TDesC8& aData )
+	{
+	LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
+	LOG1(_L("\taData.Length = %d"), aData.Length());
+
+	(void) aOperationId; // ignore warning about this variable being unused
+	
+	if (!iInProgress && iMsgQueue.IsEmpty())
+		{
+		ProcessMessage(aData);
+		}
+	else
+		{
+		CRemConMediaInformationQueuedMessage* msg = NULL;
+		TRAPD(err, msg = CRemConMediaInformationQueuedMessage::NewL(aData));
+		if (err == KErrNone)
+			{
+			iMsgQueue.AddLast(*msg);
+			}
+		}
+	}
+	
+void CRemConMediaInformationTarget::ProcessMessage(const TDesC8& aData)
+	{
+	iInProgress = ETrue;
+	// Try to read the incoming request
+	TInt error = KErrNone;
+	RRemConGetElementAttributesRequest request;
+	TRAP(error, request.ReadL(aData));
+
+	// Couldn't parse the request; tell them it was invalid
+	if (error != KErrNone)
+		{
+		request.Close();
+		return SendError(KErrAvrcpMetadataParameterNotFound);
+		}
+
+	// Specification section 5.3.1 (page 49) says unique id
+	// must be 0x0. All other values are currently reserved
+	if (request.iElement != 0)
+		{
+		request.Close();
+		return SendError(KErrAvrcpMetadataInvalidParameter);
+		}
+
+	// this may have been used by a previous GetElementAttributes, so
+	iMediaAttributeIDs.Reset();
+
+	if (request.iNumberAttributes == 0)
+		{
+		// spec says this is a request for all attribs
+		// current spec has 7 specified (0x01 to 0x07)
+		for (TInt i = 1; i <= 7; i++)
+			{
+			if (iMediaAttributeIDs.Append((TMediaAttributeId)i) != KErrNone)
+				{
+				request.Close();
+				return SendError(KErrAvrcpMetadataInternalError);
+				}
+			}
+		}
+	else
+		{
+		// No need to check request.iNumberAttributes == request.iAttributes.Count()
+		// as this must be correct or request.ReadL(aData) leaves
+		for (TInt i = 0; i < request.iNumberAttributes; i++)
+			{
+			TUint8 value = request.iAttributes[i];
+			if (value > 0 && value <= KMaxMediaAttributeValue )
+				{
+				if (iMediaAttributeIDs.Append((TMediaAttributeId)value) != KErrNone)
+					{
+						request.Close();
+						return SendError(KErrAvrcpMetadataInternalError);
+					}
+				}
+			}
+		}
+	request.Close();
+
+	// check that some valid attribute ids have been found
+	if (iMediaAttributeIDs.Count())
+		{
+		// if the client has not yet called Completed() on the last request
+		// clear the the attributes from the previous response
+		iResponse->Close();
+		
+		// reset the interator to the start, as it may have been used before
+		iAttributeIterator.Start();
+		
+		// call the client API to get the client value.
+		iObserver.MrcmitoGetCurrentlyPlayingMetadata(iAttributeIterator);
+		}
+	else
+		{
+		// no valid attribute ids found so return an error to bearer
+		SendError(KErrAvrcpMetadataParameterNotFound);
+		}
+	}
+
+// The client application has signaled that all attributes have been returned so 
+// response can now be sent
+EXPORT_C void CRemConMediaInformationTarget::Completed()
+	{
+	if (!iInProgress)
+		{
+		return;
+		}
+	// Finalise response; update number of attributes returned
+	iResponse->iNumberAttributes = iResponse->iAttributes.Count();
+
+	//Check the bound of the number of attributes, zero is not permitted
+	if (iResponse->iNumberAttributes == 0)
+		{
+		return SendError(KErrAvrcpMetadataInternalError);
+		}
+	
+	// Allocate a buffer for the formatted message
+	RBuf8 messageBuffer;
+	if ( messageBuffer.Create(iResponse->Size()) != KErrNone )
+		{
+		// On OOM drop the message
+		iResponse->Close();
+		return;
+		}
+		
+	// send the result back to the CT
+	TInt error = KErrNone;
+	TRAP(error, iResponse->WriteL(messageBuffer));
+	if (error == KErrNone)
+		{
+		InterfaceSelector().SendUnreliable(TUid::Uid(KRemConMediaInformationApiUid),
+								EGetElementAttributes, ERemConResponse, messageBuffer);
+		}
+	
+	// Make sure attribute list is reset for next time
+	iResponse->Close();
+	messageBuffer.Close();
+	
+	iInProgress = EFalse;
+	if (!iMsgQueue.IsEmpty())
+		{
+		iNextMessageCallBack->CallBack();
+		}
+	
+	}
+
+int CRemConMediaInformationTarget::NextMessageCb(TAny* aThis)
+	{
+	static_cast<CRemConMediaInformationTarget*>(aThis)->DoNextMessage();
+	return KErrNone;
+	}
+
+void CRemConMediaInformationTarget::DoNextMessage()
+	{
+	CRemConMediaInformationQueuedMessage* msg = iMsgQueue.First();
+	iMsgQueue.Remove(*msg);
+	ProcessMessage(msg->Data());
+	delete msg;
+	}
+
+EXPORT_C TMediaAttributeIter::TMediaAttributeIter(RArray<TMediaAttributeId>& aMediaAttributeIDs) :
+    iMediaAttributeIDs(aMediaAttributeIDs),
+    iterator(0)
+	{
+	}
+
+EXPORT_C void TMediaAttributeIter::Start()
+	{
+	iterator = 0;
+	}
+
+EXPORT_C TBool TMediaAttributeIter::Next(TMediaAttributeId& aId)
+	{
+	TInt count = iMediaAttributeIDs.Count();
+	if (iterator > count - 1)
+		{
+		return EFalse;
+		}
+	aId = iMediaAttributeIDs[iterator];
+	iterator++;
+	return ETrue;
+	}
+
+CRemConMediaInformationQueuedMessage* CRemConMediaInformationQueuedMessage::NewL(const TDesC8& aData)
+	{
+	CRemConMediaInformationQueuedMessage* self = new (ELeave) CRemConMediaInformationQueuedMessage();
+	CleanupStack::PushL(self);
+	self->ConstructL(aData);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CRemConMediaInformationQueuedMessage::CRemConMediaInformationQueuedMessage()
+	{
+	
+	}
+
+void CRemConMediaInformationQueuedMessage::ConstructL(const TDesC8& aData)
+	{
+	iData.CreateL(aData);
+	}
+
+CRemConMediaInformationQueuedMessage::~CRemConMediaInformationQueuedMessage()
+	{
+	iData.Close();
+	}
+
+const TDesC8& CRemConMediaInformationQueuedMessage::Data()
+	{
+	return iData;
+	}
+
+
+