diff -r 000000000000 -r f63038272f30 bluetoothappprofiles/avrcp/mediainformationapi/src/mediainformationapi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothappprofiles/avrcp/mediainformationapi/src/mediainformationapi.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -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 +#include +#include +#include +#include +#include + +#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 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( + static_cast(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(aThis)->DoNextMessage(); + return KErrNone; + } + +void CRemConMediaInformationTarget::DoNextMessage() + { + CRemConMediaInformationQueuedMessage* msg = iMsgQueue.First(); + iMsgQueue.Remove(*msg); + ProcessMessage(msg->Data()); + delete msg; + } + +EXPORT_C TMediaAttributeIter::TMediaAttributeIter(RArray& 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; + } + + +