bluetoothappprofiles/avrcp/remconbeareravrcp/src/controlcommand.cpp
author hgs
Sat, 24 Apr 2010 00:12:05 +0300
changeset 25 9c3798b88e30
parent 0 f63038272f30
child 11 a42ed326b458
permissions -rw-r--r--
201011

// 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;
	}