bluetoothappprofiles/avrcp/avrcpipc/src/ipc.cpp
changeset 0 f63038272f30
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothappprofiles/avrcp/avrcpipc/src/ipc.cpp	Mon Jan 18 20:28:57 2010 +0200
@@ -0,0 +1,1541 @@
+// Copyright (c) 2007-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
+ @internalTechnology
+ @released
+*/
+
+#include <e32debug.h>
+#include <remconmediaerror.h>
+#include "avrcpipcutils.h"
+#include "avrcpinternalinterface.h"
+#include "mediabrowse.h"
+#include "mediainformation.h"
+#include "nowplaying.h"
+#include "playerinformation.h"
+
+/*
+ * These methods are intended to provide structured IPC communication between
+ * the AVRCP bearer, and the client API DLLs. They are intended to be 'simple'
+ * classes, in which the basic operation are as follows:
+ *
+ *   reading: call ReadL(request) and pull information out of member variables
+ *   writing: put information into member variables, then call WriteL(request)
+ *
+ * The ReadL() and WriteL() methods effectively just serialize the information
+ * already stored in the member varables. However, they serialize in Big-Endian
+ * format, so that after calling WriteL() and then sending the response back to
+ * the AVRCP bearer via IPC, the bearer can just append the response straight
+ * into an AVC frame; no bit-twiddling is necessary.
+ *
+ * Therefore it is important that these classes _ALWAYS_ write in Big-Endian
+ * format, and write out responses that conform to the AVRCP specification for
+ * PDUs listed in sections 5.1 - 5.4 of the AVRCP 1.3 specification. The ReadL()
+ * operation is the inverse of the WriteL() operation and reads an AVRCP request
+ * in the format listed in the AVRCP specification.
+ *
+ * There's also a Size() method, which will return the size of the response
+ * before WriteL() is called. This is required particularly for responses with
+ * text strings so that the correct-sized buffer can be allocated, as these
+ * could be very large responses (theoretically up to 16 megabytes!) sent via
+ * IPC (just once) and then kept and fragmented in the AVRCP bearer. The Close()
+ * method frees up any memory allocated with these classes.
+ */
+
+
+// --------------------------------------------------------------------------------
+// Used for constructing PDU 0x30 responses
+
+EXPORT_C void RRemConPlayerInformationGetPlayStatusResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iTrackLength      = Read32L();
+	iPlayPos          = Read32L();
+	iStatus           = (MPlayerEventsObserver::TPlaybackStatus) Read8L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerInformationGetPlayStatusResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	Write32L(iTrackLength);
+	Write32L(iPlayPos);
+	Write8L(iStatus);
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for constructing PDU 0xff requests
+
+EXPORT_C void RRemConPlayerInformationGetPlayStatusUpdateRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iStatus           = (MPlayerEventsObserver::TPlaybackStatus) Read8L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerInformationGetPlayStatusUpdateRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write8L(iStatus);
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for constructing PDU 0xff responses
+
+EXPORT_C void RRemConPlayerInformationGetPlayStatusUpdateResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iStatus           = (MPlayerEventsObserver::TPlaybackStatus) Read8L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerInformationGetPlayStatusUpdateResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iStatus);
+	iStream.CommitL();
+	}
+// --------------------------------------------------------------------------------
+// Used for constructing PDU 0x15 and PDU 0x16 responses
+
+EXPORT_C void RRemConGetPlayerApplicationTextResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iNumberAttributes = Read8L();
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		RSettingWithCharset setting;
+		CleanupClosePushL(setting);
+		setting.iAttributeId = Read8L();
+		setting.iCharset     = Read16L();
+		setting.iStringLen   = Read8L();
+		setting.iString      = HBufC8::NewL(setting.iStringLen);
+		TPtr8 ptr            = setting.iString->Des();
+		iReadStream.ReadL(ptr);
+		iAttributes.AppendL(setting);
+		CleanupStack::Pop(&setting);
+		}
+	
+	}
+
+EXPORT_C void RRemConGetPlayerApplicationTextResponse::WriteL(TDes8& aOutData)
+	{
+	// The caller should have called Size() to pre-allocate enough buffer space
+	__ASSERT_DEBUG(aOutData.MaxLength() >= Size(), AvrcpIpcUtils::Panic(EAvrcpIpcCommandDataTooLong));
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iNumberAttributes);
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write8L(iAttributes[i].iAttributeId);
+		Write16L(iAttributes[i].iCharset);
+		Write8L(iAttributes[i].iStringLen);
+		iStream.WriteL(iAttributes[i].iString->Des());
+		}
+	iStream.CommitL();
+	}
+
+EXPORT_C TInt RRemConGetPlayerApplicationTextResponse::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	
+	TInt size = 5; // 5 bytes: status code + number attributes
+	for (TInt i = 0; i < iNumberAttributes; i++)
+		{
+		size += 4;   // 4 bytes: attribute id + charset + stringlen
+		size += iAttributes[i].iString->Length();
+		}
+	return size;
+	}
+
+EXPORT_C void RRemConGetPlayerApplicationTextResponse::Close()
+	{
+	for (TInt i = 0; i < iAttributes.Count(); i++)
+		{
+		iAttributes[i].Close();
+		}
+	iAttributes.Close();
+	RAvrcpIPC::Close();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for constructing PDU 0x10 responses
+
+EXPORT_C void RRemConGetCapabilitiesResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iCapabilityId     = Read8L();
+	if (   iCapabilityId != ECapabilityIdCompanyID
+	    && iCapabilityId != ECapabilityIdEventsSupported)
+		{
+		iReadStream.Close();
+		User::Leave(KErrNotSupported);
+		}
+	
+	iCapabilityCount  = Read8L();
+	for (TInt i = 0; i < iCapabilityCount; i++ )
+		{
+		if (iCapabilityId == ECapabilityIdCompanyID)
+			{
+			iCapabilities.AppendL(Read24L());  // Read 3 bytes
+			}
+		else
+			{
+			iCapabilities.AppendL(Read8L());   // Read 1 byte
+			}
+		}
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConGetCapabilitiesResponse::WriteL(TDes8& aOutData)
+	{
+	if (   iCapabilityId != ECapabilityIdCompanyID
+	    && iCapabilityId != ECapabilityIdEventsSupported)
+		{
+		User::Leave(KErrNotSupported);
+		}
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iCapabilityId);
+	Write8L(iCapabilityCount);
+	for (TInt i = 0; i < iCapabilityCount; i++ )
+		{
+		if (iCapabilityId == ECapabilityIdCompanyID)
+			{
+			Write24L(iCapabilities[i]);  // Write 3 bytes
+			}
+		else
+			{
+			Write8L(iCapabilities[i]);   // Write 1 byte
+			}
+		}
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for constructing and parsing PDU 0x13 (response) and PDU 0x14 (request)
+
+EXPORT_C void RRemConPlayerAttributeIdsAndValues::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iNumberAttributes = Read8L();
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		TInt attributeId     = Read8L();
+		TInt attributeValue = Read8L();
+		iAttributeId.AppendL(attributeId);
+		iAttributeValue.AppendL(attributeValue);
+		}
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerAttributeIdsAndValues::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iNumberAttributes);
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write8L(iAttributeId[i]);
+		Write8L(iAttributeValue[i]);
+		}
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for constructing PDU 0x11 and PDU 0x12 responses
+
+EXPORT_C void RRemConPlayerListOfAttributes::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iNumberAttributes = Read8L();
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		TInt attribute = Read8L();
+		iAttributes.AppendL(attribute);
+		}
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerListOfAttributes::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	iAttributes.Sort();
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iNumberAttributes);
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write8L(iAttributes[i]);
+		}
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing PDU 0x20 requests
+
+EXPORT_C void RRemConGetElementAttributesRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iElement = Read64L();
+	iNumberAttributes = Read8L();
+	
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		TInt attribute = Read32L();
+		iAttributes.AppendL(attribute);
+		}
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConGetElementAttributesRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	iAttributes.Sort();
+	Write32L(KErrNone);   // Successful operation
+	
+	// 64 bits of data
+	Write64L(iElement);
+	Write8L(iNumberAttributes);
+
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write32L(iAttributes[i]);
+		}
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for PDU 0x20 responses
+
+EXPORT_C void RRemConGetElementAttributesResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iNumberAttributes = Read8L();
+	
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		REAResponse eattr;
+		CleanupClosePushL(eattr);
+		eattr.iAttributeId = Read32L();
+		eattr.iCharset     = Read16L();
+		eattr.iStringLen   = Read16L();
+		eattr.iString      = HBufC8::NewL(eattr.iStringLen);
+		TPtr8 ptr          = eattr.iString->Des();
+		iReadStream.ReadL(ptr);
+		iAttributes.AppendL(eattr);
+		CleanupStack::Pop(&eattr);
+		}
+	
+	}
+
+EXPORT_C void RRemConGetElementAttributesResponse::WriteL(TDes8& aOutData)
+	{
+	__ASSERT_DEBUG(aOutData.MaxLength() >= Size(), AvrcpIpcUtils::Panic(EAvrcpIpcCommandDataTooLong));
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write8L(iNumberAttributes);
+
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write32L(iAttributes[i].iAttributeId);
+		Write16L(iAttributes[i].iCharset);
+		Write16L(iAttributes[i].iStringLen);
+		iStream.WriteL(iAttributes[i].iString->Des());
+		}
+	iStream.CommitL();
+	}
+
+EXPORT_C TInt RRemConGetElementAttributesResponse::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	
+	TInt size = 5; // 5 bytes: status code + number attributes
+	for (TInt i = 0; i < iNumberAttributes; i++)
+		{
+		size += 4+2+2; // 8 bytes: attrId (4 bytes) + charset (2 bytes) + stringlen (2 bytes)
+		size += iAttributes[i].iString->Length();
+		}
+	return size;
+	}
+
+EXPORT_C void RRemConGetElementAttributesResponse::Close()
+	{
+	for (TInt i = 0; i < iAttributes.Count(); i++)
+		{
+		iAttributes[i].Close();
+		}
+	iAttributes.Close();
+	RAvrcpIPC::Close();
+	}
+
+// --------------------------------------------------------------------------------
+
+EXPORT_C void RRemConPlayerInformation8BitResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iValue = Read8L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerInformation8BitResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write8L(iValue);
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+
+EXPORT_C void RRemConPlayerInformation32BitResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iValue = Read32L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerInformation32BitResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write32L(iValue);
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+
+EXPORT_C void RRemConPlayerInformation64BitResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iValue = Read64L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConPlayerInformation64BitResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write64L(iValue);
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+
+EXPORT_C void RSettingWithCharset::Close()
+	{
+	delete iString;
+	iString = NULL;
+	}
+
+EXPORT_C void REAResponse::Close()
+	{
+	delete iString;
+	iString = NULL;
+	}
+
+EXPORT_C void RRemConGetCapabilitiesResponse::Close()
+	{
+	iCapabilities.Close();
+	}
+
+EXPORT_C void RRemConPlayerListOfAttributes::Close()
+	{
+	iAttributes.Close();
+	}
+
+EXPORT_C void RRemConGetElementAttributesRequest::Close()
+	{
+	iAttributes.Close();
+	}
+
+EXPORT_C void RRemConPlayerAttributeIdsAndValues::Close()
+	{
+	iAttributeId.Close();
+	iAttributeValue.Close();
+	}
+
+EXPORT_C void RItem::Close()
+	{
+	delete iName;
+	for(TInt i = 0; i<iAttributes.Count(); i++)
+		{
+		iAttributes[i].Close();
+		}
+	}
+
+EXPORT_C TInt RItem::Size()
+	{
+	// Base size:
+	// type + length field + length
+	return 3 + iLength;
+	}
+
+EXPORT_C void RMediaPlayerItem::Close()
+	{
+	iName.Close();
+	}
+
+EXPORT_C TInt RMediaPlayerItem::Size()
+	{
+	// Base size:
+	// type + length field + length
+	return 3 + iLength;
+	}
+
+/**
+Parses PDU 0x74 and 0x90 requests.
+*/
+EXPORT_C void RRemConNowPlayingRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iScope = static_cast<TRemConFolderScope>(Read8L());
+	iElement = Read64L();
+	iUidCounter = Read16L();
+	}
+
+/**
+Constructs PDU 0x74 and 0x90 requests.
+*/
+EXPORT_C void RRemConNowPlayingRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iScope);
+	Write64L(iElement);
+	Write16L(iUidCounter);
+	iStream.CommitL();
+	}
+
+/**
+Parses PDU 0x74 and 0x90 responses
+*/
+EXPORT_C void RRemConNowPlayingResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iStatus = Read8L();
+	}
+
+/**
+Constructs PDU 0x74 and 0x90 responses.
+*/
+EXPORT_C void RRemConNowPlayingResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	if ((KErrAvrcpAirBase - KErrAvrcpAirSuccess) == iStatus)
+	    {
+	    Write32L(KErrNone);   // Successful operation
+	    Write8L(iStatus);
+	    }
+	else
+		{
+		Write32L(KErrAvrcpAirBase - iStatus);
+		}
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing PDU 0x71 requests
+EXPORT_C void RRemConGetFolderItemsRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iScope = Read8L();
+	iStartItem = Read32L();
+	iEndItem = Read32L();
+	iNumberAttributes = Read8L();
+	
+	if (iNumberAttributes == 0)
+		{
+		// spec says this is a request for all attribs
+		// current spec has 7 specified (0x01 to 0x07)
+		for (TInt i = 1; i <= KMaxMediaAttributeValue; i++)
+			{
+			iAttributes.AppendL(i);
+			}
+		}
+	else if (iNumberAttributes == 0xff)
+		{
+		// No attributes requested
+		}
+	else
+		{
+		for (TInt i = 0; i < iNumberAttributes; i++ )
+			{
+			TInt attribute = Read32L();
+			if (attribute > 0 && attribute <= KMaxMediaAttributeValue )
+				{
+				iAttributes.AppendL(attribute);
+				}
+			}
+		}
+
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConGetFolderItemsRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	iAttributes.Sort();
+	Write32L(KErrNone);   // Successful operation
+	
+	Write8L(iScope);
+	Write32L(iStartItem);
+	Write32L(iEndItem);
+	Write8L(iNumberAttributes);
+
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write32L(iAttributes[i]);
+		}
+
+	iStream.CommitL();
+	}
+
+EXPORT_C void RRemConGetFolderItemsRequest::Close()
+	{
+	iAttributes.Close();
+	}
+
+EXPORT_C TInt RRemConGetFolderItemsRequest::CopyAttributes(RArray<TMediaAttributeId>& aOutAttributes)
+	{
+	TInt result = KErrNone;
+	TMediaAttributeId attributeId;
+	TInt attributeCount = iAttributes.Count();
+	for (TInt i = 0; i < attributeCount; i++)
+		{
+		attributeId = static_cast<TMediaAttributeId>(iAttributes[i]);
+		result = aOutAttributes.Append(attributeId);
+		if (result != KErrNone)
+			{
+			break;
+			}
+		}
+	return result;
+	}
+// --------------------------------------------------------------------------------
+// Used for PDU 0x71 responses
+
+EXPORT_C void RRemConGetFolderItemsResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iPduId = Read8L();
+	iParamLength = Read16L();
+	iStatus = Read8L();
+	iUidCounter = Read16L();
+	iNumberItems = Read16L();
+	
+	for(TInt i = 0; i < iNumberItems; i++)
+		{
+		ReadItemL();
+		}
+	
+	iReadStream.Close();
+	}
+
+void RRemConGetFolderItemsResponse::ReadItemL()
+	{
+	RItem item;
+	CleanupClosePushL(item);
+	
+	item.iType = static_cast<AvrcpBrowsing::TItemType>(Read8L());
+	item.iLength = Read16L();
+	item.iUid = Read64L();
+	
+	if(item.iType == AvrcpBrowsing::EFolderItem)
+		{
+		item.iFolderType = static_cast<AvrcpBrowsing::TFolderType>(Read8L());
+		item.iPlayable = Read8L();
+		}
+	else 
+		{
+		item.iMediaType = Read8L();
+		}
+	
+	item.iCharset = Read16L();
+	item.iNameLength = Read16L();
+	item.iName = HBufC8::NewL(item.iNameLength);
+	TPtr8 ptr = item.iName->Des();
+	iReadStream.ReadL(ptr);
+	
+	if(item.iType == AvrcpBrowsing::EMediaElement)
+		{
+		item.iNumberAttributes = Read32L();
+		
+		for (TInt i = 0; i < item.iNumberAttributes; i++ )
+			{
+			REAResponse eattr;
+			CleanupClosePushL(eattr);
+			
+			eattr.iAttributeId = Read32L();
+			eattr.iCharset     = Read16L();
+			eattr.iStringLen   = Read16L();
+			eattr.iString      = HBufC8::NewL(eattr.iStringLen);
+			TPtr8 ptr          = eattr.iString->Des();
+			iReadStream.ReadL(ptr);
+			
+			item.iAttributes.AppendL(eattr);
+			CleanupStack::Pop(&eattr);
+			}
+		}
+	
+	iItems.AppendL(item);
+	CleanupStack::Pop(&item);
+	}
+
+EXPORT_C void RRemConGetFolderItemsResponse::WriteL(TDes8& aOutData)
+	{
+	__ASSERT_DEBUG(aOutData.MaxLength() >= Size(), AvrcpIpcUtils::Panic(EAvrcpIpcCommandDataTooLong));
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write8L(iPduId);
+	Write16L(iParamLength);
+	Write8L(iStatus);
+	
+	if(iStatus == 0x4)
+		{
+		Write16L(iUidCounter);
+		Write16L(iNumberItems);
+	
+		for (TInt i = 0; i < iNumberItems; i++ )
+			{
+			WriteItemL(i);
+			}
+		}
+	
+	iStream.CommitL();
+	}
+
+void RRemConGetFolderItemsResponse::WriteItemL(TInt aIndex)
+	{
+	RItem& item = iItems[aIndex];
+	
+	Write8L(item.iType);
+	Write16L(item.iLength);
+	Write64L(item.iUid);
+	
+	if(item.iType == AvrcpBrowsing::EFolderItem)
+		{
+		Write8L(item.iFolderType);
+		Write8L(item.iPlayable);
+		}
+	else
+		{
+		Write8L(item.iMediaType);
+		}
+	
+	Write16L(item.iCharset);
+	Write16L(item.iNameLength);
+	iStream.WriteL(item.iName->Des());
+	
+	if(item.iType == AvrcpBrowsing::EMediaElement)
+		{
+		Write8L(item.iNumberAttributes);
+		
+		for(TInt i = 0; i < item.iNumberAttributes; i++)
+			{
+			Write32L(item.iAttributes[i].iAttributeId);
+			Write16L(item.iAttributes[i].iCharset);
+			Write16L(item.iAttributes[i].iStringLen);
+			iStream.WriteL(item.iAttributes[i].iString->Des());
+			}
+		}
+	}
+
+EXPORT_C TInt RRemConGetFolderItemsResponse::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	
+	// base size 
+	// pduid + paramlength + status + uidcount + number items
+	TInt size = KGetFolderItemsResponseBaseSize;
+	
+	for (TInt i = 0; i < iNumberItems; i++)
+		{
+		size += iItems[i].Size();
+		}
+	return size;
+	}
+
+EXPORT_C void RRemConGetFolderItemsResponse::Close()
+	{
+	for (TInt i = 0; i < iItems.Count(); i++)
+		{
+		iItems[i].Close();
+		}
+	iItems.Reset();
+	}
+
+EXPORT_C TInt RRemConGetFolderItemsResponse::CopyItems(
+		const TArray<TRemConItem>& aItems)
+	{
+	TInt err = KErrNone;
+	for(TInt i = 0; i < aItems.Count(); i++)
+		{
+		RItem item;
+		item.iName = NULL;
+		item.iUid = aItems[i].iUid;
+		item.iType = static_cast<AvrcpBrowsing::TItemType>(aItems[i].iType);
+		
+		err = iItems.Append(item);
+		if(err)
+			{
+			break;
+			}
+		}
+	return err;
+	}
+
+EXPORT_C TBool RRemConGetFolderItemsResponse::RequestNextItem(TInt& aError, 
+		RBuf8& aOutBuf, TUint16 aCookie)
+	{
+	aError = KErrNone;
+	// Work out if we have as many items as fit
+	TBool getMoreItems = ETrue;
+	iCurrentListingSize += (iCurrentItem + 1) ? iItems[iCurrentItem].Size() : 0;
+	if(iCurrentListingSize > iMaxResponse)
+		{
+		// We can't fit this item in the listing
+		iItems[iCurrentItem].Close();
+		getMoreItems = EFalse;
+		iItems.Remove(iCurrentItem);
+		}
+	
+	if(getMoreItems && ++iCurrentItem < iItems.Count())
+		{
+		return ETrue;
+		}
+	else
+		{
+		// We have all items, send the response
+		iNumberItems = iCurrentItem;
+		if(aOutBuf.Create(Size()) != KErrNone)
+			{
+			aError = KErrGeneral;
+			return EFalse;
+			}
+		
+		iPduId = AvrcpBrowsing::EGetFolderItems;
+		iStatus = KErrAvrcpAirBase - KErrAvrcpAirSuccess;//0x4
+		iUidCounter = aCookie;
+		TRAP(aError, WriteL(aOutBuf));
+		}
+	return EFalse;
+	}
+// --------------------------------------------------------------------------------
+// Used for parsing PDU 0x72 requests
+
+EXPORT_C void RRemConChangePathRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iUidCounter = Read16L();
+	iDirection = Read8L();
+	
+	if(iDirection == AvrcpBrowsing::KDown)
+		{
+		iElement = Read64L();
+		}
+
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConChangePathRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write16L(iUidCounter);
+	Write8L(iDirection);
+	Write64L(iElement);
+
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for PDU 0x72 responses
+
+EXPORT_C void RRemConChangePathResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iStatus = Read8L();
+	iNumberItems = Read32L();
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConChangePathResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write8L(iPduId);
+	Write16L(iParamLength);
+	Write8L(iStatus);
+	
+	if(iStatus == 0x4)
+		{
+		Write32L(iNumberItems);
+		}
+		
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing PDU 0x73 requests
+
+EXPORT_C void RRemConGetItemAttributesRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iScope = Read8L();
+	iElement = Read64L();
+	iUidCounter = Read16L();
+	iNumberAttributes = Read8L();
+	
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		TInt attribute = Read32L();
+		iAttributes.AppendL(attribute);
+		}
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConGetItemAttributesRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	iAttributes.Sort();
+	Write32L(KErrNone);   // Successful operation
+	
+	Write8L(iScope);
+	// 64 bits of data
+	Write64L(iElement);
+	Write16L(iUidCounter);
+	Write8L(iNumberAttributes);
+
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		Write32L(iAttributes[i]);
+		}
+	iStream.CommitL();
+	}
+
+EXPORT_C void RRemConGetItemAttributesRequest::Close()
+	{
+	iAttributes.Close();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for PDU 0x73 responses
+
+EXPORT_C void RRemConGetItemAttributesResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iStatus = Read8L();
+	iNumberAttributes = Read8L();
+	
+	for (TInt i = 0; i < iNumberAttributes; i++ )
+		{
+		REAResponse eattr;
+		eattr.iAttributeId = Read32L();
+		eattr.iCharset     = Read16L();
+		eattr.iStringLen   = Read16L();
+		eattr.iString      = HBufC8::NewL(eattr.iStringLen);
+		TPtr8 ptr          = eattr.iString->Des();
+		iReadStream.ReadL(ptr);
+		iAttributes.AppendL(eattr);
+		}
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConGetItemAttributesResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write8L(iPduId);
+	Write16L(iParamLength);
+	Write8L(iStatus);
+	
+	if(iStatus == 0x4)
+		{
+		Write8L(iNumberAttributes);
+	
+		for (TInt i = 0; i < iNumberAttributes; i++ )
+			{
+			Write32L(iAttributes[i].iAttributeId);
+			Write16L(iAttributes[i].iCharset);
+			Write16L(iAttributes[i].iStringLen);
+			iStream.WriteL(iAttributes[i].iString->Des());
+			}
+		}
+	iStream.CommitL();
+	}
+
+EXPORT_C TInt RRemConGetItemAttributesResponse::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	
+	TInt size = 9; // 6 bytes: error + pduid + paramlength + status code + number attributes
+	for (TInt i = 0; i < iAttributes.Count(); i++)
+		{
+		size += 4+2+2; // 8 bytes: attrId (4 bytes) + charset (2 bytes) + stringlen (2 bytes)
+		size += iAttributes[i].iString->Length();
+		}
+	return size;
+	}
+
+EXPORT_C void RRemConGetItemAttributesResponse::Close()
+	{
+	for (TInt i = 0; i < iAttributes.Count(); i++)
+		{
+		iAttributes[i].Close();
+		}
+	iAttributes.Close();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing PDU 0x80 requests
+
+EXPORT_C void RRemConSearchRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iCharset = Read16L();
+	iStringLen = Read16L();
+	
+	TInt dataLength = aData.Length();
+	TPtrC8 pString = aData.Right(dataLength - 2*sizeof(TUint16));
+	if (pString.Length() != iStringLen)
+		{
+		User::Leave(KErrArgument);
+		}
+	
+	RBuf8 searchBuf;
+	searchBuf.CreateL(iStringLen);
+	CleanupClosePushL(searchBuf);
+	
+	iReadStream.ReadL(searchBuf);
+	
+	CleanupStack::Pop(&searchBuf);
+	iSearchString.Assign(searchBuf);
+
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConSearchRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write16L(iCharset);
+	Write16L(iStringLen);
+	WriteL(iSearchString);
+	
+	iStream.CommitL();
+	}
+
+EXPORT_C TInt RRemConSearchRequest::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	TInt size = sizeof(iCharset) + sizeof(iStringLen) + iSearchString.Length(); 
+	
+	return size;
+	}
+
+EXPORT_C void RRemConSearchRequest::Close()
+	{
+	iSearchString.Close();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for PDU 0x80 responses
+
+EXPORT_C void RRemConSearchResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iStatus = Read8L();
+	iUidCounter = Read16L();
+	iNumberItems = Read32L();
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConSearchResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write8L(iPduId);
+	Write16L(iParamLength);
+	Write8L(iStatus);
+	
+	if(iStatus == 0x4)
+		{
+		Write16L(iUidCounter);
+		Write32L(iNumberItems);
+		}
+
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing SetBrowsedPlayer requests
+
+EXPORT_C void RRemConSetBrowsedPlayerRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	// iMaxResponse is little endian
+	iMaxResponse = iReadStream.ReadInt32L();
+	iPlayerId = Read16L();
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConSetBrowsedPlayerRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	// Use little endian on iMaxResponse
+	iStream.WriteInt32L(iMaxResponse);
+	Write16L(iPlayerId);
+	
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for SetBrowsedPlayer responses
+
+EXPORT_C void RRemConGetPathResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iStatus = Read8L();
+	iUidCounter = Read16L();
+	iNumberItems = Read32L();
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConGetPathResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write8L(iPduId);
+	Write16L(iParamLength);
+	Write8L(iStatus);
+	
+	if(iStatus != 0x4)
+		{
+		iStream.CommitL();
+		return;
+		}
+    
+	// The depth is equal to the number of items in the array.
+	iFolderDepth = iPath.Count();
+	Write16L(iUidCounter);
+	Write32L(iNumberItems);
+	Write16L(KUtf8MibEnum);
+	Write8L(iFolderDepth);
+	
+	for(TInt i = 0; i < iFolderDepth; i++)
+		{
+		Write16L((iPath[i])->Length());
+		iStream.WriteL(*(iPath[i]));
+		}
+	
+	iStream.CommitL();
+	}
+
+EXPORT_C TInt RRemConGetPathResponse::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	iFolderDepth = iPath.Count();
+	TInt size = 13 + (iFolderDepth*2);
+	
+	for(TInt i = 0; i < iFolderDepth; i++)
+		{
+		size += (iPath[i])->Length();
+		}
+	
+	return size;
+	}
+
+EXPORT_C void RRemConGetPathResponse::Close()
+	{
+	iPath.ResetAndDestroy();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing SetAddressedPlayer requests
+
+EXPORT_C void RAvrcpSetAddressedPlayerRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iPlayerId = Read16L();
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RAvrcpSetAddressedPlayerRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write16L(iPlayerId);
+	
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for SetAddressedPlayer responses
+
+EXPORT_C void RAvrcpSetAddressedPlayerResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iStatus = Read8L();
+	
+	iReadStream.Close();
+	}
+
+EXPORT_C void RAvrcpSetAddressedPlayerResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write32L(KErrNone);   // Successful operation
+	Write8L(iStatus);
+	
+	iStream.CommitL();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for parsing PDU 0x71 requests with media player list scope
+
+EXPORT_C void RAvrcpGetFolderItemsRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iScope = Read8L();
+	iStartItem = Read32L();
+	iEndItem = Read32L();
+	}
+
+EXPORT_C void RAvrcpGetFolderItemsRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write8L(iScope);
+	Write32L(iStartItem);
+	Write32L(iEndItem);
+
+	iStream.CommitL();
+	}
+
+EXPORT_C void RAvrcpGetFolderItemsRequest::Close()
+	{
+	RAvrcpIPC::Close();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for PDU 0x71 responses with media player list scope
+
+EXPORT_C void RAvrcpGetFolderItemsResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	
+	iPduId = Read8L();
+	iParamLength = Read16L();
+	iStatus = Read8L();
+	iUidCounter = Read16L();
+	iNumberItems = Read16L();
+	
+	for(TInt i = 0; i < iNumberItems; i++)
+		{
+		ReadItemL();
+		}
+	
+	iReadStream.Close();
+	}
+
+void RAvrcpGetFolderItemsResponse::ReadItemL()
+	{
+	RMediaPlayerItem item;
+	CleanupClosePushL(item);
+	
+	item.iType = static_cast<AvrcpBrowsing::TItemType>(Read8L());
+	item.iLength = Read16L();
+	item.iPlayerId = Read16L();
+	
+	item.iPlayerType = Read8L();
+	item.iPlayerSubType = Read32L();
+	item.iPlayStatus = Read8L();
+	iReadStream.ReadL(item.iFeatureBitmask);
+	
+	item.iCharset = Read16L();
+	item.iNameLength = Read16L();
+	
+	item.iName.CreateL(item.iNameLength);
+	iReadStream.ReadL(item.iName);
+	
+	iItems.AppendL(item);
+	CleanupStack::Pop(&item);
+	}
+
+EXPORT_C void RAvrcpGetFolderItemsResponse::WriteL(TDes8& aOutData)
+	{
+	__ASSERT_DEBUG(aOutData.MaxLength() >= Size(), AvrcpIpcUtils::Panic(EAvrcpIpcCommandDataTooLong));
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	
+	Write8L(iPduId);
+	Write16L(iParamLength);
+	Write8L(iStatus);
+	
+	if(iStatus == 0x4)
+		{
+		Write16L(iUidCounter);
+		Write16L(iNumberItems);
+	
+		for (TInt i = 0; i < iNumberItems; i++ )
+			{
+			WriteItemL(i);
+			}
+		}
+	
+	iStream.CommitL();
+	}
+
+void RAvrcpGetFolderItemsResponse::WriteItemL(TInt aIndex)
+	{
+	RMediaPlayerItem& item = iItems[aIndex];
+	
+	Write8L(item.iType);
+	Write16L(item.iLength);
+	Write16L(item.iPlayerId);
+	
+	Write8L(item.iPlayerType);
+	Write32L(item.iPlayerSubType);
+	Write8L(item.iPlayStatus);
+	iStream.WriteL(item.iFeatureBitmask);
+	
+	Write16L(item.iCharset);
+	Write16L(item.iNameLength);
+	iStream.WriteL(item.iName);
+	}
+
+EXPORT_C TInt RAvrcpGetFolderItemsResponse::Size()
+	{
+	// Return the size that a buffer needs to be allocated to
+	// serialise the data encapsulated within this data structure.
+	
+	// base size 
+	// pduid + paramlength + status + uidcount + number items
+	TInt size = KGetFolderItemsResponseBaseSize;
+	
+	for (TInt i = 0; i < iNumberItems; i++)
+		{
+		size += iItems[i].Size();
+		}
+	return size;
+	}
+
+EXPORT_C void RAvrcpGetFolderItemsResponse::Close()
+	{
+	for (TInt i = 0; i < iNumberItems; i++)
+		{
+		iItems[i].Close();
+		}
+	iItems.Reset();
+	}
+
+// --------------------------------------------------------------------------------
+// Used for PDU 0x30 responses with event addressed player changed
+
+EXPORT_C void RAvrcpAddressedPlayerNotificationResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iPlayerId = Read16L();
+	iUidCounter = Read16L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RAvrcpAddressedPlayerNotificationResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write16L(iPlayerId);
+	Write16L(iUidCounter);
+	iStream.CommitL();
+	}
+
+EXPORT_C void RAvrcpUidCounterNotificationResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iUidCounter = Read16L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RAvrcpUidCounterNotificationResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write32L(KErrNone);   // Successful operation
+	
+	Write16L(iUidCounter);
+	iStream.CommitL();
+	}
+
+EXPORT_C void RRemConMediaErrorResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iPduId = Read8L();
+	iLength = Read16L();
+	iStatus = Read8L();
+	iReadStream.Close();
+	}
+
+EXPORT_C void RRemConMediaErrorResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write8L(iPduId);
+	Write16L(KErrResponseParameterLength);
+	Write8L(iStatus);
+	iStream.CommitL();
+	}
+
+EXPORT_C TUint8 RAvrcpIPC::SymbianErrToStatus(TInt aErr)
+	{
+	return KErrAvrcpAirBase - SymbianErrorCheck(aErr);
+	}
+
+/**
+Ensure we get a known error.
+*/
+EXPORT_C TInt RAvrcpIPC::SymbianErrorCheck(TInt aError)
+	{
+	TInt error = aError;
+	
+	switch (error)
+		{
+		case KErrNone:
+			error = KErrAvrcpAirSuccess;
+			break;
+		case KErrAvrcpAirInvalidCommand:
+		case KErrAvrcpAirInvalidParameter:
+		case KErrAvrcpAirParameterNotFound:
+		case KErrAvrcpAirInternalError:
+		case KErrAvrcpAirSuccess:
+		case KErrAvrcpAirUidChanged:
+		case KErrAvrcpAirReserved:
+		case KErrAvrcpAirInvalidDirection:
+		case KErrAvrcpAirNotADirectory:
+		case KErrAvrcpAirDoesNotExist:
+		case KErrAvrcpAirInvalidScope:
+		case KErrAvrcpAirRangeOutOfBounds:
+		case KErrAvrcpAirUidIsADirectory:
+		case KErrAvrcpAirMediaInUse:
+		case KErrAvrcpAirNowPlayingListFull:
+		case KErrAvrcpAirSearchNotSupported:
+		case KErrAvrcpAirSearchInProgress:
+		case KErrAvrcpAirInvalidPlayerId:
+		case KErrAvrcpAirPlayerNotBrowesable:
+		case KErrAvrcpAirPlayerNotAddressed:
+		case KErrAvrcpAirNoValidSearchResults:
+		case KErrAvrcpAirNoAvailablePlayers:
+		case KErrAvrcpAirAddressedPlayerChanged:
+		case KErrAvrcpInvalidScope:
+			break;
+		default:
+			error = KErrAvrcpAirInternalError;
+		}
+	
+	return error;
+	}
+
+EXPORT_C void RRemConUidsChangedRequest::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iInitialUidCounter = Read16L();
+	}
+
+EXPORT_C void RRemConUidsChangedRequest::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write16L(iInitialUidCounter);
+	iStream.CommitL();
+	}
+
+EXPORT_C void RRemConUidsChangedResponse::ReadL(const TDesC8& aData)
+	{
+	iReadStream.Open(aData);
+	iUidCounter = Read16L();
+	}
+
+EXPORT_C void RRemConUidsChangedResponse::WriteL(TDes8& aOutData)
+	{
+	aOutData.Zero();
+	iStream.Open(aOutData);
+	Write16L(iUidCounter);
+	iStream.CommitL();
+	}