remotecontrol/avrcp/statusconverter/remconavrcpstatusconverter.cpp
changeset 51 20ac952a623c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotecontrol/avrcp/statusconverter/remconavrcpstatusconverter.cpp	Wed Oct 13 16:20:29 2010 +0300
@@ -0,0 +1,551 @@
+// 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 <remconbeareravrcp.h>
+
+#include "remconstatusapi.h"
+#include "remconavrcpstatusconverter.h"
+
+/** Factory function.
+
+@return Ownership of a new CRemConAvrcpStatusConverter.
+*/
+CRemConAvrcpStatusConverter* CRemConAvrcpStatusConverter::NewL()
+	{
+	CRemConAvrcpStatusConverter* self = new(ELeave) CRemConAvrcpStatusConverter;
+	return self;
+	}
+
+/** Destructor.
+*/
+CRemConAvrcpStatusConverter::~CRemConAvrcpStatusConverter()
+	{
+	}
+
+/** Constructor.
+*/
+CRemConAvrcpStatusConverter::CRemConAvrcpStatusConverter()
+	{
+	}
+
+/** Called to get a converter interface.
+
+@param aUid The uid of the desired interface.
+@return An instance of the desired interface, NULL if
+		one could not be found.
+*/
+TAny* CRemConAvrcpStatusConverter::GetInterface(TUid aUid)
+	{
+	TAny* ret = NULL;
+	if ( aUid == TUid::Uid(KRemConConverterInterface1) )
+		{
+		ret = reinterpret_cast<TAny*>(
+			static_cast<MRemConConverterInterface*>(this)
+			);
+		}
+
+	return ret;
+	}
+
+/** Decides whether this converter supports this interface.
+
+This converter supports only the AVRCP bearer and Status API.
+This function checks whether the Uids provided match AVRCP and
+Status.
+
+@param aInterfaceData The Uid of the originating RemCon interface.
+@param aBearerUid The Uid of the bearer this data is destined for.
+@return Whether this data can be converted.	
+*/
+TBool CRemConAvrcpStatusConverter::SupportedUids(const TUid& aInterfaceUid, const TUid& aBearerUid) const
+	{
+	return (aInterfaceUid == TUid::Uid(KRemConStatusApiUid) &&
+	   aBearerUid == TUid::Uid(KRemConBearerAvrcpImplementationUid));
+	}
+
+/** Decides whether this converter supports this interface.
+
+This converter supports only the AVRCP bearer.  That bearer publishes
+interface data in the format of an AV/C frame.  This function 
+checks that aBearerUid is that of AVRCP, and if so examines the AV/C
+frame in aInterfaceData to see if it is a supported command.
+
+@param aInterfaceData Data in the format of the bearer identified by
+					  aBearerUid.  
+@param aBearerUid The Uid of the bearer this data originates from.
+@return Whether this data can be converted.
+*/	
+TBool CRemConAvrcpStatusConverter::SupportedInterface(const TDesC8& aInterfaceData, const TUid& aBearerUid) const
+	{
+	TInt supported = EFalse;
+	if(aBearerUid == TUid::Uid(KRemConBearerAvrcpImplementationUid))
+		{
+		AVC::TOpcode opcode = AVC::EPower; // arbitrary initialisation to avoid compiler warning
+		TRAPD(err, opcode = CAVCFrame::OpcodeL(aInterfaceData));
+		
+		if (		err == KErrNone
+			&&		( opcode == AVC::EUnitInfo || opcode == AVC::ESubunitInfo )
+			)
+			{
+			supported = ETrue;
+			}
+		}
+		
+	return supported;
+	}
+
+/** Convert data from the API's form (as we're given it by RemCon) to 
+bearer-specific form.
+
+We only deal with the AVRCP bearer.  This requires us to produce a
+CAVCFrame.
+
+The supported commands are Unit Info and Subunit Info.
+
+@param aInterfaceUid The Uid of the originating RemCon interface.
+@param aOperationId The id of the operation within the interface.
+@param aData Data in the format defined by the RemCon interface.
+@param aMsgType Whether this is a command or response.
+@param aBearerData On return, an AV/C frame representing the operation.
+*/
+TInt CRemConAvrcpStatusConverter::InterfaceToBearer(TUid aInterfaceUid, 
+		TUint aOperationId,
+		const TDesC8& /*aData*/,
+		TRemConMessageType aMsgType, 
+		TDes8& aBearerData) const
+	{
+	__ASSERT_ALWAYS(aInterfaceUid.iUid == KRemConStatusApiUid, CRemConAvrcpStatusConverter::Panic(EStatusConverterWrongInterface));
+	TInt err = KErrCorrupt;
+	
+	switch(aOperationId)
+		{
+		case ERemConStatusApiUnitInfo:
+			{
+			if(aMsgType == ERemConCommand)
+				{
+				CAVCFrame* frame = NULL;
+				TRAP(err, frame = UnitInfoL());
+				if(!err)
+					{
+					aBearerData = frame->Data();
+					err = KErrNone;
+					delete frame;
+					}
+				}
+			else if(aMsgType == ERemConResponse)
+				{
+				// These should be generated within the bearer
+				// as it knows the manufacturer id
+				err = KErrNotSupported;
+				}
+			break;
+			}
+		case ERemConStatusApiSubunitInfo:
+			{
+			if(aMsgType == ERemConCommand)
+				{
+				CAVCFrame* frame = NULL;
+				TRAP(err, frame = SubunitInfoL());
+				if(!err)
+					{
+					aBearerData = frame->Data();
+					err = KErrNone;
+					delete frame;
+					}
+				}
+			else if(aMsgType == ERemConResponse)
+				{
+				// These should be generated within the bearer
+				// as it knows the manufacturer id
+				err = KErrNotSupported;
+				}
+			break;
+			}
+		default:
+			{
+			err = KErrNotSupported;
+			break;
+			}
+		}
+
+	return err;
+	}
+
+/** Produce a Unit Info AV/C frame.
+
+@return A new AV/C frame representing unit info.
+@leave System wide error.
+*/
+CAVCFrame* CRemConAvrcpStatusConverter::UnitInfoL()
+	{
+	CAVCFrame* frame = CAVCFrame::NewL(AVC::ECommand, AVC::EStatus, AVC::EUnit, AVC::EIgnore);
+	frame->Append(TChar(AVC::EUnitInfo));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	return frame;
+	}
+
+/** Produce a Subunit Info AV/C frame.
+
+@return A new AV/C frame representing subunit info.
+@leave System wide error.
+*/	
+CAVCFrame* CRemConAvrcpStatusConverter::SubunitInfoL()
+	{
+	CAVCFrame* frame = CAVCFrame::NewL(AVC::ECommand, AVC::EStatus, AVC::EUnit, AVC::EIgnore);
+	frame->Append(TChar(AVC::ESubunitInfo));
+	frame->Append(TChar(0x7));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	frame->Append(TChar(0xff));
+	return frame;
+	}
+
+/** Convert data from the bearer format to RemCon interface format.
+
+We only deal with the Status Api. The supported commands are Unit 
+Info response and Subunit Info response.
+
+Support of these commands is mandatory in the targets.  In the case
+where a remote sends us something rubbish, we'll just provide our
+client with the default info.
+
+@param aBearerData An AV/C frame to convert.
+@param aInterfaceUid On return, the Uid of the RemCon interface.
+@param aOperationId On return, the id of the operation within the 
+					interface.
+@param aMsgType Whether this is a command or response.
+@param aData On return, Data in the format defined by the RemCon interface.
+@return Whether the command was successfully converted.
+*/
+TInt CRemConAvrcpStatusConverter::BearerToInterface(const TDesC8& aBearerData,
+		TUid& aInterfaceUid, 
+		TUint& aOperationId,
+		TRemConMessageType& aMsgType, 
+		TDes8& aData) const
+	{
+	TInt err = KErrCorrupt;
+	
+	switch(aOperationId)
+		{
+		case ERemConStatusApiUnitInfo:
+			{
+			if(aMsgType == ERemConCommand)
+				{
+				// These should be generated within the bearer
+				// as it knows the manufacturer id
+				err = KErrNotSupported;
+				}
+			else if(aMsgType == ERemConResponse)
+				{
+				// We try to parse the data, but if what the remote's sent
+				// us is invalid we'll fill in sensible values later
+				TRAP(err, SetUnitInfoResponseDataL(aBearerData, aData));
+				aInterfaceUid = TUid::Uid(KRemConStatusApiUid);
+				aOperationId = ERemConStatusApiUnitInfo;
+
+				if(err == KErrCorrupt)
+					{
+					// The data is set to the correct length in SetUnitInfoResponseDataL
+					// Stick some default data in there 
+					SetCommandDataFromInt(aData, KRemConStatusApiUnitOffset, 
+						KRemConStatusApiUnitLength, AVC::EID0);
+
+					SetCommandDataFromInt(aData, KRemConStatusApiUnitTypeOffset, 
+						KRemConStatusApiUnitTypeLength, AVC::EPanel);
+				
+					SetCommandDataFromInt(aData, KRemConStatusApiExtendedUnitTypeOffset, 
+						KRemConStatusApiExtendedUnitTypeLength, 0);		
+							
+					SetCommandDataFromInt(aData, KRemConStatusApiVendorIdOffset, 
+						KRemConStatusApiVendorIdLength, KRemConStatusApiDefaultVendorId);
+
+					err = KErrNone;
+					}
+				}
+			break;
+			}
+		case ERemConStatusApiSubunitInfo:
+			{
+			if(aMsgType == ERemConCommand)
+				{
+				// These should be generated within the bearer
+				// as it knows the manufacturer id
+				err = KErrNotSupported;
+				}
+			else if(aMsgType == ERemConResponse)
+				{
+				// We try to parse the data, but if what the remote's sent
+				// us is invalid we'll fill in sensible values later
+				TRAP(err, SetSubunitInfoResponseDataL(aBearerData, aData));
+				aInterfaceUid = TUid::Uid(KRemConStatusApiUid);
+				aOperationId = ERemConStatusApiSubunitInfo;
+
+				if(err == KErrCorrupt)
+					{
+					// Subunit response data varies in length, so the length
+					// set in SetSubunitInfoResponseDataL may be wrong.
+					aData.FillZ(KRemConStatusApiPageLength + KRemConStatusApiExtensionLength + KRemConStatusApiDefaultPageDataLength);
+				
+					// Stick some default data in there 
+					SetCommandDataFromInt(aData, KRemConStatusApiPageOffset, 
+						KRemConStatusApiPageLength, 0);	
+						
+					SetCommandDataFromInt(aData, KRemConStatusApiExtensionOffset, 
+						KRemConStatusApiExtensionLength, AVC::EIgnore);	
+
+					SetCommandDataFromInt(aData, KRemConStatusApiPageDataOffset, 
+						KRemConStatusApiDefaultPageDataLength, KRemConStatusApiDefaultPageData);	
+
+					err = KErrNone;
+					}
+				}
+			break;
+			}
+		default:
+			{
+			err = KErrNotSupported;
+			break;
+			}
+		}
+
+	return err;
+	}
+	
+/** Parses command data from the buffer.
+
+@param aCommandData The buffer from which to read the data.
+@param aVendorId On return, the vendor id
+@param aUnit On return, the unit
+@param aUnitType On return, the unit type 
+@param aExtendedUnitType On return, the extended unit type
+
+@internalComponent
+@released
+*/
+void CRemConAvrcpStatusConverter::SetUnitInfoResponseDataL(const TDesC8& aBearerData,
+	TDes8& aRemConData)
+	{
+	// AVRCP should pass us a sensible sized buffer!
+	__ASSERT_ALWAYS(aRemConData.MaxLength() >= KUnitInfoResponseLength, CRemConAvrcpStatusConverter::Panic(EAvrcpPassedTooSmallABuffer));
+
+	// Get rid of any junk
+	aRemConData.FillZ(KRemConStatusApiUnitLength + KRemConStatusApiUnitTypeLength
+					  + KRemConStatusApiExtendedUnitTypeLength
+					  + KRemConStatusApiVendorIdLength);
+
+	// Get unit id if there's enough data for it
+	if(aBearerData.Length() < KUnitIdOffset + KUnitIdLength)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	TInt unit;
+	ReadCommandDataToInt(aBearerData, KUnitIdOffset, KUnitIdLength, unit);
+	unit &= KAVCSubunitIDMask;
+	SetCommandDataFromInt(aRemConData, KRemConStatusApiUnitOffset, 
+		KRemConStatusApiUnitLength, unit);
+	
+	// Get unit type (maybe extended) if there's enough data
+	if(aBearerData.Length() < KUnitTypeOffset + KUnitTypeLength)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	TInt unitType;
+	ReadCommandDataToInt(aBearerData, KUnitTypeOffset, KUnitTypeLength, unitType);
+	unitType &= KAVCSubunitTypeMask;
+	unitType >>= KUnitTypeShift;
+	SetCommandDataFromInt(aRemConData, KRemConStatusApiUnitTypeOffset, 
+		KRemConStatusApiUnitTypeLength, unitType);
+	
+	TInt unitTypeExtend = 0;
+	TInt vendorIdOffset = KVendorIdBaseOffset;
+	if(unitType == KUnitTypeExtend)
+		{
+		// Extended unit type.  VendorId is offset by 1
+		vendorIdOffset++;
+		
+		// Read the next byte if it's there
+		if(aBearerData.Length() < KUnitTypeExtendOffset + 1)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		ReadCommandDataToInt(aBearerData, KUnitTypeExtendOffset, 1, unitTypeExtend);
+		unitTypeExtend <<= 8;
+		
+		// 	Double extended unit type. 
+		if(unitTypeExtend == KUnitTypeExtendExtend)
+			{
+			// VendorId is offset by 1
+			vendorIdOffset++;
+			
+			// Read the next byte
+			TInt unitTypeExtendExtend = 0;
+			if(aBearerData.Length() < KUnitTypeExtendExtendOffset + 1)
+				{
+				User::Leave(KErrCorrupt);
+				}
+			ReadCommandDataToInt(aBearerData, KUnitTypeExtendExtendOffset, 1, 
+								 unitTypeExtendExtend);	
+			unitTypeExtend |= unitTypeExtendExtend;
+			}
+
+		SetCommandDataFromInt(aRemConData, KRemConStatusApiExtendedUnitTypeOffset, 
+			KRemConStatusApiExtendedUnitTypeLength, unitTypeExtend);
+		}		
+
+	// Get vendor id
+	if(aBearerData.Length() < vendorIdOffset + KVendorIdLength)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	TInt vendorId;
+	ReadCommandDataToInt(aBearerData, vendorIdOffset, KVendorIdLength, vendorId);				
+	SetCommandDataFromInt(aRemConData, KRemConStatusApiVendorIdOffset, 
+		KRemConStatusApiVendorIdLength, vendorId);
+	}
+
+/** Parses command data from the buffer.
+
+@param aCommandData The buffer from which to read the data.
+@param aPage On return, the page
+@param aExtension On return, the extension
+@param aPageData On return, the page data
+
+@internalComponent
+@released
+*/
+void CRemConAvrcpStatusConverter::SetSubunitInfoResponseDataL(const TDesC8& aBearerData,
+	TDes8& aRemConData)
+	{
+	// AVRCP should pass us a sensible sized buffer!
+	__ASSERT_ALWAYS(aRemConData.MaxLength() >= KUnitInfoResponseLength, CRemConAvrcpStatusConverter::Panic(EAvrcpPassedTooSmallABuffer));
+
+	CAVCFrame* frame = CAVCFrame::NewL(aBearerData, AVC::EResponse); //Qualified
+	CleanupStack::PushL(frame);		
+	TPtrC8 ptr = frame->Data();
+	
+	// Work out how long a buffer we need for the RemCon data.
+	// This is KRemConStatusApiPageLength + KRemConStatusApiExtensionLength
+	// + the length of the page data.
+	// We can work out the length of the page data from the frame - 
+	// it's the remainder of the frame after KSubunitPageDataOffset.
+	// This gives us:
+	TInt remConDataLen = KRemConStatusApiPageLength 
+						+ KRemConStatusApiPageLength 
+						+ (ptr.Length() - KSubunitPageDataOffset);
+
+	if(aRemConData.MaxLength() < remConDataLen)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	// Get rid of any junk
+	aRemConData.FillZ(remConDataLen);
+	
+	// Get page
+	if(aBearerData.Length() < KSubunitPageOffset + KSubunitPageLength)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	TInt page;
+	ReadCommandDataToInt(aBearerData, KSubunitPageOffset, KSubunitPageLength, page);
+	page &= KSubunitPageMask;
+	SetCommandDataFromInt(aRemConData, KRemConStatusApiPageOffset, 
+		KRemConStatusApiPageLength, page);	
+		
+	// Get extension code
+	if(aBearerData.Length() < KSubunitExtensionOffset + KSubunitExtensionLength)
+		{
+		User::Leave(KErrCorrupt);
+		}
+	TInt extensionCode;
+	ReadCommandDataToInt(aBearerData, KSubunitExtensionOffset, KSubunitExtensionLength, 
+		extensionCode);
+	extensionCode &= KSubunitExtensionMask;
+	SetCommandDataFromInt(aRemConData, KRemConStatusApiExtensionOffset, 
+		KRemConStatusApiExtensionLength, extensionCode);		
+		
+	// Get page data
+	TPtrC8 pageDataPtr = aBearerData.Mid(KSubunitPageDataOffset);
+	aRemConData.Replace(KRemConStatusApiPageDataOffset, pageDataPtr.Length(), pageDataPtr);
+	
+	CleanupStack::PopAndDestroy(frame);	
+	}
+	
+/** Reads command data from the buffer to an int.
+
+@param aCommandData The buffer from which to read the data.
+@param aOffset The offset within aCommandData read from.
+@param aLength The length of data to read.  This must not be
+				more than 4.
+@param aValue On return, the value of the specified data section.
+
+@internalComponent
+@released
+*/	
+void CRemConAvrcpStatusConverter::ReadCommandDataToInt(const TDesC8& aCommandData, 
+	TInt aOffset, TInt aLength, TInt& aValue)
+	{
+	__ASSERT_DEBUG(aLength <= 4, CRemConAvrcpStatusConverter::Panic(EStatusConverterDataTooShort));
+
+	aValue = 0;
+	
+	for(TInt i = 0 ; i < aLength; i++)
+		{
+		aValue |= aCommandData[aOffset+i]<<(8*i);
+		}
+	}
+	
+/** Set the command data.  This overwrites the current
+contents of the data buffer.
+
+@param aCommandData The buffer in which to set the data.
+@param aOffset The offset within aCommandData to set the data.
+@param aLength The length of data to replace.
+@param aValue The new value for the replaced data.
+*/
+void CRemConAvrcpStatusConverter::SetCommandDataFromInt(TDes8& aCommandData, 
+	TInt aOffset, TInt aLength, TInt aValue)
+	{
+	__ASSERT_DEBUG(aLength <= 4, CRemConAvrcpStatusConverter::Panic(EStatusConverterDataTooShort));
+	
+	for(TInt i = 0; i < aLength; i++)
+		{
+		aCommandData[aOffset+i] = aValue >> (8*i);
+		}
+	}
+
+/** Utility Status Converter panic function.
+
+@param aPanic The panic number.
+*/
+void CRemConAvrcpStatusConverter::Panic(TStatusConverterPanic aPanic)
+	{
+	User::Panic(KStatusConverterPanicName, aPanic);
+	}
+
+//
+// End of file