--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/remconbeareravrcp/src/avrcpMetadataTransfer.cpp Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1078 @@
+// Copyright (c) 2006-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
+ @prototype
+*/
+
+#include <avcframe.h>
+#include <e32base.h>
+#include <remcon/remconbearerobserver.h>
+#include <remcon/remconconverterplugin.h>
+#include <remcon/messagetype.h>
+#include <remcon/avrcpspec.h>
+#include <remconbeareravrcp.h>
+
+#include <remconbatterytargetobserver.h>
+#include <absolutevolumeapi.h>
+#include <absolutevolumeutils.h>
+
+#include "avrcp.h"
+#include "controlcommand.h"
+#include "avrcpcommandframer.h"
+#include "avrcpinternalinterface.h"
+#include "avrcpipc.h"
+#include "avrcplog.h"
+#include "avrcputils.h"
+#include "avrcpincomingcommandhandler.h"
+#include "mediabrowse.h"
+#include "mediainformation.h"
+#include "nowplaying.h"
+#include "playerinformation.h"
+#include "remconbattery.h"
+#include "remcongroupnavigation.h"
+
+TInt CControlCommand::ParseMetadataTransferPassthroughCommand()
+ {
+ // company id and frame type should already be set before here
+ __ASSERT_DEBUG(iFrame->Type() == AVC::EControl, AvrcpUtils::Panic(EAvrcpCTypeNotSet));
+ __ASSERT_DEBUG(iVendorId == KBluetoothSIGVendorId, AvrcpUtils::Panic(EAvrcpCompanyIDNotSet));
+
+ TInt ret = KErrNotSupported;
+ TUint16 operation = MetadataTransferParser::GetPassThroughOperationId(iVendorPayloadData);
+ if (operation == ENextGroup)
+ {
+ iOperationId = ENextGroup;
+ iInterfaceUid = TUid::Uid(KRemConGroupNavigationApiUid);
+ ret = KErrNone;
+ }
+ else if (operation == EPreviousGroup)
+ {
+ iOperationId = EPreviousGroup;
+ iInterfaceUid = TUid::Uid(KRemConGroupNavigationApiUid);
+ ret = KErrNone;
+ }
+ return ret;
+ }
+
+/* Before calling this method, the following MUST be set:
+ * - Vendor Payload data
+ * - Opcode == Vendor Dependent
+ * - Subunit Type == Panel
+ * - Subunit Id == 0
+ */
+
+TInt CControlCommand::ParseMetadataTransferVendorCommand(CAVRCPFragmenter& aFragmenter)
+ {
+ __ASSERT_DEBUG(iFrame->Opcode() == AVC::EVendorDependent, AvrcpUtils::Panic(EAvrcpNotFullyConstructed));
+ __ASSERT_DEBUG(iFrame->SubunitType() == AVC::EPanel, AvrcpUtils::Panic(EAvrcpNotFullyConstructed));
+ __ASSERT_DEBUG(iFrame->SubunitID() == 0, AvrcpUtils::Panic(EAvrcpNotFullyConstructed));
+
+ TInt ret = KErrNotSupported;
+ iInterfaceUid = TUid::Uid(0);
+
+ TMetadataTransferPDUID metadataPDUID = MetadataTransferParser::GetPDUID(iVendorPayloadData);
+
+ TPtrC8 mtPayload(iVendorPayloadData.Mid(KRemConMetadataHeaderLength));
+
+ TUint paramLength = MetadataTransferParser::GetParamLength(iVendorPayloadData);
+
+ if (mtPayload.Length() != paramLength)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ // If we're in a fragmented state, and we receive an un-expected
+ // PDU (i.e. not CONTINUE or ABORT) then throw away the fragment
+ // and just process the request. The specification (section 5.5.1)
+ // isn't entirely clear as to what should happen, but Sian reckons
+ // this is probably the most polite thing to do (be liberal, etc)
+ if (aFragmenter.InFragmentedState())
+ {
+ if ( metadataPDUID != ERequestContinuingResponse
+ && metadataPDUID != EAbortContinuingResponse)
+ {
+ aFragmenter.Reset();
+ }
+ }
+
+ switch (iFrame->Type())
+ {
+ case AVC::EControl:
+ {
+ switch (metadataPDUID)
+ {
+ case ERequestContinuingResponse:
+ ret = ParseContinuingResponse(mtPayload, aFragmenter);
+ break;
+ case EAbortContinuingResponse:
+ ret = ParseAbortContinuingResponse(mtPayload, aFragmenter);
+ break;
+ case ESetPlayerApplicationSettingValue:
+ ret = ParseSetPlayerApplicationSettingValue(mtPayload);
+ break;
+
+ case EInformBatteryStatusOfCT:
+ ret = ParseInformBatteryStatusOfCT(mtPayload);
+ break;
+
+ case EInformDisplayableCharacterSet:
+ ret = KErrNotSupported;
+ break;
+ case ESetAddressedPlayer:
+ ret = ParseSetAddressedPlayer(mtPayload);
+ break;
+ case EPlayItem:
+ ret = ParsePlayItem(mtPayload);
+ break;
+ case EAddToNowPlaying:
+ ret = ParseAddToNowPlaying(mtPayload);
+ break;
+
+ case ESetAbsoluteVolume:
+ ret =ParseSetAbsoluteVolume(mtPayload);
+ break;
+ default:
+ // not allowed PDUID for Control
+ ret = KErrAvrcpMetadataInvalidCommand;
+ }
+ break;
+ }
+ case AVC::EStatus:
+ {
+ switch (metadataPDUID)
+ {
+ case EGetCapabilities:
+ ret = ParseGetCapabilities( mtPayload );
+ break;
+
+ case EGetPlayStatus:
+ ret = ParseGetPlayStatus( mtPayload );
+ break;
+
+ case EListPlayerApplicationSettingAttributes:
+ ret = ParseListPlayerApplicationSettingAttributes( mtPayload );
+ break;
+
+ case EListPlayerApplicationSettingValues:
+ ret = ParseListPlayerApplicationSettingValues( mtPayload );
+ break;
+
+ case EGetCurrentPlayerApplicationSettingValue:
+ ret = ParseGetCurrentPlayerApplicationSettingValue( mtPayload );
+ break;
+
+ case EGetPlayerApplicationSettingAttributeText:
+ ret = ParseGetPlayerApplicationSettingAttributeText( mtPayload );
+ break;
+
+ case EGetPlayerApplicationSettingValueText:
+ ret = ParseGetPlayerApplicationSettingValueText( mtPayload );
+ break;
+
+ case EGetElementAttributes:
+ ret = ParseGetElementAttributes(mtPayload );
+ break;
+
+ case ESetAddressedPlayer:
+ ret = ParseSetAddressedPlayer(mtPayload );
+ break;
+
+ case EPlayItem:
+ ret = ParsePlayItem(mtPayload );
+ break;
+
+ case EAddToNowPlaying:
+ ret = ParseAddToNowPlaying(mtPayload );
+ break;
+ default:
+ // not allowed PDUID for Status
+ ret = KErrAvrcpMetadataInvalidCommand;
+ }
+
+ break;
+ }
+ case AVC::ENotify:
+ {
+ if (metadataPDUID==ERegisterNotification)
+ {
+ if (mtPayload.Length() != KLengthRegisterNotification)
+ {
+ ret = KErrAvrcpMetadataInvalidCommand;
+ }
+ else
+ {
+ ret = KErrNone;
+ TRegisterNotificationEvent eventId = static_cast<TRegisterNotificationEvent>(mtPayload[KVendorDependentEventId]);
+ switch (eventId)
+ {
+ case ERegisterNotificationPlaybackStatusChanged:
+ case ERegisterNotificationTrackChanged:
+ case ERegisterNotificationTrackReachedEnd:
+ case ERegisterNotificationTrackReachedStart:
+ case ERegisterNotificationBatteryStatusChanged:
+ case ERegisterNotificationPlayerApplicationSettingChanged:
+ {
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ iOperationId = RAvrcpIPC::SetIPCOperationIdFromEventId(eventId);
+ break;
+ }
+ // Note: ERegisterNotificationPlaybackPosChanged takes a 4 byte parameter
+ case ERegisterNotificationPlaybackPosChanged:
+ {
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ iOperationId = RAvrcpIPC::SetIPCOperationIdFromEventId(eventId);
+ iCommandData.Close();
+ ret = iCommandData.Create(KLengthPlaybackPosChangedParam);
+ if (ret == KErrNone)
+ {
+ iCommandData.Append(mtPayload.Right(KLengthPlaybackPosChangedParam));
+ }
+ else
+ {
+ ret = KErrAvrcpMetadataInternalError;
+ }
+ break;
+ }
+
+ // Note ERegisterNotificationSystemStatusChanged is not supported
+ case ERegisterNotificationSystemStatusChanged_NotSupported:
+ {
+ ret = KErrNotSupported;
+ break;
+ }
+
+ case ERegisterNotificationNowPlayingContentChanged:
+ {
+ iInterfaceUid = TUid::Uid(KRemConNowPlayingApiUid);
+ iOperationId = RAvrcpIPC::SetIPCOperationIdFromEventId(eventId);
+ break;
+ }
+ case ERegisterNotificationAvailablePlayersChanged:
+ case ERegisterNotificationAddressedPlayerChanged:
+ case ERegisterNotificationUidsChanged:
+ {
+ iInterfaceUid = TUid::Uid(KUidAvrcpInternalInterface);
+ iOperationId = RAvrcpIPC::SetIPCOperationIdFromEventId(eventId);
+ ret = KErrAvrcpInternalCommand;
+ break;
+ }
+ case ERegisterNotificationVolumeChanged :
+ {
+ ret = ParseVolumeChangedNotification(mtPayload);
+ break;
+ }
+ default:
+ {
+ ret = KErrAvrcpMetadataInvalidParameter;
+ }
+ }
+ }
+ }
+ else
+ {
+ ret = KErrAvrcpMetadataInvalidCommand;
+ }
+ break;
+ }
+ case AVC::EReserved1:
+ case AVC::EReserved2:
+ case AVC::EReserved3:
+ case AVC::EReserved4:
+ {
+ ret = KErrAvrcpInvalidCType;
+ break;
+ }
+ default:
+ ret = KErrAvrcpMetadataInvalidCommand;
+ }
+
+ return ret;
+ }
+
+/** Allocate correct space and append the payload to iCommandData
+ */
+TInt CControlCommand::AppendIncomingPayload(const TPtrC8& aPayload)
+ {
+ iCommandData.Close();
+ if (iCommandData.Create(aPayload.Length()) != KErrNone)
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+ iCommandData.Append(aPayload);
+ return KErrNone;
+ }
+
+/** Decode a InformBatteryStatusOfCT PDU ID: 0x18 and call the BatteryStatus API
+ */
+TInt CControlCommand::ParseInformBatteryStatusOfCT(TPtrC8& aMtPayload)
+
+ {
+ if (aMtPayload.Length() != KLengthInformBatteryStatusOfCTPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ TUint8 batteryStatus = aMtPayload[0];
+ if (batteryStatus > EFullCharge)
+ {
+ return KErrAvrcpMetadataInvalidParameter;
+ }
+
+ if (AppendIncomingPayload(aMtPayload) != KErrNone)
+ {
+ return KErrAvrcpMetadataInvalidParameter;
+ }
+
+ iOperationId = EInformBatteryStatusOfCT;
+ iInterfaceUid = TUid::Uid(KRemConBatteryApiUid);
+
+ TInt ret = RespondToInforms(EInformBatteryStatusOfCT);
+ if (ret != KErrNone)
+ {
+ return ret;
+ }
+
+ return KErrAvrcpHandledInternallyInformRemCon;
+ }
+
+
+/** Decode PDU ID 0x40 - fragmentation support
+ */
+TInt CControlCommand::ParseContinuingResponse(TPtrC8& aMtPayload,
+ CAVRCPFragmenter& aFragmenter)
+ {
+ // Check if in fragmentation state, return error if not
+ if (! aFragmenter.InFragmentedState())
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ // Check if the parameter matches the fragmented response
+ TMetadataTransferPDUID pduId = MetadataTransferParser::GetPDUID(aMtPayload);
+ if (pduId != aFragmenter.GetPDU())
+ {
+ return KErrAvrcpMetadataInvalidParameter;
+ }
+
+ RBuf8 respPayload;
+ CAVCFrame* frame = NULL;
+ TRAPD(err, frame = CAVCVendorDependentResponse::NewL(KBluetoothSIGVendorId));
+ err = respPayload.Create(KAVCMaxVendorDependentPayload); //longest resp
+ if (err == KErrNone)
+ {
+ respPayload.Append(aFragmenter.GetNextFragmentHeader());
+ respPayload.Append(aFragmenter.GetNextFragment());
+ frame->SetType(AVC::EStable);
+ frame->Append(respPayload);
+ delete iFrame;
+ iFrame = frame;
+ respPayload.Close();
+ }
+ else
+ return KErrAvrcpMetadataInternalError;
+
+ return KErrAvrcpHandledInternallyRespondNow;
+ }
+
+
+/** Decode PDU ID 0x41 - fragmentation support
+ */
+TInt CControlCommand::ParseAbortContinuingResponse(TPtrC8& aMtPayload,
+ CAVRCPFragmenter& aFragmenter)
+ {
+ // Check if in fragmentation state, return error if not
+ if (! aFragmenter.InFragmentedState())
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ // Check if the parameter matches the fragmented response
+ TMetadataTransferPDUID pduId = MetadataTransferParser::GetPDUID(aMtPayload);
+ if (pduId != aFragmenter.GetPDU())
+ {
+ return KErrAvrcpMetadataInvalidParameter;
+ }
+
+ aFragmenter.Reset();
+
+ CAVCFrame* frame = NULL;
+ TRAPD(err, frame = CAVCVendorDependentResponse::NewL(KBluetoothSIGVendorId));
+ if (err == KErrNone)
+ {
+ frame->Append(EAbortContinuingResponse);
+ frame->Append(EUnfragmented);
+ // the package length is 0
+ frame->Append( 0 );
+ frame->Append( 0 );
+ frame->SetType(AVC::EStable);
+ delete iFrame;
+ iFrame = frame;
+ }
+ else
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+
+ return KErrAvrcpHandledInternallyRespondNow;
+ }
+
+
+/** Decode a SetPlayerApplicationSettingValue PDU ID: 0x14 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseSetPlayerApplicationSettingValue(TPtrC8& aMtPayload)
+ {
+ if (aMtPayload.Length() < KMinLengthSetPASValuePdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ // get the number of attributes contained
+ TUint8 numAttributes = aMtPayload[KVendorDependentNumberAttributes];
+
+ // Each attribute is 16 bits long
+ if (sizeof(numAttributes) + numAttributes*sizeof(TUint16) != aMtPayload.Length())
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = ESetPlayerApplicationSettingValue;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+/** Decode a GetCapabilities PDU ID: 0x10 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseGetCapabilities(TPtrC8& aMtPayload)
+ {
+ // check enough data available
+ if (aMtPayload.Length() != KLengthGetCapabilitiesPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ // pass one byte of data to Player Information API
+ iOperationId = EGetCapabilities;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+/** Decode a GetPlayStatus PDU ID: 0x30 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseGetPlayStatus(TPtrC8& aMtPayload)
+ {
+ // no payload in this command
+ if (aMtPayload.Length()!=KLengthGetPlayStatusPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EGetPlayStatus;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return KErrNone;
+ }
+
+/** Decode a ListPlayerApplicationSettingAttributes PDU ID: 0x11 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseListPlayerApplicationSettingAttributes(TPtrC8& aMtPayload)
+ {
+ // check length, there should be no parameters
+ if (aMtPayload.Length()!=KLengthListPASAttributesPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EListPlayerApplicationSettingAttributes;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return KErrNone;
+ }
+
+/** Decode a ListPlayerApplicationSettingValues PDU ID: 0x12 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseListPlayerApplicationSettingValues(TPtrC8& aMtPayload)
+ {
+ // check length, there should be 1 byte of data
+ if (aMtPayload.Length() != KLengthListPASValuesPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EListPlayerApplicationSettingValues;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+/** Decode a GetCurrentPlayerApplicationSettingValue PDU ID: 0x13 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseGetCurrentPlayerApplicationSettingValue(TPtrC8& aMtPayload)
+ {
+ // check the length
+ if (aMtPayload.Length() < KMinLengthGetCurrentPASValuePdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ TUint8 numAttributes = aMtPayload[KVendorDependentNumberAttributes];
+ if (sizeof(numAttributes) + numAttributes != aMtPayload.Length())
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EGetCurrentPlayerApplicationSettingValue;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+/** Decode a GetPlayerApplicationSettingAttributeText PDU ID: 0x15 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseGetPlayerApplicationSettingAttributeText(TPtrC8& aMtPayload)
+ {
+ if (aMtPayload.Length() < KMinLengthGetPASAttributeTextPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+ // get the number of attributes contained
+ TUint8 numAttributes = aMtPayload[KVendorDependentNumberAttributes];
+ if (sizeof(numAttributes) + numAttributes != aMtPayload.Length())
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EGetPlayerApplicationSettingAttributeText;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+/** Decode a GetPlayerApplicationSettingValueText PDU ID: 0x16 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseGetPlayerApplicationSettingValueText(TPtrC8& aMtPayload)
+ {
+ if (aMtPayload.Length() < KMinLengthGetPASValueTextPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ // get number of values; preceded by attributeId (1byte) and numValues (1byte)
+ TUint8 numValues = aMtPayload[KVendorDependentNumberAttribsPdu16];
+ if (sizeof(TUint8) + sizeof(numValues) + numValues != aMtPayload.Length())
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EGetPlayerApplicationSettingValueText;
+ iInterfaceUid = TUid::Uid(KRemConPlayerInformationUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+/** Decode a GetElementAttributes PDU ID: 0x20 and call the PlayerInformation API
+ */
+TInt CControlCommand::ParseGetElementAttributes(TPtrC8& aMtPayload)
+ {
+ LOG_FUNC
+
+ if (aMtPayload.Length() < KMinLengthGetElementAttributesPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EGetElementAttributes;
+ iInterfaceUid = TUid::Uid(KRemConMediaInformationApiUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+TInt CControlCommand::ParseSetAddressedPlayer(TPtrC8& aMtPayload)
+ {
+ LOG_FUNC
+
+ if (aMtPayload.Length() < KLengthSetAddressedPlayerPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EAvrcpInternalSetAddressedPlayer;
+ iInterfaceUid = TUid::Uid(KUidAvrcpInternalInterface);
+ TInt err = AppendIncomingPayload(aMtPayload);
+
+ return err == KErrNone ? KErrAvrcpInternalCommand : err;
+ }
+
+TInt CControlCommand::ParsePlayItem(TPtrC8& aMtPayload)
+ {
+ LOG_FUNC
+
+ if (aMtPayload.Length() < KMinLengthAddToNowPlayingPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EPlayItem;
+ iInterfaceUid = TUid::Uid(KRemConNowPlayingApiUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+TInt CControlCommand::ParseAddToNowPlaying(TPtrC8& aMtPayload)
+ {
+ LOG_FUNC
+
+ if (aMtPayload.Length() < KMinLengthAddToNowPlayingPdu)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = EAddToNowPlaying;
+ iInterfaceUid = TUid::Uid(KRemConNowPlayingApiUid);
+ return AppendIncomingPayload(aMtPayload);
+ }
+
+TInt CControlCommand::ParseUidsChangedNotification(TPtrC8& /*aMtPayload*/)
+ {
+ LOG_FUNC
+ iInterfaceUid = TUid::Uid(KRemConMediaBrowseApiUid);
+ iOperationId = RAvrcpIPC::SetIPCOperationIdFromEventId(ERegisterNotificationUidsChanged);
+
+ return KErrAvrcpHandledInternallyRespondNow;
+ }
+
+TInt CControlCommand::ParseVolumeChangedNotification(TPtrC8& /*aMtPayload*/)
+ {
+ LOG_FUNC
+ iInterfaceUid = TUid::Uid(KRemConAbsoluteVolumeTargetApiUid);
+ iOperationId = KRemConAbsoluteVolumeNotification;
+
+ return KErrNone;
+ }
+
+TInt CControlCommand::GenerateMetadataResponsePayload(MRemConBearerObserver& aObserver, RBuf8& aFramePayload, const RBuf8& aResponseData)
+ {
+ TInt err = KErrNone;
+
+ // If it's a very large response; this requires re-allocating the buffer
+ if (aResponseData.Length() > KAVCFrameMaxLength)
+ {
+ aFramePayload.Close();
+ if (aFramePayload.Create(aResponseData.Length()) != KErrNone)
+ return KErrAvrcpMetadataInternalError;
+ }
+
+ // Obtain the PDU from the combined PDU + (possible) notification eventId
+ TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId);
+ aFramePayload.Zero();
+ aFramePayload.Append(pduId);
+ aFramePayload.Append(EUnfragmented);
+
+ //Check whether it is absolute volume response.
+ TBool absoluteVolumeResponse = EFalse;
+ if (pduId == ESetAbsoluteVolume)
+ {
+ absoluteVolumeResponse = ETrue;
+ }
+ else if (pduId == ERegisterNotification)
+ {
+ TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId);
+ if (eventId == ERegisterNotificationVolumeChanged)
+ {
+ absoluteVolumeResponse = ETrue;
+ }
+ }
+
+ TPtr8 responseData(NULL, 0);
+ if (absoluteVolumeResponse)
+ {
+ responseData.Set(aResponseData.RightTPtr(aResponseData.Length()));
+ }
+ else
+ {
+ // Read 4 byte Big-Endian error code before the payload
+ RAvrcpIPCError response;
+ TRAP(err, response.ReadL(aResponseData));
+
+ // If we couldn't parse the response via IPC, send an internal error
+ if (err != KErrNone)
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+
+ // If an error occurred, return it (now that we've filled in the PDU id)
+ if (response.iError != KErrNone)
+ {
+ return response.iError;
+ }
+
+ // Pass the rest of the response (minus error code) to be parsed
+ responseData.Set(aResponseData.RightTPtr(aResponseData.Length() - KLengthErrorResponse));
+ }
+
+ switch (pduId)
+ {
+ case ESetPlayerApplicationSettingValue:
+ {
+ // the package length is 0
+ aFramePayload.Append( 0 );
+ aFramePayload.Append( 0 );
+ break;
+ }
+
+ case EGetCapabilities:
+ {
+ TRAP(err,GenerateMetadataGetCapabilitiesResponsePayloadL(aObserver, aFramePayload, aResponseData));
+ if(err != KErrNone)
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+ break;
+ }
+ case EListPlayerApplicationSettingAttributes:
+ case EListPlayerApplicationSettingValues:
+ case EGetCurrentPlayerApplicationSettingValue:
+ case EGetPlayerApplicationSettingAttributeText:
+ case EGetPlayerApplicationSettingValueText:
+ case EGetElementAttributes:
+ case EGetPlayStatus:
+ case EPlayItem:
+ case EAddToNowPlaying:
+ case ESetAddressedPlayer:
+ {
+ // the package length is the response length
+ TInt packageLength = responseData.Length();
+ aFramePayload.Append(packageLength>>8);
+ aFramePayload.Append(packageLength);
+ aFramePayload.Append(responseData);
+ break;
+ }
+ case ESetAbsoluteVolume:
+ {
+ TRAPD(err, GenerateSetAbsoluteVolumeResponsePayloadL(aFramePayload,responseData));
+ if (err != KErrNone)
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+ break;
+ }
+ case ERegisterNotification:
+ {
+ GenerateNotificationResponsePayload(aFramePayload, responseData);
+ break;
+ }
+ default:
+ {
+ return KErrNotSupported;
+ }
+ }
+
+ // Success. Error conditions have been handled previously
+ return KErrNone;
+ }
+
+void CControlCommand::GenerateSetAbsoluteVolumeResponsePayloadL(
+ RBuf8& aFramePayload,
+ const TDesC8& responseData)
+ {
+ RRemConAbsoluteVolumeResponse response;
+ CleanupClosePushL(response);
+
+ response.ReadL(responseData);
+ if (response.iError != KErrNone)
+ {
+ User::Leave(response.iError);
+ }
+ TUint8 absVol = KAvrcpMaxAbsoluteVolume * response.iVolume / response.iMaxVolume;
+ TUint16 len = KLengthSetAbsoluteVolumeResponseParamter<<8 & 0xffff;
+ TPckgBuf<TUint16> parameterLength(len);
+ aFramePayload.Append(parameterLength);
+ aFramePayload.Append( absVol );
+
+ CleanupStack::PopAndDestroy(&response);
+ }
+
+void CControlCommand::DoGenerateNotifyVolumeChangeResponsePayloadL(
+ RBuf8& aFramePayload,
+ const TDesC8& responseData)
+ {
+ RRemConAbsoluteVolumeResponse response;
+ CleanupClosePushL(response);
+
+ response.ReadL(responseData);
+ if (response.iError != KErrNone)
+ {
+ User::Leave(response.iError);
+ }
+ TUint8 absVol = KAvrcpMaxAbsoluteVolume * response.iVolume / response.iMaxVolume;
+ TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId);
+ TUint16 len = KLengthNotifyVolumeChangeResponseParameter<<8 & 0xffff;
+ TPckgBuf<TUint16> parameterLength(len);
+ aFramePayload.Append( parameterLength );
+ aFramePayload.Append( eventId );
+ aFramePayload.Append( absVol );
+
+ CleanupStack::PopAndDestroy(&response);
+ }
+
+TInt CControlCommand::GenerateNotificationResponsePayload(RBuf8& aFramePayload, const TDesC8& responseData)
+ {
+ TInt err = KErrNone;
+
+ TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId);
+ switch(eventId)
+ {
+ case ERegisterNotificationVolumeChanged:
+ {
+ TRAPD(err, DoGenerateNotifyVolumeChangeResponsePayloadL(aFramePayload, responseData));
+ if (err != KErrNone)
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+ break;
+ }
+ case ERegisterNotificationPlaybackStatusChanged:
+ case ERegisterNotificationTrackChanged:
+ case ERegisterNotificationTrackReachedEnd:
+ case ERegisterNotificationTrackReachedStart:
+ case ERegisterNotificationPlaybackPosChanged:
+ case ERegisterNotificationBatteryStatusChanged:
+ case ERegisterNotificationPlayerApplicationSettingChanged:
+ case ERegisterNotificationNowPlayingContentChanged:
+ case ERegisterNotificationAvailablePlayersChanged:
+ case ERegisterNotificationAddressedPlayerChanged:
+ case ERegisterNotificationUidsChanged:
+ {
+ TUint paramLength = responseData.Length() + 1;
+ aFramePayload.Append( paramLength >>8 );
+ aFramePayload.Append( paramLength );
+ aFramePayload.Append( eventId );
+ aFramePayload.Append( responseData );
+ break;
+ }
+ default:
+ {
+ err = KErrNotSupported;
+ break;
+ }
+ };
+
+ return err;
+ }
+
+TInt CControlCommand::GenerateMetadataGetCapabilitiesResponsePayloadL(MRemConBearerObserver& /* aObserver */, RBuf8& aFramePayload, const RBuf8& aResponseData)
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG( iPlayerInfoManager != NULL, AvrcpUtils::Panic(EAvrcpNotFullyConstructed));
+ TPtr8 responseData = aResponseData.RightTPtr(aResponseData.Length() - KLengthErrorResponse);
+
+ if(responseData[KCapabilityIdOffset] == ECapabilityIdEventsSupported)
+ {
+ RBuf8 eventsBuf;
+ eventsBuf.CreateL(KNumberEventsNotInPlayerInfoApi);
+ CleanupClosePushL(eventsBuf);
+ TInt count = 0;
+
+ // if ClientId has been set it means that we've told the remote that
+ // commands are being addressed to a particular player, so return
+ // player specific info. Otherwise return generic support.
+ if(ClientId() == KNullClientId || iPlayerInfoManager->AbsoluteVolumeSupportedL(ClientId()))
+ {
+ count++;
+ eventsBuf.Append(ERegisterNotificationVolumeChanged );
+ }
+
+ if(ClientId() == KNullClientId || iPlayerInfoManager->BrowsingSupportedL(ClientId()))
+ {
+ count += 2;
+ eventsBuf.Append(ERegisterNotificationNowPlayingContentChanged );
+ eventsBuf.Append(ERegisterNotificationUidsChanged );
+ }
+
+ // Always mark support for stuff that's handled internally rather than
+ // by the player
+ count+= 2;
+ eventsBuf.Append(ERegisterNotificationAvailablePlayersChanged );
+ eventsBuf.Append(ERegisterNotificationAddressedPlayerChanged );
+
+ responseData[1] += count;
+
+ TInt packageLength = responseData.Length()+ count;
+ aFramePayload.Append(packageLength>>8);
+ aFramePayload.Append(packageLength);
+ aFramePayload.Append(responseData);
+ aFramePayload.Append(eventsBuf);
+
+ CleanupStack::PopAndDestroy(&eventsBuf);
+ }
+ else
+ {
+ TInt packageLength = responseData.Length();
+ aFramePayload.Append(packageLength>>8);
+ aFramePayload.Append(packageLength);
+ aFramePayload.Append(responseData);
+ }
+ return KErrNone;
+ }
+TMetadataTransferPDUID MetadataTransferParser::GetNotifyEventID(const TPtrC8& aData)
+ {
+ return static_cast<TMetadataTransferNotifyEventID>(aData[KVendorDependentNotifyEventIdOffset]);
+ }
+
+TMetadataTransferPDUID MetadataTransferParser::GetPDUID(const TPtrC8& aData)
+ {
+ return static_cast<TMetadataTransferPDUID>(aData[KVendorDependentRequestPDUId]);
+ }
+
+TUint16 MetadataTransferParser::GetParamLength(const TPtrC8& aData)
+ {
+ TUint16 paramLength;
+ paramLength = aData[KVendorDependentRequestParamLenMSB] << 8;
+ paramLength += aData[KVendorDependentRequestParamLenLSB];
+ return paramLength;
+ }
+
+TUint16 MetadataTransferParser::GetPassThroughOperationId(const TPtrC8& aData)
+ {
+ TUint16 operation;
+ operation = aData[KPassThroughRequestOperationIdMSB] << 8;
+ operation += aData[KPassThroughRequestOperationIdLSB];
+ return operation;
+ }
+
+
+TInt CControlCommand::RespondToInforms(TMetadataTransferPDUID aMetadataPDUID)
+ {
+ CAVCFrame* frame = NULL;
+ TRAPD(err, frame = CAVCVendorDependentResponse::NewL(KBluetoothSIGVendorId));
+
+ RBuf8 respPayload;
+ err = respPayload.Create(KAVRCPMinVendorDependentResponseLen);
+ if (err == KErrNone)
+ {
+ respPayload.Append(aMetadataPDUID);
+ respPayload.Append(EUnfragmented); // No fragmentation needed
+ respPayload.Append(0); // no params
+ respPayload.Append(0); // no params
+
+ frame->SetType(AVC::EAccepted);
+ frame->Append(respPayload);
+
+ delete iFrame;
+ iFrame = frame;
+ respPayload.Close();
+ }
+ else
+ {
+ err = KErrAvrcpMetadataInternalError;
+ }
+ return err;
+ }
+
+void CControlCommand::GenerateMetadataRejectPayloadL(TInt aError)
+ {
+ CAVCFrame* frame = CAVCVendorDependentResponse::NewL(KBluetoothSIGVendorId);
+ frame->SetType(AVC::ERejected);
+
+ frame->Append(iFrame->Data()[6]); // PDU ID
+ frame->Append(EUnfragmented);
+
+ // Param length - 2 bytes
+ frame->Append(0x0);
+ frame->Append(0x1);
+
+ TUint8 avcError = 0;
+ switch (aError)
+ {
+ case KErrAvrcpMetadataInvalidCommand:
+ {
+ avcError = EInvalidCommand;
+ break;
+ }
+ case KErrAvrcpMetadataInvalidParameter:
+ {
+ avcError = EInvalidParameter;
+ break;
+ }
+ case KErrAvrcpMetadataParameterNotFound:
+ {
+ avcError = EParameterNotFound;
+ break;
+ }
+ case KErrAvrcpMetadataInternalError:
+ {
+ avcError = EInternalError;
+ break;
+ }
+ case KErrAvrcpAirInvalidCommand:
+ case KErrAvrcpAirInvalidParameter:
+ case KErrAvrcpAirParameterNotFound:
+ case KErrAvrcpAirInternalError:
+ case KErrAvrcpAirSuccess:
+ case KErrAvrcpAirUidChanged:
+ case KErrAvrcpAirReserved:
+ case KErrAvrcpAirInvalidDirection:
+ case KErrAvrcpAirNotADirectory:
+ case KErrAvrcpAirDoesNotExist:
+ case KErrAvrcpAirInvalidScope:
+ case KErrAvrcpAirRangeOutOfBounds:
+ case KErrAvrcpAirUidIsADirectory:
+ case KErrAvrcpAirMediaInUse:
+ case KErrAvrcpAirNowPlayingListFull:
+ case KErrAvrcpAirSearchNotSupported:
+ case KErrAvrcpAirSearchInProgress:
+ case KErrAvrcpAirInvalidPlayerId:
+ case KErrAvrcpAirPlayerNotBrowesable:
+ case KErrAvrcpAirPlayerNotAddressed:
+ case KErrAvrcpAirNoValidSearchResults:
+ case KErrAvrcpAirNoAvailablePlayers:
+ case KErrAvrcpAirAddressedPlayerChanged:
+ {
+ avcError = KErrAvrcpAirBase - aError;
+ break;
+ }
+ }
+ frame->Append(avcError);
+ delete iFrame;
+ iFrame = frame;
+ }
+
+/** Decode a SetAbsoluteVolume PDU ID: 0x50 and SetAbsoluteTarget call the API
+ */
+TInt CControlCommand::ParseSetAbsoluteVolume(TPtrC8& aMtPayload)
+ {
+ if (aMtPayload.Length() != KLengthSetAbsoluteVolumeRequestParameter)
+ {
+ return KErrAvrcpMetadataInvalidCommand;
+ }
+
+ iOperationId = KRemConSetAbsoluteVolume;
+ iInterfaceUid = TUid::Uid(KRemConAbsoluteVolumeTargetApiUid);
+
+ TBuf8<KAbsoluteVolumeRequestDataSize> payload;
+ TRAPD(err, DoParseSetAbsoluteVolumeL(aMtPayload, payload));
+ if (err != KErrNone)
+ {
+ return KErrAvrcpMetadataInternalError;
+ }
+
+ return AppendIncomingPayload(payload);
+ }
+
+void CControlCommand::DoParseSetAbsoluteVolumeL(const TPtrC8& aMtPayload, TDes8& aPayload)
+ {
+ RRemConAbsoluteVolumeRequest request;
+ CleanupClosePushL(request);
+ request.iVolume = KAbsoluteVolumeMask & aMtPayload[KLengthSetAbsoluteVolumeRequestParameter - 1];
+ request.iMaxVolume = KAvrcpMaxAbsoluteVolume;
+ request.WriteL(aPayload);
+ CleanupStack::PopAndDestroy(&request);
+ }