bluetoothappprofiles/avrcp/remconbeareravrcp/src/controlcommand.cpp
changeset 0 f63038272f30
child 11 a42ed326b458
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/remconbeareravrcp/src/controlcommand.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1685 @@
+// Copyright (c) 2004-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 <avcframe.h>
+#include <e32base.h>
+#include <remcon/remconbearerobserver.h>
+#include <remcon/remconconverterplugin.h>
+#include <remcon/messagetype.h>
+#include <remconbeareravrcp.h>
+
+#include <absolutevolumeapi.h>
+#include <absolutevolumeutils.h>
+#include <remcon/avrcpspec.h>
+#include "controlcommand.h"
+#include "avrcpcommandframer.h"
+#include "avrcpfragmenter.h"
+#include "avrcpinternalinterface.h"
+#include "avrcpipc.h"
+#include "avrcplog.h"
+#include "avrcputils.h"
+#include "avrcpincomingcommandhandler.h"
+#include "avrcp.h"
+#include "mediabrowse.h"
+#include "mediainformation.h"
+#include "nowplaying.h"
+#include "playerinformation.h"
+#include "remconbattery.h"
+#include "remcongroupnavigation.h"
+
+//---------------------------------------------------------------------
+// Outgoing command construction
+//---------------------------------------------------------------------
+
+/** Factory function.
+
+@param aInterfaceUid The RemCon interface uid of this command.
+@param aCommand The operation id of this command within the interface defined
+				by aInterface Uid.
+@param aRemConId The RemCon transaction label.
+@param aTransactionLabel The AVCTP transaction label.
+@param aCommandData The RemCon command data associated with this command.
+@param aIsClick Whether this command is a button click (ie RemCon believes
+				that this and the other part of the click constitute one
+				command.
+@param aAddr The bluetooth address to send this command to.
+@return A fully constructed CControlCommand.
+@leave System wide error codes.
+*/
+CControlCommand* CControlCommand::NewL(TUid aInterfaceUid,
+	TUint aCommand, 
+	TUint aRemConId, 
+	SymbianAvctp::TTransactionLabel aTransactionLabel, 
+	RBuf8& aCommandData, 
+	TBool aIsClick, 
+	const TBTDevAddr& aAddr,
+	TBool aKnownToBearer)
+	{
+	LOG_STATIC_FUNC
+	CControlCommand* command = new (ELeave) CControlCommand(aInterfaceUid, aCommand, 
+			aRemConId, aTransactionLabel, aCommandData, aIsClick, aAddr, aKnownToBearer);
+	CleanupStack::PushL(command);
+	command->ConstructL();
+	CleanupStack::Pop(command);
+	return command;
+	}
+
+/** Constructor.
+
+@param aInterfaceUid The RemCon interface uid of this command.
+@param aCommand The operation id of this command within the interface defined
+				by aInterface Uid.
+@param aRemConId The RemCon transaction label.
+@param aTransactionLabel The AVCTP transaction label.
+@param aCommandData The RemCon command data associated with this command.
+@param aIsClick Whether this command is a button click (ie RemCon believes
+				that this and the other part of the click constitute one
+				command.
+@param aAddr The bluetooth address to send this command to.
+@return A constructed CControlCommand.
+@leave System wide error codes.
+*/
+CControlCommand::CControlCommand(TUid aInterfaceUid,
+	TUint aCommand,
+	TUint aRemConId, 
+	SymbianAvctp::TTransactionLabel aTransactionLabel, 
+	RBuf8& aCommandData,
+	TBool aIsClick,
+	const TBTDevAddr& aAddr,
+	TBool aKnownToBearer) 
+	: CAvrcpCommand(aRemConId, aTransactionLabel, aAddr)
+	{
+	LOG_FUNC
+	
+	iIsClick = aIsClick;
+	iInterfaceUid = aInterfaceUid;
+	iOperationId = aCommand;
+	iKnownToBearer = aKnownToBearer;
+	
+	iCommandData.Assign(aCommandData);
+	aCommandData.Assign(NULL);
+	iPlayerInfoManager = NULL;
+	}
+	
+//---------------------------------------------------------------------
+// Incoming command construction
+//---------------------------------------------------------------------
+
+/** Factory function.
+
+@param aMessageInformation A buffer containing AV/C frame this command is to represent.
+@param aRemConId The RemCon transaction label.
+@param aTransLabel The AVCTP transaction label.
+@param aAddr The bluetooth address to send the response to.
+@param aClientId The RemCon client that should receive this command
+@return A fully constructed CControlCommand.
+@leave System wide error codes.
+*/
+CControlCommand* CControlCommand::NewL(CAVCFrame* aFrame, 
+	TUint aRemConId, 
+	SymbianAvctp::TTransactionLabel aTransLabel, 
+	const TBTDevAddr& aAddr,
+	const TRemConClientId& aClientId,
+	CAvrcpPlayerInfoManager* aPlayerInfoManager)
+	{
+	LOG_STATIC_FUNC
+	CControlCommand* command = new(ELeave)CControlCommand(aFrame, aRemConId, aTransLabel, aAddr, aClientId, aPlayerInfoManager);
+	CleanupStack::PushL(command);
+	command->ConstructL();
+	CleanupStack::Pop(command);
+	return command;
+	}
+
+/** Constructor.
+
+@param aRemConId The RemCon transaction label.
+@param aTransLabel The AVCTP transaction label.
+@param aAddr The bluetooth address to send the response to.
+@param aClientId The RemCon client that should receive this command
+@return A partially constructed CControlCommand.
+@leave System wide error codes.
+*/	
+CControlCommand::CControlCommand(CAVCFrame* aFrame, 
+	TUint aRemConId, 
+	SymbianAvctp::TTransactionLabel aTransLabel, 
+	const TBTDevAddr& aAddr,
+	const TRemConClientId& aClientId,
+	CAvrcpPlayerInfoManager* aPlayerInfoManager) 
+	: CAvrcpCommand(aRemConId, aTransLabel, aAddr)
+	, iFrame(aFrame)
+	, iClientId(aClientId)
+	{
+	LOG_FUNC
+
+	iIsClick = ETrue; // Assume click until we know otherwise
+	iPlayerInfoManager = aPlayerInfoManager;
+	}
+
+//---------------------------------------------------------------------
+// Generic construction/destruction
+//---------------------------------------------------------------------
+
+/** Destructor.
+*/
+CControlCommand::~CControlCommand()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iUsers == 0, AvrcpUtils::Panic(EAvrcpCommandStillInUse));
+	__ASSERT_ALWAYS(!iHandlingLink.IsQueued(), AvrcpUtils::Panic(EAvrcpCommandStillQueuedForHandling));
+	__ASSERT_ALWAYS(!iReadyLink.IsQueued(), AvrcpUtils::Panic(EAvrcpCommandStillQueuedAsReady));
+	__ASSERT_ALWAYS(!iSendLink.IsQueued(), AvrcpUtils::Panic(EAvrcpCommandStillQueuedForSending));
+	delete iFrame;
+	iCommandData.Close();
+	delete iTimerEntry;
+	delete iTimerExpiryInfo;
+	}
+	
+/** Second phase construction.
+
+@leave System wide error codes.
+*/
+void CControlCommand::ConstructL()
+	{
+	LOG_FUNC
+
+	// Allocate these now so we know we have the memory.  Info is
+	// irrelevant as we won't add to the timer's queue without 
+	// setting the true info.
+	TCallBack callback(DummyCallback, NULL);
+	iTimerEntry = new(ELeave)TDeltaTimerEntry(callback);
+	iTimerExpiryInfo = new(ELeave)TAvrcpTimerExpiryInfo(NULL, *this);
+	}
+	
+//------------------------------------------------------------------------------------
+// From MRcpTimerNotify
+//------------------------------------------------------------------------------------	
+
+/** Get the timer entry.
+
+@return Timer entry.
+*/
+TDeltaTimerEntry* CControlCommand::TimerEntry()
+	{
+	return iTimerEntry;
+	}
+	
+/** Get the timer expiry info.
+
+@return Timer expiry info.
+*/
+TAvrcpTimerExpiryInfo* CControlCommand::TimerExpiryInfo()
+	{
+	return iTimerExpiryInfo;
+	}
+
+/** Remove this command's timer entry from the queue.
+
+@param aTimer The timer queue to remove this from.
+*/	
+void CControlCommand::CancelTimer(CDeltaTimer& aTimer)
+	{
+	LOG_FUNC
+
+	aTimer.Remove(*iTimerEntry);
+	}
+	
+//------------------------------------------------------------------------------------
+// Called by bearer
+//------------------------------------------------------------------------------------
+
+const TRemConClientId& CControlCommand::ClientId() const
+	{
+	return iClientId;
+	}
+//------------------------------------------------------------------------------------
+// Called by handlers
+//------------------------------------------------------------------------------------
+
+/** Creates iFrame.
+
+This function must be called between creating this command and using it.
+
+@param aInterfaceUid	The RemCon interface this command came from.
+@param aCommand			The command id within the interface identified by aInterfaceUid.
+@param aCommandData		Data supplied with this command by RemCon.  The format of this
+						data is defined by RemCon and is dependent on aInterfaceUid and 
+						aCommand.
+@leave System wide error code if parsing could not complete.
+*/
+void CControlCommand::ProcessOutgoingCommandL(MRemConBearerObserver& aObserver)
+	{
+	LOG_FUNC
+			
+	switch(iInterfaceUid.iUid)
+		{
+		//Process the absolute volume controller api
+		case KRemConAbsoluteVolumeControllerApiUid:
+			{
+			switch (iOperationId)
+			    {
+			    //Registers absolute volume changed
+			    case KRemConAbsoluteVolumeNotification:
+			        {
+					iFrame = AvrcpCommandFramer::NotifyVolumeChangeCommandL();
+			        break;
+			        }
+			    //Sets absolute volume.
+			    case KRemConSetAbsoluteVolume:
+			    	{
+			    	//Gets the absolute volume to be set.
+			    	RRemConAbsoluteVolumeRequest setAbsVol;
+			    	CleanupClosePushL(setAbsVol);
+					setAbsVol.ReadL(iCommandData);
+					
+					__ASSERT_ALWAYS(setAbsVol.iVolume <= setAbsVol.iMaxVolume, 
+							AvrcpUtils::Panic(EAvrcpVolumeBeyondMaxVolume));
+					
+					TUint8 absVol = KAvrcpMaxAbsoluteVolume * setAbsVol.iVolume / setAbsVol.iMaxVolume;
+					iFrame = AvrcpCommandFramer::SetAbsoluteVolumeCommandL(absVol);	
+					CleanupStack::PopAndDestroy(&setAbsVol);					
+			    	break;
+			    	}
+			    default:
+			    	{
+			    	User::Leave(KErrNotSupported);
+			    	}
+			    
+			    }			
+			break;
+			}
+		case KRemConCoreApiUid:
+			{
+			// Default interface - all commands are passthrough
+			AVCPanel::TOperationId avrcpOp;
+			
+			if((RemConToAvrcpOperation(iOperationId, avrcpOp) != KErrNone) ||
+			   (iCommandData.Length() < KRemConCoreApiButtonDataLength))
+				{
+				User::Leave(KErrCorrupt);
+				}
+			else
+				{
+				TInt remConButtonAct;
+				AvrcpUtils::ReadCommandDataToInt(iCommandData, 
+					KRemConCoreApiCommandDataOffset + KRemConCoreApiButtonDataOffset,
+					KRemConCoreApiButtonDataLength, remConButtonAct);
+		
+				AVCPanel::TButtonAction buttonAct = (remConButtonAct == ERemConCoreApiButtonPress) ? 
+					AVCPanel::EButtonPress : AVCPanel::EButtonRelease;
+
+				iFrame = AvrcpCommandFramer::PassthroughL(avrcpOp, buttonAct);
+				if(iIsClick)
+					{
+					// restore our mangled command data
+					AvrcpUtils::SetCommandDataFromInt(iCommandData, 
+						KRemConCoreApiCommandDataOffset + KRemConCoreApiButtonDataOffset,
+						KRemConCoreApiButtonDataLength, ERemConCoreApiButtonClick);
+					}
+				}
+			break;
+			}	
+		default:
+			{
+			RBuf8 buf;
+			buf.CreateMaxL(KAVCFrameMaxLength);
+			User::LeaveIfError(aObserver.InterfaceToBearer(TUid::Uid(KRemConBearerAvrcpImplementationUid), 
+				iInterfaceUid, iOperationId, iCommandData, ERemConCommand, buf));
+
+			CleanupClosePushL(buf);
+			iFrame = CAVCFrame::NewL(buf, AVC::ECommand);
+			CleanupStack::PopAndDestroy(&buf);
+			break;
+			}
+		};
+	}
+	
+/** Fills in command info from iFrame.
+
+This must be called by the command handler before handling this
+command.
+
+This functions sets iInterfaceUid, iOperationId and iCommandData
+to the correct values according to iFrame.  The format of iCommandData
+is defined by RemCon and is dependent on iInterfaceUid and iOperationId.
+
+@return KErrNone				If the frame has been parsed successfully.
+@return KErrNotSupported		This frame represents a command for which a
+								RemCon converter or client side interface
+								cannot be found.
+@return KErrAvrcpInvalidCType	The CType specified in this frame is invalid.
+@return KErrAvrcpMetadataInvalidCommand		The AVRCP command is invalid.
+@return KErrAvrcpMetadataInvalidParameter	The AVRCP parameter is invalid.
+@return KErrAvrcpMetadataParameterNotFound	The AVRCP parameter was not found.
+@return KErrAvrcpMetadataInternalError		An AVRCP internal error occurred (such as out-of-memory,
+											or an inter-process communication error)
+@return KErrCorrupt	        	If the frame is corrupted(e.g invalid Operation Id).
+@return	System wide error code.
+*/
+TInt CControlCommand::ParseIncomingCommandL(MRemConBearerObserver& aObserver, CAVRCPFragmenter& aFragmenter)
+	{
+	LOG_FUNC
+	TInt err = KErrNotSupported;
+	
+	switch(iFrame->Type())
+		{
+		// check it isn't a reponse
+		case AVC::ENotImplemented:
+		case AVC::EAccepted:
+		case AVC::ERejected:
+		case AVC::EInTransition:
+		case AVC::EImplemented:
+		case AVC::EChanged:
+		case AVC::EInterim:
+		case 0x0E:	// not given a enum for SC reasons; reserved response code in spec
+			{
+			// We were told this was a command, can't go using response
+			// CTypes here matey
+			err = KErrAvrcpInvalidCType;
+			break;
+			}
+		case AVC::EGeneralEnquiry:
+		case AVC::ESpecificEnquiry:
+			{
+			err = KErrNotSupported;
+			break;
+			}
+		default:
+			if (iFrame->Opcode() == AVC::EVendorDependent)
+				{
+				err = ParseIncomingVendorCommandL(aObserver, aFragmenter);
+				}
+			
+			else
+				{
+				// give off to the regular processor
+				err = ParseIncomingKnownOpcodeL(aObserver);
+				}
+			break;
+		};
+
+
+	return err;
+	}
+	
+/** Processes an incoming response.
+
+This function may not fail.  We always need to generate something
+to RemCon.
+
+@param aObserver Observer to use for retrieving converter.
+@param aFrame The AV/C frame containing the response.
+*/
+TInt CControlCommand::ParseIncomingResponse(MRemConBearerObserver& aObserver, const CAVCFrame& aFrame)
+	{
+	LOG_FUNC	
+	TInt error = KErrNone;
+	
+	// Compare Opcode with that of the sent frame rather than the
+	// received one because we trust that more.  Should be the same
+	// as this is matched by AVCTP transaction label, but who knows
+	// what those illicit remote devices could be up to.
+	if(iFrame->Opcode() == AVC::EPassThrough)
+		{
+		switch(aFrame.Type())
+			{		
+			case AVC::EAccepted:
+				{
+				InsertCoreResult(KErrNone);
+				break;
+				}
+			case AVC::ENotImplemented:
+				{
+				InsertCoreResult(KErrNotSupported);
+				break;
+				}
+			default:
+				{
+				InsertCoreResult(KErrGeneral);
+				break;
+				}
+			}
+		}	
+	else if (iFrame->Opcode() == AVC::EVendorDependent)
+		{
+		TPtrC8 payloadData;
+		AVC::TAVCVendorId vID;
+		//Get the PDU ID with that of the sent frame rather than the received one,
+		//the reason is the same to above comments.
+		payloadData.Set(CAVCVendorDependentCommand::GetPayloadAndVID(*iFrame, vID));
+		if (vID == KBluetoothSIGVendorId)
+			{
+			TMetadataTransferPDUID metadataPDUID = MetadataTransferParser::GetPDUID(payloadData);
+			switch ( metadataPDUID )
+			    {
+			    case ESetAbsoluteVolume://Response for setting absolute volume.
+			    	{
+			    	error = SetSetAbsoluteVolumeResult(aFrame);
+			    	break;
+			    	}
+			    case ERegisterNotification:
+			    	{
+			    	//Get notify event ID with the sent frame rather than the received one
+			    	//because there is a big possibility that the received one is an error response, e.g. rejected,notimplemented.
+			    	//In order to make sure this is an absolute volume response even if the response is an error response, 
+			    	//we have to use the sent frame, and then we can process absolute volume specifically.
+			    	TMetadataTransferNotifyEventID eventID = MetadataTransferParser::GetNotifyEventID(payloadData);
+			    	
+			    	__ASSERT_ALWAYS(eventID == ERegisterNotificationVolumeChanged,
+			    			AvrcpUtils::Panic(EAvrcpInvalidEventId));
+			    	
+			    	if (eventID == ERegisterNotificationVolumeChanged)
+			    		{
+			    		error = SetNotifyVolumeChangeResult(aFrame);
+			    		}
+			    	break;
+			    	}
+			    default:
+			    	{
+			    	// Should never hit here
+			    	AvrcpUtils::Panic(EAvrcpResponseToUnknownCommand);
+			        break;
+			    	}
+			    }
+			}
+		else
+			{
+			ParseIncomingUnknownResponse(aObserver, aFrame);
+			}
+		}
+	else
+		{
+		ParseIncomingUnknownResponse(aObserver, aFrame);
+		}
+	
+	return error;
+	}
+
+/** Processes an outgoing response.
+
+This should only be called for vendor dependent commands as
+we respond to passthrough commands internally.
+
+@param aObserver Observer to use for retrieving converter.
+@param aFrame The command data for the response.
+*/
+TInt CControlCommand::ProcessOutgoingResponse(MRemConBearerObserver& aObserver,
+//											TRemConMessageType aMessageType,
+											RBuf8& aResponseData,
+											CAVRCPFragmenter& aFragmenter)
+	{
+	TRAPD(err, DoProcessOutgoingResponseL(aObserver,aResponseData, aFragmenter));
+	return err;
+	}
+
+void CControlCommand::DoProcessOutgoingResponseL(MRemConBearerObserver& aObserver,
+											 RBuf8& aResponseData,
+											 CAVRCPFragmenter& aFragmenter)
+	{
+	LOG_FUNC
+	
+	// Payload size may be increased in GenerateMetadataResponsePayload
+	// if there's a very large response which needs fragmenting
+	RBuf8 payload;
+	payload.CreateL(KAVCFrameMaxLength);
+	CleanupClosePushL(payload);
+
+	if(( iInterfaceUid.iUid == KRemConMediaInformationApiUid ) 
+		|| ( iInterfaceUid.iUid == KRemConPlayerInformationUid )
+		|| ( iInterfaceUid.iUid == KRemConAbsoluteVolumeTargetApiUid )
+		|| ( iInterfaceUid.iUid == KRemConNowPlayingApiUid )
+		|| ( iInterfaceUid.iUid == KUidAvrcpInternalInterface))
+		{
+		// metadata
+		// "this" is the command for which the response lurks in aCommandData
+		// GenerateMetadataResponsePayload() MUST set PDU id, fragmentation stauts
+		// and paramlen (4 bytes total) - check this in ASSERT_DEBUG
+		User::LeaveIfError(GenerateMetadataResponsePayload(aObserver, payload, aResponseData));
+		__ASSERT_DEBUG(payload.Length() >= KAVRCPMinVendorDependentResponseLen, AvrcpUtils::Panic(EAvrcpFunnyLengthData));
+		aResponseData.Close();
+		
+		if (payload.Length() > KAVCMaxVendorDependentPayload)
+			{
+			// Fragment response (in payload) and queue fragments ready
+			// for sending when CT sends a CONTINUE request. If any other
+			// request is received (other than pass-through) then throw
+			// away our fragmented packet, as the CT has aborted.
+			aFragmenter.AssignPayload(payload);
+			payload.Assign(NULL);
+			payload.Close();
+			
+			// Re-allocate this back to a sensible size
+			// from the much larger size, which has now been
+			// assigned to fragmenter (avoids copying payload)
+			payload.CreateL(KAVCFrameMaxLength);
+			payload.Append(aFragmenter.GetNextFragmentHeader());
+			payload.Append(aFragmenter.GetNextFragment());
+			}
+			
+		CAVCFrame* frame = CAVCVendorDependentResponse::NewL(KBluetoothSIGVendorId);
+		frame->Append(payload);
+		frame->SetType(iFrame->Type());
+		delete iFrame;
+		iFrame = frame;
+		}
+	else
+		{
+		User::LeaveIfError(aObserver.InterfaceToBearer(TUid::Uid(KRemConBearerAvrcpImplementationUid),
+							iInterfaceUid, iOperationId,
+							aResponseData, /*ERemConCommand*/ERemConResponse, payload));
+		aResponseData.Close();
+		CAVCFrame* frame = CAVCFrame::NewL(payload, AVC::EResponse);
+		delete iFrame;
+		iFrame = frame;
+		}
+		
+	CleanupStack::PopAndDestroy(&payload);
+	}
+
+/** Set the response type in the AV/C frame.
+
+@param aErr The result of processing the operation. KErrNone if 
+			successful. KErrNotsupported if this operation is not
+			implemented, eg because no converter was found.
+*/
+void CControlCommand::SetResponseType(TInt aErr)
+	{
+	LOG_FUNC
+	AVC::TCType cType = iFrame->Type();
+	switch(aErr)
+		{
+		case KErrNone:
+		case KErrCompletion:
+			if (cType == AVC::EControl)
+				{
+				iFrame->SetType(AVC::EAccepted);
+				}
+			else if (cType == AVC::ENotify)
+				{
+				iFrame->SetType(AVC::EInterim);
+				}
+			else if (cType == AVC::EInterim)
+				{
+				iFrame->SetType(AVC::EChanged);
+				}
+			else if (cType == AVC::EStatus)
+				{
+				iFrame->SetType(AVC::EStable);
+				}
+			else 
+				{
+				iFrame->SetType(AVC::EImplemented);
+				}
+			break;
+		case KErrAvrcpMetadataInvalidCommand:
+		case KErrAvrcpMetadataInvalidParameter:
+		case KErrAvrcpMetadataParameterNotFound:
+		case KErrAvrcpMetadataInternalError:
+		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:
+			{
+			// If this fails, we're OOM (it only contains a NewL)
+			// so we can't send the error response - just give up
+			TRAPD(err, GenerateMetadataRejectPayloadL(aErr));
+			err = err;  // avoid warning about not using this
+			break;
+			}
+		default:
+			iFrame->SetType(AVC::ENotImplemented);
+		}
+	iFrame->SetFrameType(AVC::EResponse);	
+	}
+
+/** Gets this command's AV/C frame.
+@return the AV/C frame for this command
+*/	
+const CAVCFrame& CControlCommand::Frame() const
+	{
+	LOG_FUNC
+	return *iFrame;
+	}
+
+const TDesC8& CControlCommand::Data() const
+	{
+	LOG_FUNC
+	return iFrame->Data();
+	}
+
+SymbianAvctp::TMessageType CControlCommand::MessageType() const
+	{
+	LOG_FUNC
+	return (iFrame->FrameType() == AVC::ECommand) ? SymbianAvctp::ECommand : SymbianAvctp::EResponse;
+	}
+
+/** Gets the button action from this command's AV/C frame.
+This is only valid on passthrough commands.
+
+@return The button action.
+*/
+AVCPanel::TButtonAction CControlCommand::ButtonAct() const
+	{
+	LOG_FUNC
+	AVCPanel::TButtonAction act;
+	iFrame->ButtonAct(act);
+	return act;
+	}
+
+/** Gets whether this command is currently assumed to be a click.
+
+This is used to support the click facility offered by RemCon, which
+is not offered by AVRCP.  As such AVRCP internally simulates outgoing
+clicks by generating a press and release for one RemCon click.  When
+responses are received we know that if a command is a click we should
+send only one response up to RemCon.
+
+Incoming passthrough press commands are assumed to be click until
+the hold timer expires.  When a matching release is received we can
+then tell whether we need to send a single click up to RemCon, or 
+a release to match the press that was sent when the hold timer expired.
+
+@return ETrue is this is a click. EFalse if not.
+*/
+TBool CControlCommand::Click() const
+	{
+	LOG_FUNC
+	return iIsClick;
+	}
+
+/** Sets whether this command is currently assumed to be a click
+or not.
+
+@see CRcpcommand::Click()
+@param aIsClick ETrue to set this as click. EFalse to set this as 
+				not click.
+*/	
+void CControlCommand::SetClick(TBool aIsClick)
+	{
+	LOG_FUNC
+	iIsClick = aIsClick;
+	}
+
+/** Sets the RemCon data to indicate what button action this 
+command is.  This function is only valid for commands in the
+core api.
+
+@param aButtonAct The RemCon button action for this command.
+@param aCommand Whether this is a command. This is needed
+				because the command data is at a different offset for
+				commands and responses.
+*/
+void CControlCommand::SetCoreButtonAction(TRemConCoreApiButtonAction aButtonAct, TBool aCommand)
+	{
+	LOG_FUNC
+	
+	TInt offset = aCommand ? KRemConCoreApiButtonDataOffset + KRemConCoreApiCommandDataOffset
+						   : KRemConCoreApiButtonDataOffset + KRemConCoreApiResponseDataOffset;
+						   
+	AvrcpUtils::SetCommandDataFromInt(iCommandData, offset, 
+						  KRemConCoreApiButtonDataLength, aButtonAct);
+	}
+/** ReSets the RemCon data to indicate what button action this 
+command is. This function is called when we the command is being re-used to generate a 
+new command to remconServ.
+
+@param aButtonAct The RemCon button action for this command.
+@param aCommand Whether this is a command. This is needed
+				because the command data is at a different offset for
+				commands and responses.
+*/
+void CControlCommand::ReSetCoreButtonActionL(TRemConCoreApiButtonAction aButtonAct, TBool aCommand)
+	{
+	LOG_FUNC
+	
+	if (iCommandData.MaxLength() < KRemConCoreApiButtonDataLength)
+		{
+		iCommandData.Close();
+		iCommandData.CreateMaxL(KRemConCoreApiButtonDataLength);
+		}
+	
+	SetCoreButtonAction(aButtonAct, aCommand);
+	}
+
+/** Inserts the results at the beginning of this command's data.
+If the data buffer is not large enough it will be ReAlloced to 
+allow the insertion.
+
+@return The result to pass to RemCon. KErrNone for an AV/C accepted.
+		KErrNotSupported for an AV/C not implemented. KErrGeneral
+		for an AV/C rejected. 
+*/
+TInt CControlCommand::InsertCoreResult(TInt aResult)
+	{
+	LOG_FUNC
+	TInt err = KErrNone;
+	TInt requiredLength = KRemConCoreApiResultDataLength + iCommandData.Length();
+	
+	if(iCommandData.Length() >= requiredLength)
+		{
+		// Insert data to write result into
+		iCommandData.Insert(0, KRemConCoreApiResultPad);
+		}
+	else
+		{
+		// need longer buffer
+		err = iCommandData.ReAlloc(requiredLength);
+		if(!err)
+			{
+			iCommandData.Insert(0, KRemConCoreApiResultPad);
+			}
+		else
+			{
+			return err;
+			}
+		}
+
+	AvrcpUtils::SetCommandDataFromInt(iCommandData, 0, 
+						  KRemConCoreApiResultDataLength, aResult);
+	return err;
+	}
+
+/**
+Sets the result of set absolute volume response into this command's data
+*/
+TInt CControlCommand::SetSetAbsoluteVolumeResult(const CAVCFrame& aFrame)
+	{
+	TInt err = KErrNone;
+    TRAP(err, DoSetAbsoluteVolumeResultL(aFrame));
+    if (err != KErrNone)
+    	{
+    	// Ensure the client can receive an error in case of 
+    	// DoSetAbsoluteVolumeResultL leaves out.
+    	iCommandData.Zero();
+    	TPckgBuf<TInt> errBuf(err);
+    	iCommandData.Append(errBuf);
+    	iCommandData.SetLength(iCommandData.MaxLength());
+    	}
+    return err;
+	}
+
+void CControlCommand::DoSetAbsoluteVolumeResultL(const CAVCFrame& aFrame)
+	{
+	RRemConAbsoluteVolumeResponse absVol;	
+	absVol.iError = KErrGeneral;
+	absVol.iMaxVolume = KAvrcpMaxAbsoluteVolume;
+	
+	CleanupClosePushL(absVol);	
+	
+	switch(aFrame.Type())
+        {
+        case AVC::EAccepted:
+	        {
+	        if (aFrame.Data().Length() == KLengthSetAbsoluteVolumeResponse)
+		        {
+		        absVol.iError = KErrNone;
+		        TUint volumeOffset = KLengthSetAbsoluteVolumeResponse - 1;
+		        absVol.iVolume = KAbsoluteVolumeMask & aFrame.Data()[volumeOffset];
+		        }
+		    break;
+		    }
+        case AVC::ERejected: // fall through
+        case AVC::ENotImplemented:
+        	break;
+	    default:
+	    	break;
+        }
+	
+	absVol.WriteL(iCommandData);
+	CleanupStack::PopAndDestroy(&absVol);
+	}
+/**
+Sets the result of volume changed notification response into this command's 
+data.
+*/
+TInt CControlCommand::SetNotifyVolumeChangeResult(const CAVCFrame& aFrame)
+	{
+	TInt err = KErrNone;
+	TRAP(err, DoSetNotifyVolumeChangeResultL(aFrame));
+    if (err == KErrNone)
+    	{
+    	// Through AVC::TCType the RemCon sever can know whether the response
+    	// is an Interim or Changed or any other responses, so the RemCon 
+    	// server can decide to remove the notify command from its 
+    	// outgoingsent queue or not.
+    	iFrame->SetType(aFrame.Type());
+    	}
+    else
+    	{
+    	// Ensure the client can receive an error in case of 
+    	// DoSetNotifyVolumeChangeResultL leaves out.
+    	iCommandData.Zero();
+    	TPckgBuf<TInt> errBuf(KErrGeneral);
+    	iCommandData.Append(errBuf);
+    	iCommandData.SetLength(iCommandData.MaxLength());
+    	
+    	// Setting AVC::TCType to ERejected is intended to let the RemCon
+    	// server to remove the notify command from its outgoingsent queue
+    	// in case of DoSetNotifyVolumeChangeResultL leaves out.
+    	iFrame->SetType(AVC::ERejected);
+    	}
+    
+    return err;
+	}
+
+void CControlCommand::DoSetNotifyVolumeChangeResultL(const CAVCFrame& aFrame)
+	{
+	if (iCommandData.MaxLength() < KAbsoluteVolumeResponseDataSize)
+		{
+		iCommandData.Close();
+		iCommandData.CreateL(KAbsoluteVolumeResponseDataSize);
+		}
+	
+	RRemConAbsoluteVolumeResponse absVol;
+	absVol.iError = KErrGeneral;
+	absVol.iMaxVolume = KAvrcpMaxAbsoluteVolume;
+	
+	CleanupClosePushL(absVol);	
+	
+	switch(aFrame.Type())
+        {
+	    case AVC::EInterim:
+	    case AVC::EChanged:
+		    {
+		    if (aFrame.Data().Length() == KLengthNotifyVolumeChangeResponse)
+		    	{
+		    	absVol.iError = KErrNone;
+		    	TUint volumeOffset = KLengthNotifyVolumeChangeResponse - 1;
+		    	absVol.iVolume = KAbsoluteVolumeMask & aFrame.Data()[volumeOffset];			    	
+		    	}		    
+		    break;
+		    }
+	    case AVC::ERejected: // fall through
+	    case AVC::ENotImplemented:
+	    	break;
+	    default:
+	    	break;
+        }
+	absVol.WriteL(iCommandData);
+	CleanupStack::PopAndDestroy(&absVol);
+	}
+//------------------------------------------------------------------------------------
+// Internal utility functions
+//------------------------------------------------------------------------------------
+
+/** Fills in command info from an AVC Control.
+
+This functions sets iInterfaceUid, iOperationId and iCommandData
+to the correct values according to iFrame.  The format of iCommandData
+is defined by RemCon and is dependent on iInterfaceUid and iOperationId.
+
+@return KErrNone				If the frame has been parsed successfully.
+@return KErrNotSupported		This frame represents a command for which a
+								RemCon converter or client side interface
+								cannot be found.
+@return	System wide error code.
+*/
+TInt CControlCommand::ParseIncomingKnownOpcodeL(MRemConBearerObserver& aObserver)
+	{
+	LOG_FUNC
+	TInt err = KErrNotSupported;
+	
+	AVC::TCType cType = iFrame->Type();
+	
+	switch(iFrame->Opcode())
+		{
+		case AVC::EPassThrough:
+			{
+			if(iFrame->Data().Length() < KAVCPassthroughFrameLength)
+				{
+				LEAVEL(KErrCorrupt);
+				}
+			if (iFrame->SubunitType() != AVC::EPanel)
+				{
+				LEAVEL(KErrNotSupported);
+				}
+	
+			TUint8 avrcpOp;			
+			if (cType != AVC::EGeneralEnquiry && cType == AVC::EControl)
+				{
+				iCommandData.CreateMaxL(KRemConCoreApiButtonDataLength);
+				err = iFrame->OperationId(avrcpOp);
+				if (err == KErrNone)
+					{
+					if (avrcpOp!=AVCPanel::EVendorUnique)
+						{
+						err = AvrcpToRemConOperation(avrcpOp, iOperationId, iInterfaceUid);
+						}
+					else
+						{
+						err = ParseVendorUniquePassthroughCommand(aObserver);
+						}
+					}
+				
+				if (err!=KErrNone)
+					{
+					err = KErrAvrcpInvalidOperationId;
+					}
+				}
+			else
+				{
+				iCommandData.Close();
+				iCommandData.CreateL(KAVCFrameMaxLength);
+				TRemConMessageType message = ERemConCommand;
+				err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid),
+													iFrame->Data(),
+													iFrame->Data(),
+													iInterfaceUid,
+													iOperationId,
+													message,
+													iCommandData);
+				}
+			break;
+			}
+		case AVC::EUnitInfo:
+			{
+			if (iFrame->Type() == AVC::EStatus)
+				{
+				CAVCFrame* resp = AvrcpCommandFramer::UnitInfoResponseL();
+				delete iFrame;
+				iFrame = resp;
+				err = KErrCompletion; // since bearer has done its job without client needed
+				}
+			else
+				{
+				err = KErrAvrcpInvalidCType;
+				}
+			break;
+			}
+		case AVC::ESubunitInfo:
+			{
+			if (iFrame->Type() == AVC::EStatus)
+				{
+				CAVCFrame* resp = AvrcpCommandFramer::SubunitInfoResponseL();
+				delete iFrame;
+				iFrame = resp;
+				err = KErrCompletion; // since bearer has done its job without client needed
+				}
+			else
+				{
+				err = KErrAvrcpInvalidCType;
+				}
+			break;
+			}
+
+		default:
+			{
+			iCommandData.Close();
+			iCommandData.CreateL(KAVCFrameMaxLength);
+			TRemConMessageType message = ERemConCommand;
+			err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid),
+												iFrame->Data(),
+												iFrame->Data(),
+												iInterfaceUid,
+												iOperationId,
+												message,
+												iCommandData);
+			break;
+			}
+		}
+		
+	return err;
+	}
+	
+
+/** Fills in command info from an AVC Vendor Dependent message.
+
+This functions sets iInterfaceUid, iOperationId and iCommandData
+to the correct values according to iFrame.  The format of iCommandData
+is defined by RemCon and is dependent on iInterfaceUid and iOperationId.
+The AVC frame's length is checked that it at least contains the vendor id.
+
+@param aObserver An observer to be used to obtain a converter.
+@return KErrNone				If the frame has been parsed successfully.
+@return KErrNotSupported		This frame represents a command for which a
+								RemCon converter or client side interface
+								cannot be found.
+@return KErrAvrcpInvalidCType	The CType specified in this frame is invalid.
+@return KErrAvrcpMetadataInvalidCommand		The AVRCP command is invalid.
+@return KErrAvrcpMetadataInvalidParameter	The AVRCP parameter is invalid.
+@return KErrAvrcpMetadataParameterNotFound	The AVRCP parameter was not found.
+@return KErrAvrcpMetadataInternalError		An AVRCP internal error occurred (such as out-of-memory,
+											or an inter-process communication error)
+@return	System wide error code.
+*/	
+TInt CControlCommand::ParseIncomingVendorCommandL(MRemConBearerObserver& aObserver, CAVRCPFragmenter& aFragmenter)
+	{
+	LOG_FUNC
+	TInt err = KErrNone;
+
+	SetVendorInfoL(EFalse); // set id and payload; leaves if not enough space available
+	
+	if (iVendorId!=KBluetoothSIGVendorId)
+		{
+		iCommandData.Close();
+		iCommandData.CreateL(KAVCFrameMaxLength);
+	
+		TRemConMessageType message = ERemConCommand;
+		
+		err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid),
+											iFrame->Data(),
+											iFrame->Data(),
+											iInterfaceUid,
+											iOperationId,
+											message,
+											iCommandData);
+		}
+	else
+		{
+		// process v>1.0 version of AVRCP
+		// which use vendor dependent frames to extend v1.0 of AVRCP
+		// the vendor code has the value for the BT SIG
+		if (iFrame->SubunitType() != AVC::EPanel)
+			{
+			// this is for Control not Metadata
+			return KErrNotSupported;
+			}
+		
+		err = ParseMetadataTransferVendorCommand(aFragmenter);
+		if (err == KErrNone)
+			{
+			// Check that the interface UID is non-zero
+			__ASSERT_DEBUG(iInterfaceUid != TUid::Uid(0), AvrcpUtils::Panic(EAvrcpInterfaceUidNotSet));
+			}
+		}
+	return err;
+	}
+
+
+/** Creates RemCon command information from iFrame.
+
+This functions sets iInterfaceUid, iOperationId and iCommandData
+to the correct values according to iFrame.  The format of iCommandData
+is defined by the interface, iInterfaceUid and is dependent on 
+iOperationId.  A converter should be able to be found as this response
+is a result of an outgoing command on this interface.
+
+@param aObserver An observer used to get a converter.
+@param aFrame The AV/C frame for this command.
+*/
+void CControlCommand::ParseIncomingUnknownResponse(MRemConBearerObserver& aObserver, 
+	const CAVCFrame& aFrame)
+	{
+	LOG_FUNC
+	// We need to pass a response up to RemCon even if we can't get a
+	// converter to generate a decent response so we don't 
+
+	iCommandData.Close();
+	TInt err = iCommandData.Create(KAVCFrameMaxLength);
+	if(!err)
+		{
+		TRemConMessageType type = ERemConResponse; // output param
+		err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid),
+			aFrame.Data(), aFrame.Data(), iInterfaceUid, iOperationId, type, iCommandData);
+		}
+	}
+
+/** Translates from an AVC operation id to RemCon's core interface.
+
+@param aAvrcpOp		The AVC passthrough operation id.
+@param aRemConOp	On return the RemCon operation id within the core interface.
+@return KErrNone	If the operation has been translated successfully.
+@return KErrNotSupported	If the operation does not correspond to one
+							in the RemCon core interface.
+*/
+TInt CControlCommand::AvrcpToRemConOperation(TUint aAvrcpOp, TUint& aRemConOp, TUid& aRemConIf)
+	{
+	LOG_STATIC_FUNC
+	TInt err = KErrNone;
+
+	//TBH setting here as most are for the Core API
+	//some cases will override
+	aRemConIf = TUid::Uid(KRemConCoreApiUid);
+
+	switch(aAvrcpOp)	
+		{
+		case AVCPanel::ESelect:
+			aRemConOp = ERemConCoreApiSelect;
+			break;
+		case AVCPanel::EUp:
+			aRemConOp = ERemConCoreApiUp;
+			break;
+		case AVCPanel::EDown:
+			aRemConOp = ERemConCoreApiDown;
+			break;
+		case AVCPanel::ELeft:
+			aRemConOp = ERemConCoreApiLeft;
+			break;
+		case AVCPanel::ERight:
+			aRemConOp = ERemConCoreApiRight;
+			break;
+		case AVCPanel::ERightUp:
+			aRemConOp = ERemConCoreApiRightUp;
+			break;
+		case AVCPanel::ERightDown:
+			aRemConOp = ERemConCoreApiRightDown;
+			break;
+		case AVCPanel::ELeftUp:
+			aRemConOp = ERemConCoreApiLeftUp;
+			break;
+		case AVCPanel::ELeftDown:
+			aRemConOp = ERemConCoreApiLeftDown;
+			break;
+		case AVCPanel::ERootMenu:
+			aRemConOp = ERemConCoreApiRootMenu;
+			break;
+		case AVCPanel::ESetupMenu:
+			aRemConOp = ERemConCoreApiSetupMenu;
+			break;
+		case AVCPanel::EContentsMenu:
+			aRemConOp = ERemConCoreApiContentsMenu;
+			break;
+		case AVCPanel::EFavoriteMenu:
+			aRemConOp = ERemConCoreApiFavoriteMenu;
+			break;
+		case AVCPanel::EExit:
+			aRemConOp = ERemConCoreApiExit;
+			break;
+		case AVCPanel::E0:
+			aRemConOp = ERemConCoreApi0;
+			break;
+		case AVCPanel::E1:
+			aRemConOp = ERemConCoreApi1;
+			break;
+		case AVCPanel::E2:
+			aRemConOp = ERemConCoreApi2;
+			break;
+		case AVCPanel::E3:
+			aRemConOp = ERemConCoreApi3;
+			break;
+		case AVCPanel::E4:
+			aRemConOp = ERemConCoreApi4;
+			break;
+		case AVCPanel::E5:
+			aRemConOp = ERemConCoreApi5;
+			break;
+		case AVCPanel::E6:
+			aRemConOp = ERemConCoreApi6;
+			break;
+		case AVCPanel::E7:
+			aRemConOp = ERemConCoreApi7;
+			break;
+		case AVCPanel::E8:
+			aRemConOp = ERemConCoreApi8;
+			break;
+		case AVCPanel::E9:
+			aRemConOp = ERemConCoreApi9;
+			break;
+		case AVCPanel::EDot:
+			aRemConOp = ERemConCoreApiDot;
+			break;
+		case AVCPanel::EEnter:
+			aRemConOp = ERemConCoreApiEnter;
+			break;
+		case AVCPanel::EClear:
+			aRemConOp = ERemConCoreApiClear;
+			break;
+		case AVCPanel::EChannelUp:
+			aRemConOp = ERemConCoreApiChannelUp;
+			break;
+		case AVCPanel::EChannelDown:
+			aRemConOp = ERemConCoreApiChannelDown;
+			break;
+		case AVCPanel::EPreviousChannel:
+			aRemConOp = ERemConCoreApiPreviousChannel;
+			break;
+		case AVCPanel::ESoundSelect:
+			aRemConOp = ERemConCoreApiSoundSelect;
+			break;
+		case AVCPanel::EInputSelect:
+			aRemConOp = ERemConCoreApiInputSelect;
+			break;
+		case AVCPanel::EDisplayInformation:
+			aRemConOp = ERemConCoreApiDisplayInformation;
+			break;
+		case AVCPanel::EHelp:
+			aRemConOp = ERemConCoreApiHelp;
+			break;
+		case AVCPanel::EPageUp:
+			aRemConOp = ERemConCoreApiPageUp;
+			break;
+		case AVCPanel::EPageDown:
+			aRemConOp = ERemConCoreApiPageDown;
+			break;
+		case AVCPanel::EPower:
+			aRemConOp = ERemConCoreApiPower;
+			break;
+		case AVCPanel::EVolumeUp:
+			aRemConOp = ERemConCoreApiVolumeUp;
+			break;
+		case AVCPanel::EVolumeDown:
+			aRemConOp = ERemConCoreApiVolumeDown;
+			break;
+		case AVCPanel::EMute:
+			aRemConOp = ERemConCoreApiMute;
+			break;
+		case AVCPanel::EPlay:
+			aRemConOp = ERemConCoreApiPlay;
+			break;
+		case AVCPanel::EStop:
+			aRemConOp = ERemConCoreApiStop;
+			break;
+		case AVCPanel::EPause:
+			aRemConOp = ERemConCoreApiPause;
+			break;
+		case AVCPanel::ERecord:
+			aRemConOp = ERemConCoreApiRecord;
+			break;
+		case AVCPanel::ERewind:
+			aRemConOp = ERemConCoreApiRewind;
+			break;
+		case AVCPanel::EFastForward:
+			aRemConOp = ERemConCoreApiFastForward;
+			break;
+		case AVCPanel::EEject:
+			aRemConOp = ERemConCoreApiEject;
+			break;
+		case AVCPanel::EForward:
+			aRemConOp = ERemConCoreApiForward;
+			break;
+		case AVCPanel::EBackward:
+			aRemConOp = ERemConCoreApiBackward;
+			break;
+		case AVCPanel::EAngle:
+			aRemConOp = ERemConCoreApiAngle;
+			break;
+		case AVCPanel::ESubpicture:
+			aRemConOp = ERemConCoreApiSubpicture;
+			break;
+		case AVCPanel::EF1:
+			aRemConOp = ERemConCoreApiF1;
+			break;
+		case AVCPanel::EF2:
+			aRemConOp = ERemConCoreApiF2;
+			break;
+		case AVCPanel::EF3:
+			aRemConOp = ERemConCoreApiF3;
+			break;
+		case AVCPanel::EF4:
+			aRemConOp = ERemConCoreApiF4;
+			break;
+		case AVCPanel::EF5:
+			aRemConOp = ERemConCoreApiF5;
+			break;
+		case AVCPanel::EVendorUnique:
+		default:
+			err = KErrNotSupported;
+		}
+		
+	return err;
+	}
+	
+
+TInt CControlCommand::ParseVendorUniquePassthroughCommand(MRemConBearerObserver& aObserver)
+	{
+	TInt err = KErrNone;
+	TRAP(err, SetVendorInfoL(ETrue)); // set id and payload; leaves if not enough space available
+	
+	if (err == KErrNone && iVendorId == KBluetoothSIGVendorId)
+		{
+		// it's one of the v1.3 (or later!) MT commands
+		err = ParseMetadataTransferPassthroughCommand();
+		}
+	else
+		{
+		iCommandData.Close();
+		TRAP(err, iCommandData.CreateL(KAVCFrameMaxLength));
+		if(err == KErrNone)
+			{
+			TRemConMessageType message = ERemConCommand;
+			err = aObserver.BearerToInterface(TUid::Uid(KRemConBearerAvrcpImplementationUid),
+											  iFrame->Data(),
+											  iFrame->Data(),
+											  iInterfaceUid,
+											  iOperationId,
+											  message,
+											  iCommandData);
+			}
+		}
+
+	return err;
+	}
+	
+/** Translates from RemCon's core interface to an AVC operation id.
+
+@param aRemConOp	The RemCon operation id within the core interface.
+@param aAvrcpOp		On return the AVC passthrough operation id.
+@return KErrNone	If the operation has been translated successfully.
+@return KErrNotSupported	If the operation does not correspond to one
+							provided by AVRCP.
+*/
+TInt CControlCommand::RemConToAvrcpOperation(TUint aRemConOp, AVCPanel::TOperationId& aAvrcpOp)
+	{
+	LOG_STATIC_FUNC
+	TInt err = KErrNone;
+	switch(aRemConOp)	
+		{
+		case ERemConCoreApiSelect:
+			aAvrcpOp = AVCPanel::ESelect;
+			break;
+		case ERemConCoreApiUp:
+			aAvrcpOp = AVCPanel::EUp;
+			break;
+		case ERemConCoreApiDown:
+			aAvrcpOp = AVCPanel::EDown;
+			break;
+		case ERemConCoreApiLeft:
+			aAvrcpOp = AVCPanel::ELeft;
+			break;
+		case ERemConCoreApiRight:
+			aAvrcpOp = AVCPanel::ERight;
+			break;
+		case ERemConCoreApiRightUp:
+			aAvrcpOp = AVCPanel::ERightUp;
+			break;
+		case ERemConCoreApiRightDown:
+			aAvrcpOp = AVCPanel::ERightDown;
+			break;
+		case ERemConCoreApiLeftUp:
+			aAvrcpOp = AVCPanel::ELeftUp;
+			break;
+		case ERemConCoreApiLeftDown:
+			aAvrcpOp = AVCPanel::ELeftDown;
+			break;
+		case ERemConCoreApiRootMenu:
+			aAvrcpOp = AVCPanel::ERootMenu;
+			break;
+		case ERemConCoreApiSetupMenu:
+			aAvrcpOp = AVCPanel::ESetupMenu;
+			break;
+		case ERemConCoreApiContentsMenu:
+			aAvrcpOp = AVCPanel::EContentsMenu;
+			break;
+		case ERemConCoreApiFavoriteMenu:
+			aAvrcpOp = AVCPanel::EFavoriteMenu;
+			break;
+		case ERemConCoreApiExit:
+			aAvrcpOp = AVCPanel::EExit;
+			break;
+		case ERemConCoreApi0:
+			aAvrcpOp = AVCPanel::E0;
+			break;
+		case ERemConCoreApi1:
+			aAvrcpOp = AVCPanel::E1;
+			break;
+		case ERemConCoreApi2:
+			aAvrcpOp = AVCPanel::E2;
+			break;
+		case ERemConCoreApi3:
+			aAvrcpOp = AVCPanel::E3;
+			break;
+		case ERemConCoreApi4:
+			aAvrcpOp = AVCPanel::E4;
+			break;
+		case ERemConCoreApi5:
+			aAvrcpOp = AVCPanel::E5;
+			break;
+		case ERemConCoreApi6:
+			aAvrcpOp = AVCPanel::E6;
+			break;
+		case ERemConCoreApi7:
+			aAvrcpOp = AVCPanel::E7;
+			break;
+		case ERemConCoreApi8:
+			aAvrcpOp = AVCPanel::E8;
+			break;
+		case ERemConCoreApi9:
+			aAvrcpOp = AVCPanel::E9;
+			break;
+		case ERemConCoreApiDot:
+			aAvrcpOp = AVCPanel::EDot;
+			break;
+		case ERemConCoreApiEnter:
+			aAvrcpOp = AVCPanel::EEnter;
+			break;
+		case ERemConCoreApiClear:
+			aAvrcpOp = AVCPanel::EClear;
+			break;
+		case ERemConCoreApiChannelUp:
+			aAvrcpOp = AVCPanel::EChannelUp;
+			break;
+		case ERemConCoreApiChannelDown:
+			aAvrcpOp = AVCPanel::EChannelDown;
+			break;
+		case ERemConCoreApiPreviousChannel:
+			aAvrcpOp = AVCPanel::EPreviousChannel;
+			break;
+		case ERemConCoreApiSoundSelect:
+			aAvrcpOp = AVCPanel::ESoundSelect;
+			break;
+		case ERemConCoreApiInputSelect:
+			aAvrcpOp = AVCPanel::EInputSelect;
+			break;
+		case ERemConCoreApiDisplayInformation:
+			aAvrcpOp = AVCPanel::EDisplayInformation;
+			break;
+		case ERemConCoreApiHelp:
+			aAvrcpOp = AVCPanel::EHelp;
+			break;
+		case ERemConCoreApiPageUp:
+			aAvrcpOp = AVCPanel::EPageUp;
+			break;
+		case ERemConCoreApiPageDown:
+			aAvrcpOp = AVCPanel::EPageDown;
+			break;
+		case ERemConCoreApiPower:
+			aAvrcpOp = AVCPanel::EPower;
+			break;
+		case ERemConCoreApiVolumeUp:
+			aAvrcpOp = AVCPanel::EVolumeUp;
+			break;
+		case ERemConCoreApiVolumeDown:
+			aAvrcpOp = AVCPanel::EVolumeDown;
+			break;
+		case ERemConCoreApiMute:
+			aAvrcpOp = AVCPanel::EMute;
+			break;
+		case ERemConCoreApiPlay:
+			aAvrcpOp = AVCPanel::EPlay;
+			break;
+		case ERemConCoreApiStop:
+			aAvrcpOp = AVCPanel::EStop;
+			break;
+		case ERemConCoreApiPause:
+			aAvrcpOp = AVCPanel::EPause;
+			break;
+		case ERemConCoreApiRecord:
+			aAvrcpOp = AVCPanel::ERecord;
+			break;
+		case ERemConCoreApiRewind:
+			aAvrcpOp = AVCPanel::ERewind;
+			break;
+		case ERemConCoreApiFastForward:
+			aAvrcpOp = AVCPanel::EFastForward;
+			break;
+		case ERemConCoreApiEject:
+			aAvrcpOp = AVCPanel::EEject;
+			break;
+		case ERemConCoreApiForward:
+			aAvrcpOp = AVCPanel::EForward;
+			break;
+		case ERemConCoreApiBackward:
+			aAvrcpOp = AVCPanel::EBackward;
+			break;
+		case ERemConCoreApiAngle:
+			aAvrcpOp = AVCPanel::EAngle;
+			break;
+		case ERemConCoreApiSubpicture:
+			aAvrcpOp = AVCPanel::ESubpicture;
+			break;
+		case ERemConCoreApiF1:
+			aAvrcpOp = AVCPanel::EF1;
+			break;
+		case ERemConCoreApiF2:
+			aAvrcpOp = AVCPanel::EF2;
+			break;
+		case ERemConCoreApiF3:
+			aAvrcpOp = AVCPanel::EF3;
+			break;
+		case ERemConCoreApiF4:
+			aAvrcpOp = AVCPanel::EF4;
+			break;
+		case ERemConCoreApiF5:
+			aAvrcpOp = AVCPanel::EF5;
+			break;
+		default:
+			err = KErrNotSupported;
+		}
+	return err;
+	}
+
+TUint16 CControlCommand::Get16(const TPtrC8& aPtr)
+	{
+	return (aPtr[0]<<8) | aPtr[1];
+	}
+
+TInt CControlCommand::DummyCallback(TAny*)
+	{
+	// Should never be called- should be overwritten by a non-dummy callback 
+	// before it's ever requested let alone called.
+	AvrcpUtils::Panic(EAvrcpDummyCallbackCalled);
+	return KErrNone;
+	}
+
+void CControlCommand::SetVendorInfoL(TBool aIsPassthrough)
+	{
+	if (aIsPassthrough)
+		{
+		if (iFrame->DataLength() < KAVCVendorUniquePassthroughHeader)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		iVendorPayloadData.Set(CAVCVendorUniquePassthroughCommand::GetPayloadAndVID(*iFrame, iVendorId));
+		}
+	else
+		{
+		if (iFrame->DataLength() < KAVCVendorIdLength)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		iVendorPayloadData.Set(CAVCVendorDependentCommand::GetPayloadAndVID(*iFrame, iVendorId));
+		}
+	}
+
+TBool CControlCommand::IsAvrcpPassthrough() const
+	{
+	TBool isAvrcpPassthrough = EFalse;
+	
+	if(iInterfaceUid.iUid == KRemConCoreApiUid || iInterfaceUid.iUid == KRemConGroupNavigationApiUid)
+		{
+		isAvrcpPassthrough = ETrue;
+		}
+	
+	return isAvrcpPassthrough;
+	}
+
+TBool CControlCommand::IsPassthrough() const
+	{
+	return ((iFrame->Opcode() == AVC::EPassThrough) && (iFrame->SubunitType() == AVC::EPanel));
+	}
+
+TBool CControlCommand::PlayerSpecificNotify() const
+	{
+	TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId);
+	TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId);
+
+	if(pduId != ERegisterNotification)
+		{
+		return EFalse;
+		}
+	
+	if(iInterfaceUid == TUid::Uid(KRemConPlayerInformationUid))
+		{
+		if((eventId == ERegisterNotificationPlaybackStatusChanged) ||
+		  (eventId == ERegisterNotificationTrackChanged) ||
+		  (eventId == ERegisterNotificationTrackReachedEnd) ||
+		  (eventId == ERegisterNotificationTrackReachedStart) ||
+		  (eventId == ERegisterNotificationPlaybackPosChanged) ||
+		  (eventId == ERegisterNotificationPlayerApplicationSettingChanged))
+			{
+			return ETrue;
+			}
+		}
+	else if(iInterfaceUid == TUid::Uid(KRemConNowPlayingApiUid))
+		{
+		if (eventId == ERegisterNotificationNowPlayingContentChanged)
+			{
+			return ETrue;
+			}
+		}
+	else 
+		{
+		return EFalse;
+		}
+	return EFalse;
+	}
+
+TBool CControlCommand::NormalCommand()
+	{
+	TBool ret = ETrue;
+	TRegisterNotificationEvent eventId = RAvrcpIPC::GetEventIdFromIPCOperationId(iOperationId);
+	TMetadataTransferPDU pduId = RAvrcpIPC::GetPDUIdFromIPCOperationId(iOperationId);
+	
+	if((eventId == ERegisterNotificationAvailablePlayersChanged) ||
+	    (eventId == ERegisterNotificationAddressedPlayerChanged))
+		{
+		ret = EFalse;
+		}
+	return ret;
+	}
+/**
+@return Ownership of a CControlCommand representing an interim response to this command
+ */
+CControlCommand* CControlCommand::InterimResponseL()
+	{
+	CAVCFrame* frame = CAVCFrame::NewL(iFrame->Data(), AVC::EResponse);
+	CleanupStack::PushL(frame);
+	frame->SetType(AVC::EInterim);
+	
+	CControlCommand* finalResponse = CControlCommand::NewL(frame, iRemConId,
+			iTransactionLabel, iRemoteAddr, iClientId, iPlayerInfoManager);
+	CleanupStack::Pop(frame);
+	
+	finalResponse->iInterfaceUid = iInterfaceUid;
+	finalResponse->iOperationId = iOperationId;
+	
+	return finalResponse;
+	}
+