bluetoothappprofiles/avrcp/mediainformationapi/src/mediainformationapi.cpp
changeset 70 f5508c13dfe0
parent 67 16e4b9007960
child 71 083fd884d7dd
equal deleted inserted replaced
67:16e4b9007960 70:f5508c13dfe0
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @publishedAll
       
    19  @released
       
    20 */
       
    21 
       
    22 #include <bluetooth/logger.h>
       
    23 #include <remcon/avrcpspec.h>
       
    24 #include <remconmediainformationtarget.h>
       
    25 #include <remconmediainformationtargetobserver.h>
       
    26 #include <remconinterfaceselector.h>
       
    27 #include <avcframe.h>
       
    28 
       
    29 #include "mediainformation.h"
       
    30 
       
    31 #ifdef __FLOG_ACTIVE
       
    32 _LIT8(KLogComponent, LOG_COMPONENT_AVRCP_MEDIA_INFO);
       
    33 #endif
       
    34 
       
    35 EXPORT_C CRemConMediaInformationTarget* CRemConMediaInformationTarget::NewL(CRemConInterfaceSelector& aInterfaceSelector, 
       
    36 		MRemConMediaInformationTargetObserver& aObserver)
       
    37 	{
       
    38 	LOG_STATIC_FUNC
       
    39 
       
    40 	CRemConMediaInformationTarget* self = new(ELeave) CRemConMediaInformationTarget(aInterfaceSelector, aObserver);
       
    41 	CleanupStack::PushL(self);
       
    42 	self->ConstructL();
       
    43 	CleanupStack::Pop(self);
       
    44 	return self;
       
    45 	}
       
    46 
       
    47 CRemConMediaInformationTarget::CRemConMediaInformationTarget(CRemConInterfaceSelector& aInterfaceSelector, 
       
    48 		MRemConMediaInformationTargetObserver& aObserver)
       
    49 :	CRemConInterfaceBase(TUid::Uid(KRemConMediaInformationApiUid), 
       
    50 						 KMaxLengthMediaInformationMsg, 
       
    51 						 aInterfaceSelector,
       
    52 						 ERemConClientTypeTarget), 
       
    53 	iObserver(aObserver),
       
    54 	iAttributeIterator(iMediaAttributeIDs),
       
    55 	iMsgQueue(_FOFF(CRemConMediaInformationQueuedMessage, iLink))
       
    56 	{
       
    57 	}
       
    58 	
       
    59 void CRemConMediaInformationTarget::ConstructL()
       
    60 	{
       
    61 	iResponse = new(ELeave)RRemConGetElementAttributesResponse();
       
    62 	TCallBack cb(&NextMessageCb, this);
       
    63 	iNextMessageCallBack = new (ELeave) CAsyncCallBack(cb, CActive::EPriorityStandard);
       
    64 	BaseConstructL();
       
    65 	}
       
    66 	
       
    67 
       
    68 /** Destructor.
       
    69 
       
    70 @publishedAll
       
    71 @released
       
    72 */
       
    73 EXPORT_C CRemConMediaInformationTarget::~CRemConMediaInformationTarget()
       
    74 	{
       
    75 	iMediaAttributeIDs.Close();
       
    76 	iResponse->Close();
       
    77 	delete iResponse;
       
    78 	iNextMessageCallBack->Cancel();
       
    79 	delete iNextMessageCallBack;
       
    80 	TSglQueIter<CRemConMediaInformationQueuedMessage> iter(iMsgQueue);
       
    81 	CRemConMediaInformationQueuedMessage* msg;
       
    82 	iter.SetToFirst();
       
    83 	while ((msg = iter++) != NULL)
       
    84 		{
       
    85 		iMsgQueue.Remove(*msg);
       
    86 		delete msg;
       
    87 		}
       
    88 	}
       
    89 
       
    90 /** Gets a pointer to a specific interface version.
       
    91 
       
    92 @return A pointer to the interface, NULL if not supported.
       
    93 @internalComponent
       
    94 @released
       
    95 */
       
    96 TAny* CRemConMediaInformationTarget::GetInterfaceIf(TUid aUid)
       
    97 	{
       
    98 	TAny* ret = NULL;
       
    99 	if ( aUid == TUid::Uid(KRemConInterfaceIf1) )
       
   100 		{
       
   101 		ret = reinterpret_cast<TAny*>(
       
   102 			static_cast<MRemConInterfaceIf*>(this)
       
   103 			);
       
   104 		}
       
   105 
       
   106 	return ret;
       
   107 	}
       
   108 
       
   109 EXPORT_C TInt CRemConMediaInformationTarget::AttributeValue( TMediaAttributeId aAttributeId, TDesC8& aAttributeData )
       
   110 	{
       
   111 	// check that the values supplied were requested
       
   112 	if ( KErrNotFound == iMediaAttributeIDs.Find( aAttributeId ) )
       
   113 		{
       
   114 		return KErrNotFound;
       
   115 		}
       
   116 		
       
   117 	REAResponse resp;
       
   118 	resp.iAttributeId = aAttributeId;
       
   119 	resp.iCharset = KUtf8MibEnum;
       
   120 	resp.iStringLen = aAttributeData.Length();
       
   121 	resp.iString = aAttributeData.Alloc();
       
   122 	if (resp.iString == NULL)
       
   123 		{
       
   124 		return KErrNoMemory;
       
   125 		}
       
   126 	TInt status = iResponse->iAttributes.Append(resp);
       
   127 	if (status != KErrNone)
       
   128 		{
       
   129 		resp.Close();  // make sure heap string is de-allocated
       
   130 		}
       
   131 	return status;
       
   132 	}
       
   133 
       
   134 // from MRemConInterfaceIf
       
   135 void CRemConMediaInformationTarget::SendError(TInt aError)
       
   136 	{
       
   137 	RBuf8 outBuf;
       
   138 	if (outBuf.Create(KAVCFrameMaxLength) != KErrNone)
       
   139 		{
       
   140 		// On OOM drop the message
       
   141 		return;
       
   142 		}
       
   143 	
       
   144 	TInt error = 0;
       
   145 	RAvrcpIPCError response;
       
   146 	response.iError = aError;
       
   147 	TRAP(error, response.WriteL(outBuf));   // Don't send error if OOM
       
   148 	if (error == KErrNone)
       
   149 		{
       
   150 		InterfaceSelector().SendUnreliable(TUid::Uid(KRemConMediaInformationApiUid),
       
   151 							EGetElementAttributes, ERemConResponse, outBuf);
       
   152 		}
       
   153 	outBuf.Close();
       
   154 	}
       
   155 
       
   156 // from MRemConInterfaceIf
       
   157 void CRemConMediaInformationTarget::MrcibNewMessage(TUint aOperationId, const TDesC8& aData )
       
   158 	{
       
   159 	LOG1(_L("\taOperationId = 0x%02x"), aOperationId);
       
   160 	LOG1(_L("\taData.Length = %d"), aData.Length());
       
   161 
       
   162 	(void) aOperationId; // ignore warning about this variable being unused
       
   163 	
       
   164 	if (!iInProgress && iMsgQueue.IsEmpty())
       
   165 		{
       
   166 		ProcessMessage(aData);
       
   167 		}
       
   168 	else
       
   169 		{
       
   170 		CRemConMediaInformationQueuedMessage* msg = NULL;
       
   171 		TRAPD(err, msg = CRemConMediaInformationQueuedMessage::NewL(aData));
       
   172 		if (err == KErrNone)
       
   173 			{
       
   174 			iMsgQueue.AddLast(*msg);
       
   175 			}
       
   176 		}
       
   177 	}
       
   178 	
       
   179 void CRemConMediaInformationTarget::ProcessMessage(const TDesC8& aData)
       
   180 	{
       
   181 	iInProgress = ETrue;
       
   182 	// Try to read the incoming request
       
   183 	TInt error = KErrNone;
       
   184 	RRemConGetElementAttributesRequest request;
       
   185 	TRAP(error, request.ReadL(aData));
       
   186 
       
   187 	// Couldn't parse the request; tell them it was invalid
       
   188 	if (error != KErrNone)
       
   189 		{
       
   190 		request.Close();
       
   191 		return SendError(KErrAvrcpMetadataParameterNotFound);
       
   192 		}
       
   193 
       
   194 	// Specification section 5.3.1 (page 49) says unique id
       
   195 	// must be 0x0. All other values are currently reserved
       
   196 	if (request.iElement != 0)
       
   197 		{
       
   198 		request.Close();
       
   199 		return SendError(KErrAvrcpMetadataInvalidParameter);
       
   200 		}
       
   201 
       
   202 	// this may have been used by a previous GetElementAttributes, so
       
   203 	iMediaAttributeIDs.Reset();
       
   204 
       
   205 	if (request.iNumberAttributes == 0)
       
   206 		{
       
   207 		// spec says this is a request for all attribs
       
   208 		// current spec has 7 specified (0x01 to 0x07)
       
   209 		for (TInt i = 1; i <= 7; i++)
       
   210 			{
       
   211 			if (iMediaAttributeIDs.Append((TMediaAttributeId)i) != KErrNone)
       
   212 				{
       
   213 				request.Close();
       
   214 				return SendError(KErrAvrcpMetadataInternalError);
       
   215 				}
       
   216 			}
       
   217 		}
       
   218 	else
       
   219 		{
       
   220 		// No need to check request.iNumberAttributes == request.iAttributes.Count()
       
   221 		// as this must be correct or request.ReadL(aData) leaves
       
   222 		for (TInt i = 0; i < request.iNumberAttributes; i++)
       
   223 			{
       
   224 			TUint8 value = request.iAttributes[i];
       
   225 			if (value > 0 && value <= KMaxMediaAttributeValue )
       
   226 				{
       
   227 				if (iMediaAttributeIDs.Append((TMediaAttributeId)value) != KErrNone)
       
   228 					{
       
   229 						request.Close();
       
   230 						return SendError(KErrAvrcpMetadataInternalError);
       
   231 					}
       
   232 				}
       
   233 			}
       
   234 		}
       
   235 	request.Close();
       
   236 
       
   237 	// check that some valid attribute ids have been found
       
   238 	if (iMediaAttributeIDs.Count())
       
   239 		{
       
   240 		// if the client has not yet called Completed() on the last request
       
   241 		// clear the the attributes from the previous response
       
   242 		iResponse->Close();
       
   243 		
       
   244 		// reset the interator to the start, as it may have been used before
       
   245 		iAttributeIterator.Start();
       
   246 		
       
   247 		// call the client API to get the client value.
       
   248 		iObserver.MrcmitoGetCurrentlyPlayingMetadata(iAttributeIterator);
       
   249 		}
       
   250 	else
       
   251 		{
       
   252 		// no valid attribute ids found so return an error to bearer
       
   253 		SendError(KErrAvrcpMetadataParameterNotFound);
       
   254 		}
       
   255 	}
       
   256 
       
   257 // The client application has signaled that all attributes have been returned so 
       
   258 // response can now be sent
       
   259 EXPORT_C void CRemConMediaInformationTarget::Completed()
       
   260 	{
       
   261 	if (!iInProgress)
       
   262 		{
       
   263 		return;
       
   264 		}
       
   265 	// Finalise response; update number of attributes returned
       
   266 	iResponse->iNumberAttributes = iResponse->iAttributes.Count();
       
   267 
       
   268 	//Check the bound of the number of attributes, zero is not permitted
       
   269 	if (iResponse->iNumberAttributes == 0)
       
   270 		{
       
   271 		return SendError(KErrAvrcpMetadataInternalError);
       
   272 		}
       
   273 	
       
   274 	// Allocate a buffer for the formatted message
       
   275 	RBuf8 messageBuffer;
       
   276 	if ( messageBuffer.Create(iResponse->Size()) != KErrNone )
       
   277 		{
       
   278 		// On OOM drop the message
       
   279 		iResponse->Close();
       
   280 		return;
       
   281 		}
       
   282 		
       
   283 	// send the result back to the CT
       
   284 	TInt error = KErrNone;
       
   285 	TRAP(error, iResponse->WriteL(messageBuffer));
       
   286 	if (error == KErrNone)
       
   287 		{
       
   288 		InterfaceSelector().SendUnreliable(TUid::Uid(KRemConMediaInformationApiUid),
       
   289 								EGetElementAttributes, ERemConResponse, messageBuffer);
       
   290 		}
       
   291 	
       
   292 	// Make sure attribute list is reset for next time
       
   293 	iResponse->Close();
       
   294 	messageBuffer.Close();
       
   295 	
       
   296 	iInProgress = EFalse;
       
   297 	if (!iMsgQueue.IsEmpty())
       
   298 		{
       
   299 		iNextMessageCallBack->CallBack();
       
   300 		}
       
   301 	
       
   302 	}
       
   303 
       
   304 int CRemConMediaInformationTarget::NextMessageCb(TAny* aThis)
       
   305 	{
       
   306 	static_cast<CRemConMediaInformationTarget*>(aThis)->DoNextMessage();
       
   307 	return KErrNone;
       
   308 	}
       
   309 
       
   310 void CRemConMediaInformationTarget::DoNextMessage()
       
   311 	{
       
   312 	CRemConMediaInformationQueuedMessage* msg = iMsgQueue.First();
       
   313 	iMsgQueue.Remove(*msg);
       
   314 	ProcessMessage(msg->Data());
       
   315 	delete msg;
       
   316 	}
       
   317 
       
   318 EXPORT_C TMediaAttributeIter::TMediaAttributeIter(RArray<TMediaAttributeId>& aMediaAttributeIDs) :
       
   319     iMediaAttributeIDs(aMediaAttributeIDs),
       
   320     iterator(0)
       
   321 	{
       
   322 	}
       
   323 
       
   324 EXPORT_C void TMediaAttributeIter::Start()
       
   325 	{
       
   326 	iterator = 0;
       
   327 	}
       
   328 
       
   329 EXPORT_C TBool TMediaAttributeIter::Next(TMediaAttributeId& aId)
       
   330 	{
       
   331 	TInt count = iMediaAttributeIDs.Count();
       
   332 	if (iterator > count - 1)
       
   333 		{
       
   334 		return EFalse;
       
   335 		}
       
   336 	aId = iMediaAttributeIDs[iterator];
       
   337 	iterator++;
       
   338 	return ETrue;
       
   339 	}
       
   340 
       
   341 CRemConMediaInformationQueuedMessage* CRemConMediaInformationQueuedMessage::NewL(const TDesC8& aData)
       
   342 	{
       
   343 	CRemConMediaInformationQueuedMessage* self = new (ELeave) CRemConMediaInformationQueuedMessage();
       
   344 	CleanupStack::PushL(self);
       
   345 	self->ConstructL(aData);
       
   346 	CleanupStack::Pop(self);
       
   347 	return self;
       
   348 	}
       
   349 
       
   350 CRemConMediaInformationQueuedMessage::CRemConMediaInformationQueuedMessage()
       
   351 	{
       
   352 	
       
   353 	}
       
   354 
       
   355 void CRemConMediaInformationQueuedMessage::ConstructL(const TDesC8& aData)
       
   356 	{
       
   357 	iData.CreateL(aData);
       
   358 	}
       
   359 
       
   360 CRemConMediaInformationQueuedMessage::~CRemConMediaInformationQueuedMessage()
       
   361 	{
       
   362 	iData.Close();
       
   363 	}
       
   364 
       
   365 const TDesC8& CRemConMediaInformationQueuedMessage::Data()
       
   366 	{
       
   367 	return iData;
       
   368 	}
       
   369 
       
   370 
       
   371