bluetooth/btstack/avdtp/avdtpSignallingChannel.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avdtp/avdtpSignallingChannel.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1903 @@
+// Copyright (c) 2003-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:
+// Implements the avdtp signalling channel
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include "avdtpSignallingChannel.h"
+#include "avdtp.h"
+#include "avdtputil.h"
+#include "avdtpSignallingTransaction.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVDTP);
+#endif
+
+//Macro to just return (and enter debugger in debug builds) if we get an unsolicited response packet
+#define RETURN_IF_NO_TRANSACTION(transaction) 	if (!transaction) {	LOG(_L("No transaction found"));return;}
+#define RETURN_IF_SIGNAL_BAD(transaction, signal) if (!CheckSignal(*transaction, signal)) {LOG1(_L("Transaction has different signal (%d)"), signal); return;}
+
+// check that sessions have replied with an AVDTP error in error cases
+#define	CHECK_ERROR(result) if (!(result<=KErrAvdtpSignallingErrorBase || result==KErrNone || result==KErrNotFound)) __DEBUGGER();
+
+CSignallingChannel* CSignallingChannel::NewL(CAvdtpProtocol& aProtocol,
+											 CLogicalChannelFactory& aChannelFactory,
+											 const TBTDevAddr& aRemoteAddress)
+	{
+	LOG_STATIC_FUNC
+	CSignallingChannel* s = CSignallingChannel::NewLC(aProtocol, aChannelFactory, aRemoteAddress);
+	CleanupStack::Pop();
+	return s;
+	}
+
+CSignallingChannel* CSignallingChannel::NewLC(CAvdtpProtocol& aProtocol,
+											  CLogicalChannelFactory& aChannelFactory,
+											  const TBTDevAddr& aRemoteAddress)
+	{
+	LOG_STATIC_FUNC
+	CSignallingChannel* s = new(ELeave)	CSignallingChannel(aProtocol, aChannelFactory, aRemoteAddress);
+	CleanupStack::PushL(s);
+	s->ConstructL();
+	return s;
+	}
+	
+CSignallingChannel::CSignallingChannel(CAvdtpProtocol& aProtocol,
+									   CLogicalChannelFactory& aChannelFactory,
+									   const TBTDevAddr& aRemoteAddress)
+: iProtocol(aProtocol),
+  iLogicalChannelFactory(aChannelFactory),
+  iPermanentUsers(_FOFF(XAvdtpSignalReceiver,iSignalReceiverEmbeddedLink)),
+  iTransactions(_FOFF(CSignallingTransaction,iLink)),
+  iRemoteAddress(aRemoteAddress),
+  iInboundMessage(*this),
+  iDraftMessages(_FOFF(CAvdtpOutboundSignallingMessage,iLink)),
+  iQueuedMessages(_FOFF(CAvdtpOutboundSignallingMessage,iLink))
+	{
+	LOG_FUNC
+	SetBlocked(EFalse);
+	
+	TCallBack cb(TryToClose, this);
+	iIdleTimerEntry.Set(cb);
+	}
+	
+void CSignallingChannel::ConstructL()
+	{
+	LOG_FUNC
+	TCallBack cb(CSignallingChannel::TryToSendCallback, this);
+	iTryToSendCallback = new (ELeave)CAsyncCallBack(cb, CActive::EPriorityStandard);
+	}
+
+CSignallingChannel::~CSignallingChannel()
+	{
+	LOG_FUNC
+	CancelIdleTimer();
+
+	// cancel possible outstanding factory request
+	iLogicalChannelFactory.Cancel(iLogicalChannelRequest);
+	
+	// remove from protocol's knowledge
+	iProtocol.SignallingChannelDown(*this);
+	
+	// any preauthorisation for device this represents is now void
+	if (!IsListening())
+		{
+		iProtocol.RemoteSEPCache().InvalidateSEPs(iRemoteAddress);
+		(void)iProtocol.SetPreauthorisation(iRemoteAddress, EFalse);
+		}
+		
+	if (iBearer)
+		{
+		// tell l2cap
+		iBearer->Shutdown(CServProviderBase::EImmediate);
+		}
+		
+	delete iBearer;
+	delete iTryToSendCallback;
+	}
+
+void CSignallingChannel::StartTryToSendCallback()
+	{
+	LOG_FUNC
+	if (!iTryToSendCallback->IsActive())
+		{
+		iTryToSendCallback->CallBack();
+		}
+	// else already running and will callback anyway
+	}
+
+void CSignallingChannel::CancelTryToSendCallback()
+	{
+	LOG_FUNC
+	iTryToSendCallback->Cancel();
+	}
+
+/*static*/ TInt CSignallingChannel::TryToSendCallback(TAny *aSigCh)
+	{
+	LOG_STATIC_FUNC
+	return (reinterpret_cast<CSignallingChannel*>(aSigCh))->TryToSendCallback();
+	}
+
+void CSignallingChannel::ObtainMTU()
+	{
+	LOG_FUNC
+	TPckg<TInt> mtubuf(iBearerMTU);
+	TInt err=iBearer->GetOption(KSolBtL2CAP,KL2CAPOutboundMTUForBestPerformance,mtubuf);
+	if (err!=KErrNone)
+		{
+		Error(err);
+		}
+	}
+
+/*
+Does post-packet-send processing
+*/
+void CSignallingChannel::PacketSent(CSignallingTransaction& aTransaction)
+	{
+	LOG_FUNC
+	// We can't delete the transaction yet, because it looks after timer.
+		
+	switch (aTransaction.SentAction())
+		{
+		case EKeepSetRTX:
+			{
+			aTransaction.StartTimer();
+			break;
+			}
+		case EDiscard:
+			{
+			// these transactions can be cleared up now
+			// we don't support caching of responses if they get lost - they'll be regenerated if needed
+			aTransaction.iLink.Deque();
+			delete &aTransaction;
+			break;
+			}
+		case EKeepDontSetRTX:
+		// do nothing!
+			break;
+		default:
+			__ASSERT_DEBUG(0, Panic(EAvdtpUnknownPostSendAction));
+		}
+	}
+	
+void CSignallingChannel::CheckOutboundQueue()
+	{
+	// check to see if the outbound queue is empty but we have an outstanding
+	// request to service it
+	if (iQueuedMessages.IsEmpty() && iTryToSendCallback->IsActive())
+		{
+		CancelTryToSendCallback();
+		}				
+	}
+	
+void CSignallingChannel::ServiceOutboundQueue()
+	{
+	LOG_FUNC
+	if (!Blocked())
+		{
+		// we can send!
+		// get fragments to send if we don't have any from before
+		if(iOutgoingSignallingMessage.IsEmpty())
+			{
+			// get the head message
+			CAvdtpOutboundSignallingMessage& message = *iQueuedMessages.First();
+			
+			// find the transaction pertaining to it (and make it the current transaction)
+			iCurrentTransaction = FindTransaction(message.TransactionLabel());
+			
+			__ASSERT_DEBUG(iCurrentTransaction!=NULL, Panic(EAvdtpSignallingChannelDrainingFaulty));
+			
+			// see whether this requires fragmenting, and get next fragment
+			// note reference return parameter
+			TRAPD(ret, iMoreFrags = message.GetNextOutboundFragmentL(iOutgoingSignallingMessage, iBearerMTU));
+			if (ret!=KErrNone)
+				{
+				iMoreFrags = EFalse;
+				iOutgoingSignallingMessage.Free();
+				// error the user
+				iCurrentTransaction->Error(ret);
+				return;
+				}
+			}
+			
+
+		// write outgoing fragments to bearer
+		TInt sent = iBearer->Write(iOutgoingSignallingMessage,NULL);
+		
+		if (!sent)
+			{
+			// leave fragment there for next time writing
+			SetBlocked(ETrue);
+			}
+		else
+			{
+			iOutgoingSignallingMessage.Free();
+			if (!iMoreFrags)
+				{
+				// that message has been completely sent
+				PacketSent(*iCurrentTransaction);
+				}
+			}
+
+		if (!iQueuedMessages.IsEmpty())
+			{
+			// more to send, send asynchronously.
+			StartTryToSendCallback();
+			}
+		else if (iTryToSendCallback->Priority()==KAvdtpReleaseAcceptPriority)
+            {
+            // cancel the Release send boost (actually might want to use boosting
+            // to clear remaining fragments of partially sent commands)
+            iTryToSendCallback->SetPriority(CActive::EPriorityStandard);
+            }
+   		}
+	}
+
+/*static*/ TInt CSignallingChannel::TryToSendCallback()
+	{
+	LOG_STATIC_FUNC
+	ServiceOutboundQueue();
+	return EFalse;
+	}
+
+TBTDevAddr CSignallingChannel::RemoteAddress()
+	{
+	LOG_FUNC
+	if (iBearer && IsListening())
+		{
+		TL2CAPSockAddr remote;
+		iBearer->RemName(remote);		
+		iRemoteAddress = remote.BTAddr();
+		}
+	if (iBearer)
+		{
+		return iRemoteAddress;
+		}
+	else
+		{
+		return TBTDevAddr(0);
+		}
+	}
+
+void CSignallingChannel::LogicalChannelFactoryRequestComplete(TLogicalChannelFactoryTicket aTicket, TInt aError)
+	{
+	LOG_FUNC
+	
+	if (aError == KErrNone)
+		{
+		iLogicalChannelRequest = aTicket;
+
+		TLogicalChannelRecord rec = aTicket.GetLogicalChannel();
+		
+		// we take this "out" of the logical channel for performance reasons
+		// (the pending logical channel will then die at some point later)
+		iBearer = rec.iLogicalChannelSAP;
+		iBearer->SetNotify(this);
+		
+		// get the MTU now
+		ObtainMTU();
+
+		// decide on our address (we may have been passive)
+		// to let clients know we signal all the Signal Receivers
+		TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	
+		while (iter)
+			{
+			iter++->SignallingChannelReady(*this);
+			}
+			
+		// migrate all the current listening sessions, to this new channel
+		// if their clients not happy they can detach and relisten for new connection
+		// just as if they got an inbound connection - which this is like
+		// whether it really is passive l2cap, or was initiated by any one session
+		
+		iProtocol.ConnectSignallingListeners(*this);
+		
+		// process any already received inbound data
+		if (rec.iDataCount)
+			{
+			NewData(rec.iDataCount);
+			}
+		if (rec.iEndOfData)
+			{
+			NewData(KNewDataEndofData);
+			Disconnect();
+			}
+		}
+	else
+		{
+		// to let clients know we signal all the Signal Receivers
+		TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	
+		while (iter)
+			{
+			iter++->SignallingChannelError(aError);
+			}
+		if (IsIdle())
+			{
+			IdledD();
+			}
+		}
+	}
+	
+TInt CSignallingChannel::AttachSignallingUser(XAvdtpSignalReceiver& aUser)
+	{
+	LOG_FUNC
+	// must check they're not already in the queue
+#ifdef _DEBUG
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	while (iter)
+		{
+		if (iter++ == &aUser)
+			{
+			Panic(EAvdtpBadSignallingUserQueue);
+			}
+		}
+#endif
+
+	TBool isFirstUser = iPermanentUsers.IsEmpty();
+	TInt ret = KErrNone;
+	
+	iPermanentUsers.AddFirst(aUser);
+	if (iBearer)
+		{
+		aUser.SignallingChannelReady(*this);
+		}
+	else if(isFirstUser)
+		{
+		// kick off the need for a signalling channel - we have a user
+		
+		// form a request
+		if (!IsListening())
+			{
+			TRAP(ret, iLogicalChannelRequest = iLogicalChannelFactory.CreateSignallingLogicalChannelL(iRemoteAddress, *this));
+			}
+		else
+			{
+			TRAP(ret, iLogicalChannelRequest = iLogicalChannelFactory.ExpectSignallingLogicalChannelL(*this));
+			}
+		}
+	
+	return ret;
+	}
+
+void CSignallingChannel::DetachSignallingUser(XAvdtpSignalReceiver& aUser)
+	{
+	LOG_FUNC
+	aUser.iSignalReceiverEmbeddedLink.Deque();
+	
+	// cleanup any requests they had outstanding
+	RemoveTransactions(aUser);
+
+	if (IsIdle())
+		{
+		if(!IsListening())
+			{
+			QueIdleTimer();
+			}
+		else
+			{
+			//listener just dies
+			IdledD();
+			}
+		}
+	}
+
+TBool CSignallingChannel::IsIdle() const
+	{
+	LOG_FUNC
+
+	// idle if permanent users empty, and transient users haven't got stuff queued
+	return (iPermanentUsers.IsEmpty() && iTransactions.IsEmpty());
+	}
+	
+void CSignallingChannel::QueIdleTimer()
+	{
+	LOG_FUNC
+	CancelIdleTimer();
+	iIdleTimerActive = ETrue;	
+	BTSocketTimer::Queue(KAvdtpSignallingChannelIdleTimeout, iIdleTimerEntry);
+	}
+	
+void CSignallingChannel::CancelIdleTimer()
+	{
+	LOG_FUNC
+	if(iIdleTimerActive)
+		{
+		// there's something to cancel
+		iIdleTimerActive = EFalse;
+		BTSocketTimer::Remove(iIdleTimerEntry);
+		}
+	}
+
+/*static*/ TInt CSignallingChannel::TryToClose(TAny* aSignallingChannel)
+	{
+	LOG_STATIC_FUNC
+	// check if still idle
+	CSignallingChannel* sigch = reinterpret_cast<CSignallingChannel*>(aSignallingChannel);
+	if (sigch->IsIdle())
+		{
+		sigch->IdledD();
+		}
+	return EFalse;
+	}
+
+void CSignallingChannel::IdledD()
+	{
+	LOG_FUNC
+	// we are till idle
+	__ASSERT_ALWAYS(iDraftMessages.IsEmpty(), Panic(EAvdtpSignallingChannelDyingWithDraftMessagesOnQueue));
+	__ASSERT_ALWAYS(iTransactions.IsEmpty(), Panic(EAvdtpSignallingChannelDyingWithTransactionsOnQueue));
+	__ASSERT_ALWAYS(iQueuedMessages.IsEmpty(), Panic(EAvdtpSignallingChannelDyingWithMessagesOnQueue));
+
+	delete this;
+	}
+	
+/*
+Remove transactions held by a user
+*/
+void CSignallingChannel::RemoveTransactions(XAvdtpSignalReceiver& aUser)
+	{
+	LOG_FUNC
+	TDblQueIter<CSignallingTransaction> iter(iTransactions);
+	while (iter)
+		{
+		CSignallingTransaction* transaction = iter++;
+		if (transaction->User() == &aUser)
+			{
+			transaction->iLink.Deque();
+			delete transaction;
+			
+			// outbound queue may now be empty
+			CheckOutboundQueue();			
+			}
+		}
+	}
+
+void CSignallingChannel::NewData(TUint aCount)
+	{
+	LOG_FUNC
+	// read out now (could make this async though)
+	// just give to inbound message
+	TInt res = iInboundMessage.NewData(aCount);
+	
+	if (res!=KErrNone)
+		{
+		// have to error this channel
+		Error(res);
+		}
+	}
+	
+
+/**
+Called by packet as it builds itself up - get stuff out of bearer now
+The service provided is always to fetch an MTU's worth
+*/
+TInt CSignallingChannel::GetData(RMBufChain& aData, TUint aOptions, TSockAddr* aAddr)
+	{
+	LOG_FUNC
+	return iBearer->GetData(aData,iBearerMTU,aOptions,aAddr);
+	}
+	
+
+/**
+Upcall from L2CAP - it is now ready to send
+*/	
+void CSignallingChannel::CanSend()
+	{
+	LOG_FUNC
+	SetBlocked(EFalse);
+	StartTryToSendCallback();
+	}
+	
+void CSignallingChannel::ConnectComplete()
+	{
+	LOG_FUNC
+	// the factory would have done this by now
+	}
+	
+void CSignallingChannel::ConnectComplete(const TDesC8& /*aConnectData*/)
+	{
+	LOG_FUNC
+	// the factory would have done this by now
+	}
+	
+void CSignallingChannel::ConnectComplete(CServProviderBase& /*aSSP*/)
+	{
+	LOG_FUNC
+	// the factory would have done this by now
+	}
+	
+void CSignallingChannel::ConnectComplete(CServProviderBase& /*aSSP*/,const TDesC8& /*aConnectData*/)
+	{
+	LOG_FUNC
+	// the factory would have done this by now
+	}
+	
+void CSignallingChannel::CanClose(TDelete /*aDelete*/)
+	{
+	LOG_FUNC
+	// only support immediate shutdown so shouldnt be called
+	}
+	
+void CSignallingChannel::CanClose(const TDesC8& /*aDisconnectData*/,TDelete aDelete)
+	{
+	LOG_FUNC
+	// l2cap shouldnt upcall this, but just in case
+	CanClose(aDelete);
+	}
+	
+void CSignallingChannel::Error(TInt aError,TUint /*aOperationMask*/)
+	{
+	LOG_FUNC
+	// from logical channel
+	ErrorPermanentUsers(aError);
+	ErrorServiceRequesters(aError);
+	delete this;
+	}
+	
+void CSignallingChannel::ErrorPermanentUsers(TInt aError)
+	{
+	LOG_FUNC
+	// error all users
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	while (iter)
+		{
+		iter++->SignallingChannelError(aError);
+		}
+	}
+
+void CSignallingChannel::ErrorServiceRequesters(TInt aError)
+	{
+	LOG_FUNC
+	// complete all outstanding services
+	TDblQueIter<CSignallingTransaction> iter(iTransactions);
+	while (iter)
+		{
+		CSignallingTransaction* transaction = iter++;
+
+		if (transaction->User())
+			{
+			// it was a command, tell the user it failed
+			// This will cause the transaction to be tidied
+			// up.
+			transaction->Error(aError);
+			}
+		else
+			{
+			// Just tidy up, there's no user to inform.
+			RemoveTransaction(*transaction);
+			}					
+		}
+	}
+	
+void CSignallingChannel::CancelTransactions(XAvdtpSignalReceiver& aUser)
+	{
+	LOG_FUNC
+	RemoveTransactions(aUser);
+	}
+	
+void CSignallingChannel::Disconnect()
+	{
+	LOG_FUNC
+	Error(KErrDisconnected);
+	}
+	
+void CSignallingChannel::Disconnect(TDesC8& /*aDisconnectData*/)
+	{
+	LOG_FUNC
+	// shouldnt be supported by l2cap, but just in case
+	Disconnect();
+	}
+	
+void CSignallingChannel::IoctlComplete(TDesC8* /*aBuf*/)
+	{
+	LOG_FUNC
+	// we don't issue ioctls - drop
+	}
+	
+void CSignallingChannel::NoBearer(const TDesC8& /*aConnectionInfo*/)
+	{
+	LOG_FUNC
+	// do nothing
+	}
+	
+void CSignallingChannel::Bearer(const TDesC8& /*aConnectionInfo*/)
+	{
+	LOG_FUNC
+	// do nothing	
+	}
+		
+/**
+Find a transaction given a transaction label - there shuold be one
+@param aLabel the transaction label in the packet for which a transaction is required
+@internalComponent
+*/
+CSignallingTransaction* CSignallingChannel::FindTransaction(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	TDblQueIter<CSignallingTransaction> iter(iTransactions);
+	while (iter)
+		{
+		CSignallingTransaction* t = iter;
+		if (t->Label() == aLabel)
+			{
+			return t;
+			}
+		iter++;
+		}
+	//__DEBUGGER();// FLOG
+	return NULL;
+	}
+
+/**
+Relinquish a transaction - may not be found if race with client cancelling
+@param aLabel the label of the transaction to relinquish
+@internalComponent
+**/	
+void CSignallingChannel::RemoveTransaction(CSignallingTransaction& aTransaction)
+	{
+	LOG_FUNC
+
+	// This will cancel the timer and remove the transaction from the queue
+	delete &aTransaction;
+
+	// outbound queue may now be empty
+	CheckOutboundQueue();			
+	
+	if (IsIdle())
+		{
+		QueIdleTimer();
+		}
+	}
+	
+void CSignallingChannel::DiscoverIndication(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	// create transaction ready for the response
+	CSignallingTransaction* transaction = PrepareSignallingResponse(EResponseAccept, EAvdtpDiscover, aLabel);
+	
+	if (transaction)
+		{
+		// go and ask sessions to contribute to packet
+		TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+		
+		while (iter)
+			{
+			// sessions MUST process this synchronously.
+			(void)(iter++)->DiscoverIndication(aLabel, transaction->Message());
+			}
+		
+		// ..as we now deem the packet constructed, and ready to send
+		(void)EnqueueMessage(*transaction);
+		// if Enque failed (it can't at present for Responses) remote would timeout
+		}
+	}
+	
+	
+
+void CSignallingChannel::DiscoverConfirm(TAvdtpTransactionLabel aLabel,
+										  TInt aResult,
+										  const TAvdtpInternalDiscoverConfirm* const aConfirm)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);	
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpDiscover);
+		
+	transaction->User()->DiscoverConfirm(aResult, aConfirm);
+	
+	RemoveTransaction(*transaction); //clears RTX timer
+	}
+
+void CSignallingChannel::GetCapsIndication(TAvdtpTransactionLabel aLabel, TSEID aSEID)
+	{
+	LOG_FUNC
+	// create transaction ready for the response
+	CSignallingTransaction* transaction = PrepareSignallingResponse(EResponseAccept, EAvdtpGetCapabilities, aLabel);
+	if (transaction)
+		{
+		// go and ask sessions to contribute to packet
+		TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+		TInt result = KErrNotFound;
+
+		while (iter)
+			{
+			// sessions MUST process this synchronously.
+			result = (iter++)->GetCapsIndication(aLabel, aSEID, transaction->Message());
+			if (result!=KErrNotFound)
+				{
+				// some error occured that meant we need not bother asking other sessions
+				break;
+				}
+			}
+	
+		// ..as we now deem the packet constructed, and ready to send
+		if (result==KErrNone)
+			{
+			(void)EnqueueMessage(*transaction);
+			// if Enque failed (it can't at present for Responses) remote would timeout
+			}
+		else
+			{
+			delete transaction;
+			
+			if (result==KErrNotFound)
+				{
+				SendReject(aLabel, EAvdtpGetCapabilities, EAvdtpBadACPSEID);
+				}
+			// else dump, and leave to time out				
+			}
+		}
+	else
+		{
+		// leave to timeout - no apt error
+		}
+	}
+
+void CSignallingChannel::GetCapsConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, const HBufC8* aCaps/*=NULL*/)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpGetCapabilities);
+	
+	TSEID seid(reinterpret_cast<TUint>(transaction->Cookie()));
+	if (aResult==KErrNone)
+		{
+		//Parse the SEID info, updating the protocol's sep cache and
+		//generating a descriptor to pass to the client.
+		
+		// tricky to get this to be efficient
+		// we just tell cache - it'll parse if it chooses to :o)
+		iProtocol.RemoteSEPCache().SetCapabilities(iRemoteAddress,
+												   seid,
+												   const_cast<HBufC8*>(aCaps));
+														   	
+			
+		// to make life for the user we tell the the categories we did see
+		// if they do want to investigate more they can begin a deep parse
+		TAvdtpServiceCategories  cats;
+		TRAPD(err, cats = iProtocol.RemoteSEPCache().GetCapabilitiesL(
+											iRemoteAddress,
+											seid));
+											
+		transaction->User()->GetCapsConfirm(err, seid,cats());
+		}
+	else
+		{
+		transaction->User()->GetCapsConfirm(aResult,seid, NULL);
+		}
+	RemoveTransaction(*transaction); //clears RTX timer
+	}
+
+
+void CSignallingChannel::SetConfigIndication(TAvdtpTransactionLabel aLabel,
+											  TSEID aACPSEID,
+											  TSEID aINTSEID,
+											  RBuf8& aConfigData)
+	{		
+	LOG_FUNC
+	// ownership of aConfigData transferred
+	// a consuming session will take owership
+	// if it is unclaimed we tidyup
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+	
+	while (iter)
+		{
+		result = (iter++)->SetConfigIndication(aLabel, aACPSEID, aINTSEID, aConfigData);
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}
+			
+	if (result!=KErrNone && result!=KErrNoMemory)
+		{
+		CHECK_ERROR(result);
+		TAvdtpSignallingErrorCode code = AvdtpInternalUtils::SymbianErrorToAvdtpError(result);
+		
+		// as per contract, the session has given extended info back to us
+		SendSetConfigurationReject(aLabel, code, static_cast<TAvdtpServiceCategory>(aConfigData[0]));
+		
+		aConfigData.Close();
+		}
+	else if (result == KErrNoMemory)
+		{
+		// if no memory then leave for remote to timeout
+		aConfigData.Close();
+		}
+	}
+		
+
+void CSignallingChannel::SetConfigConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, TAvdtpServiceCategory aErrorCategory)
+	{
+	LOG_FUNC
+	ConfigConfirm(aLabel, aResult, aErrorCategory, EFalse);
+	}
+
+
+void CSignallingChannel::GetConfigIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+	{	
+	LOG_FUNC
+	// create transaction ready for the response
+	CSignallingTransaction* transaction = PrepareSignallingResponse(EResponseAccept, EAvdtpGetConfiguration, aLabel);
+	
+	if(transaction)
+		{
+		// go and ask sessions to contribute to packet
+		TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+		TInt result = KErrNotFound;
+
+		while (iter)
+			{
+			// sessions MUST process this synchronously.
+			result = (iter++)->GetConfigIndication(aLabel, aACPSEID, transaction->Message());
+			if (result!=KErrNotFound)
+				{
+				break;
+				}
+			}
+		
+		// ..as we now deem the packet constructed, and ready to send
+		if (result==KErrNone)
+			{
+			(void)EnqueueMessage(*transaction);
+			// leave remote to timeout
+			}
+		else if (result!=KErrNoMemory)
+			{
+			delete transaction;
+			SendReject(aLabel, EAvdtpGetConfiguration, AvdtpInternalUtils::SymbianErrorToAvdtpError(result));
+			}
+		// else leave to timeout, no suitable response to send
+		}
+	// else leave to timeout, no suitable response to send
+	}
+
+
+void CSignallingChannel::GetConfigConfirm(TAvdtpTransactionLabel /*aLabel*/, TInt /*aResult*/)
+	{
+	LOG_FUNC
+	// shouldnt get one of these as we wont send GetConf yet
+	// drop
+	}
+
+
+void CSignallingChannel::ReconfigIndication(TAvdtpTransactionLabel aLabel,
+										TSEID aACPSEID,
+										 RBuf8& aConfigData)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+		
+	while (iter)
+		{
+		result = (iter++)->ReconfigIndication(aLabel, aACPSEID, aConfigData);
+		if (result==KErrNone)
+			{
+			break;
+			}
+		}
+	
+	if (result!=KErrNone && result!=KErrNoMemory)
+		{
+		CHECK_ERROR(result);
+	
+		TAvdtpSignallingErrorCode code = AvdtpInternalUtils::SymbianErrorToAvdtpError(result);
+		// as per contract, the session has given extended info back to us
+		SendReconfigureReject(aLabel, code, static_cast<TAvdtpServiceCategory>(aConfigData[0]));
+		
+		aConfigData.Close();
+		}
+	else if (result != KErrNone)
+		{
+		// clean up the config data if we failed - it hasn't been passed on
+		aConfigData.Close();
+		}
+	// else leave remote to timeout
+	}
+
+void CSignallingChannel::ReconfigConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, TAvdtpServiceCategory aErrorCategory)
+	{
+	LOG_FUNC
+	ConfigConfirm(aLabel, aResult, aErrorCategory, ETrue);
+	}
+
+TInt CSignallingChannel::SendOpenStream(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	TInt result = KErrNoMemory;
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpOpen);
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageOpen::Command::Format(transaction->Message(), aACPSEID);
+		if (result==KErrNone)
+			{
+			transaction->SetCookie(reinterpret_cast<TAny*>(aACPSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+	return result;
+	}
+	
+void CSignallingChannel::OpenIndication(TAvdtpTransactionLabel aLabel, TSEID aSEID)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+		
+	while (iter)
+		{
+		result = (iter++)->OpenIndication(aSEID); 
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}	
+	
+	if (result==KErrNone)
+		{
+		result = SendAccept(aLabel, EAvdtpOpen);
+		}
+	else if (result!=KErrNone && result!=KErrNoMemory)
+		{
+		SendReject(aLabel, EAvdtpOpen, AvdtpInternalUtils::SymbianErrorToAvdtpError(result));
+		}
+
+	if (result==KErrNone)
+		{
+		// now we are happy to pre-authorise remote for more incoming logical channels
+		iProtocol.SetPreauthorisation(iRemoteAddress, ETrue);
+		}
+//#pragma message("would be nice to error session that consumed")
+	}
+
+
+void CSignallingChannel::OpenConfirm(TAvdtpTransactionLabel aLabel, TInt aResult)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpOpen);
+			
+	transaction->User()->OpenConfirm(aResult, TSEID(reinterpret_cast<TUint>(transaction->Cookie())));
+	RemoveTransaction(*transaction); //clears RTX timer
+	}
+
+
+void CSignallingChannel::StartIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+	
+	while (iter)
+		{
+		result = (iter++)->StartIndication(aLabel, aACPSEID);
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}
+
+	if (result != KErrNone && result!=KErrNoMemory)
+		{
+		CHECK_ERROR(result);		
+		
+		// this one has to error slightly differently - we tell remote of the first bad SEID
+		// which would be this one.
+		TPckg<TUint8> seidPckg(aACPSEID.PacketValue());
+		SendReject(aLabel, EAvdtpStart, AvdtpInternalUtils::SymbianErrorToAvdtpError(result), &seidPckg);
+		}
+	//else leave remote to timeout
+	}
+
+void CSignallingChannel::StartConfirm(TAvdtpTransactionLabel aLabel, TInt aResult)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpStart);
+	
+	transaction->User()->StartConfirm(aResult, TSEID(reinterpret_cast<TUint>(transaction->Cookie())));
+	RemoveTransaction(*transaction); //clears RTX timer
+	}
+
+void CSignallingChannel::SuspendConfirm(TAvdtpTransactionLabel aLabel, TInt aResult)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpSuspend);
+		
+	transaction->User()->SuspendConfirm(aResult, TSEID(reinterpret_cast<TUint>(transaction->Cookie())));
+	RemoveTransaction(*transaction); //clears RTX timer
+	}
+
+
+void CSignallingChannel::ReleaseIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+	
+	while (iter)
+		{
+		result = (iter++)->ReleaseIndication(aLabel, aACPSEID);
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}
+
+	// session must send accept otherwise we may send OK after it has released transport channels	
+	if (result!=KErrNone && result!=KErrNoMemory)
+		{
+		result = SendReject(aLabel, EAvdtpRelease, AvdtpInternalUtils::SymbianErrorToAvdtpError(result));
+		}
+	// else leave remote to timeout
+	if (result!=KErrNone)
+		{
+//	#pragma message("would be nice to just error the session that consumed")
+//			iSignallingChannelError(err);
+		}
+	}
+
+void CSignallingChannel::ReleaseConfirm(TAvdtpTransactionLabel aLabel, TInt aResult)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpRelease);
+	
+	// We take the details we need and remove transaction before
+	// passing the signal on for processing as ReleaseConfirm may
+	// lead to the stream, and all its transactions, being 
+	// destroyed.
+	XAvdtpSignalReceiver* user = transaction->User();
+	TSEID seid(reinterpret_cast<TUint>(transaction->Cookie()));
+	RemoveTransaction(*transaction); //clears RTX timer
+
+	if (user)
+		{
+		// it was an "normal" Release - forward confirm
+		user->ReleaseConfirm(aResult, seid);
+		}
+	}
+
+
+void CSignallingChannel::SuspendIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+	
+	while (iter)
+		{
+		result = (iter++)->SuspendIndication(aLabel, aACPSEID);
+		/* if we've found and suspended we don't need to go round again
+		   if we've run out of memory or anything then...
+		*/
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}
+
+	/* if we've not broken out then we will come out with notfound
+	   which is a bad sepid */
+	if (result!=KErrNone && result!=KErrNoMemory)
+		{
+		CHECK_ERROR(result);		
+		
+		// this one has to error slightly differently - we tell remote of the first bad SEID
+		// which would be this one.
+		TPckg<TUint8> seidPckg(aACPSEID.PacketValue());
+		SendReject(aLabel, EAvdtpSuspend, AvdtpInternalUtils::SymbianErrorToAvdtpError(result), &seidPckg);
+		}
+	// else leave remote to timeout
+	}
+
+
+void CSignallingChannel::AbortIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+	
+	while (iter)
+		{
+		result = (iter++)->AbortIndication(aLabel, aACPSEID);
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}
+		
+	if (result == KErrNone)
+		{
+		(void)SendAccept(aLabel, EAvdtpAbort);
+		}
+	// else no error path for Abort. Just ignore.			
+	}
+
+void CSignallingChannel::AbortConfirm(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpAbort);
+
+	// We take the details we need and remove transaction before
+	// passing the signal on for processing as AbortConfirm may
+	// lead to the stream, and all its transactions, being 
+	// destroyed.
+	XAvdtpSignalReceiver* user = transaction->User();
+	TSEID seid(reinterpret_cast<TUint>(transaction->Cookie()));
+	RemoveTransaction(*transaction); //clears RTX timer
+
+	if (user)
+		{
+		// it was an "immediate" Abort - noone wants confirm
+		user->AbortConfirm(seid);
+		}
+	}
+
+
+void CSignallingChannel::SecurityControlIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID, const HBufC8* aSecurityData)
+	{
+	LOG_FUNC
+	TDblQueIter<XAvdtpSignalReceiver> iter(iPermanentUsers);
+	TInt result = KErrNotFound;
+	
+	while (iter)
+		{
+		result = (iter++)->SecurityControlIndication(aLabel, aACPSEID, aSecurityData);
+		if (result!=KErrNotFound)
+			{
+			break;
+			}
+		}
+
+	if (result!=KErrNone && result!=KErrNoMemory)
+		{
+		CHECK_ERROR(result);		
+		
+		// destroy HBuf
+		delete (const_cast<HBufC8*>(aSecurityData));
+		SendReject(aLabel, EAvdtpSecurityControl, AvdtpInternalUtils::SymbianErrorToAvdtpError(result));
+		}
+	// else ownership of HBufC8 transferred
+	}
+
+void CSignallingChannel::SecurityControlConfirm(TAvdtpTransactionLabel aLabel, TInt aResult, const TDesC8& aResponseData)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);	
+	RETURN_IF_SIGNAL_BAD(transaction, EAvdtpSecurityControl);
+
+	transaction->User()->SecurityControlConfirm(aResult, TSEID(reinterpret_cast<TUint>(transaction->Cookie())), aResponseData);
+	RemoveTransaction(*transaction); //clears RTX timer
+	}
+
+
+/**
+Send primitives
+**/
+
+
+TInt CSignallingChannel::SendDiscoverSEPs(XAvdtpSignalReceiver& aReceiver)
+	{
+	LOG_FUNC
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+		
+	CSignallingTransaction*	transaction = PrepareSignallingCommand(aReceiver, EAvdtpDiscover);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result=EnqueueMessage(*transaction);
+		}
+	if (result!=KErrNone)
+		{
+		delete transaction;
+		}
+		
+	return result;
+	}
+	
+TInt CSignallingChannel::SendGetCapabilities(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	if (!aACPSEID.IsValid() || aACPSEID.IsLocal())
+		{
+		return KErrArgument;
+		}
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpGetCapabilities);
+	TInt result = KErrNoMemory;
+
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageGetCapabilities::Command::Format(transaction->Message(), aACPSEID);
+		if (result==KErrNone)
+			{
+			//Stuff the seid in the CSignallingTransaction as AVDTP spec forgets it
+			transaction->SetCookie(reinterpret_cast<TAny*>(aACPSEID.Value()));			
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+	return result;
+	}
+	
+TInt CSignallingChannel::SendReleaseAccept(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+    // want to turn this around asap to avoid remote hanging, and races with local l2cap shutting down
+    // so one-shot bump the priority
+
+ 	if(!iTryToSendCallback->IsActive())
+ 	    {
+		iTryToSendCallback->SetPriority(KAvdtpReleaseAcceptPriority);	
+    	}
+    else if(iTryToSendCallback->Priority()!=KAvdtpReleaseAcceptPriority)
+   		{
+   		//Callback is active trying to send a low priority item
+   		//Cancel it and set the priority to high. The priority will remain high until the
+   		//callback has run enough times to empty the message queue.
+   		iTryToSendCallback->Cancel();
+    	iTryToSendCallback->SetPriority(KAvdtpReleaseAcceptPriority);
+    	}
+    //Else, do nothing. The priority will remain high until the message queue has been
+    //cleared, so the EAvdtpRelease about to be added should be sent whilst the priority
+    //is still high
+    	
+    return SendAccept(aLabel, EAvdtpRelease);
+	}
+	
+	
+TInt CSignallingChannel::SendSetConfigurationAccept(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	return SendAccept(aLabel, EAvdtpSetConfiguration);
+	}
+									  
+TInt CSignallingChannel::SendSetConfigurationReject(TAvdtpTransactionLabel aLabel,
+											TBluetoothAvDistributionError aResult,
+									  		TAvdtpServiceCategory aCategory)
+	{
+	LOG_FUNC
+	// packet size of errored category is 8bits
+	TPckg<TUint8> cat(static_cast<TUint8>(aCategory));
+	return SendReject(aLabel, EAvdtpSetConfiguration, aResult, &cat);
+	}
+
+TInt CSignallingChannel::SendReconfigureAccept(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	return SendAccept(aLabel, EAvdtpReconfigure);
+	}
+	
+TInt CSignallingChannel::SendReconfigureReject(TAvdtpTransactionLabel aLabel,
+											TBluetoothAvDistributionError aResult,
+									  		TAvdtpServiceCategory aCategory)
+	{
+	LOG_FUNC
+	// packet size of errored category is 8bits
+	TPckg<TUint8> cat(static_cast<TUint8>(aCategory));
+	return SendReject(aLabel, EAvdtpReconfigure, aResult, &cat);
+	}
+
+TInt CSignallingChannel::SendSecurityControlAccept(TAvdtpTransactionLabel aLabel, const TDesC8* aOptionalData)
+	{
+	LOG_FUNC
+	return SendAccept(aLabel, EAvdtpSecurityControl, aOptionalData);	
+	}
+	
+TInt CSignallingChannel::SendSecurityControlReject(TAvdtpTransactionLabel aLabel, TBluetoothAvDistributionError aResult)
+	{
+	LOG_FUNC
+	return SendReject(aLabel, EAvdtpSecurityControl, aResult, NULL);
+	}
+	
+TInt CSignallingChannel::SendRelease(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	if (!aACPSEID.IsValid())
+		{
+		return KErrArgument;
+		}
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	// create transaction
+	TInt result = KErrNoMemory;
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpRelease);
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageStreamRelease::Command::Format(transaction->Message(), aACPSEID);
+		if (result==KErrNone)
+			{
+			transaction->SetCookie(reinterpret_cast<TAny*>(aACPSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+			
+	// create packet
+	return result;	
+	}
+	
+TInt CSignallingChannel::SendSetConfiguration(XAvdtpSignalReceiver& aReceiver,
+										  TSEID aINTSEID,
+										  TSEID aACPSEID,
+										  const RBuf8& aConfiguration)
+	{
+	LOG_FUNC
+	if (!aACPSEID.IsValid() || !aINTSEID.IsValid())
+		{
+		return KErrArgument;
+		}
+
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	// create transaction
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpSetConfiguration);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageSetConfiguration::Command::Format(transaction->Message(), aACPSEID, aINTSEID, aConfiguration);
+		if (result==KErrNone)
+			{
+			transaction->SetCookie(reinterpret_cast<TAny*>(aACPSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+			
+	// create packet
+	return result;	
+	}
+
+
+TInt CSignallingChannel::SendReconfigure(XAvdtpSignalReceiver& aReceiver,
+										  TSEID aACPSEID,
+										  const RBuf8& aConfiguration)
+	{
+	LOG_FUNC
+	if (!aACPSEID.IsValid())
+		{
+		return KErrArgument;
+		}
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	// create transaction
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpReconfigure);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageReconfigure::Command::Format(transaction->Message(), aACPSEID, aConfiguration);
+		
+		if (result==KErrNone)
+			{
+			transaction->SetCookie(reinterpret_cast<TAny*>(aACPSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+			
+	// create packet
+	return result;	
+	}
+
+
+TInt CSignallingChannel::SendStartStream(XAvdtpSignalReceiver& aReceiver, TSEID aRemoteSEID)
+	{
+	LOG_FUNC
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	// create transaction
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpStart);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageStart::Command::Format(transaction->Message(), aRemoteSEID);
+		if (result==KErrNone)
+			{
+			transaction->SetCookie(reinterpret_cast<TAny*>(aRemoteSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+			
+	// create packet
+	return result;	
+	}
+
+
+TInt CSignallingChannel::SendSuspendStream(XAvdtpSignalReceiver& aReceiver, TSEID aACPSEID)
+	{
+	LOG_FUNC
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	// create transaction
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpSuspend);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result=AvdtpSignallingMessageSuspend::Command::Format(transaction->Message(), aACPSEID);
+		if (result==KErrNone)
+			{
+			transaction->SetCookie(reinterpret_cast<TAny*>(aACPSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+			
+	// create packet
+	return result;	
+	}
+		
+
+
+TInt CSignallingChannel::SendAbort(XAvdtpSignalReceiver& aReceiver, TSEID aRemoteSEID)
+	{
+	LOG_FUNC
+	if (!aRemoteSEID.IsValid())
+		{
+		return KErrArgument;
+		}
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	CSignallingTransaction*	transaction = PrepareSignallingCommand(aReceiver, EAvdtpAbort);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageAbort::Command::Format(transaction->Message(), aRemoteSEID);
+		if (result==KErrNone)
+			{
+			//Stuff the seid in the CSignallingTransaction as AVDTP forgets it
+			transaction->SetCookie(reinterpret_cast<TAny*>(aRemoteSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+	return result;
+	}
+	
+
+TInt CSignallingChannel::SendSecurityControl(XAvdtpSignalReceiver& aReceiver, 
+									    TSEID aRemoteSEID,
+									    const TDesC8& aSecurityData)
+	{
+	LOG_FUNC
+	if (!aRemoteSEID.IsValid())
+		{
+		return KErrArgument;
+		}
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+
+	CSignallingTransaction* transaction = PrepareSignallingCommand(aReceiver, EAvdtpSecurityControl);
+	TInt result = KErrNoMemory;
+	
+	if (transaction)
+		{
+		result = AvdtpSignallingMessageSecurityControl::Command::Format(transaction->Message(), aRemoteSEID, aSecurityData);
+			
+		if (result==KErrNone)
+			{
+			//Stuff the seid in the CSignallingTransaction as AVDTP spec forgets it
+			transaction->SetCookie(reinterpret_cast<TAny*>(aRemoteSEID.Value()));
+			result=EnqueueMessage(*transaction);
+			}
+		if (result!=KErrNone)
+			{
+			delete transaction;
+			}
+		}
+		
+	return result;
+	}
+	
+	
+TInt CSignallingChannel::SendStartAccept(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	return SendAccept(aLabel, EAvdtpStart);
+	}
+	
+TInt CSignallingChannel::SendStartReject(TAvdtpTransactionLabel aLabel,
+											TBluetoothAvDistributionError aResult,
+											TSEID aBadSEID)
+	{
+	LOG_FUNC
+	TPckg<TUint8> badSEID(aBadSEID.PacketValue());
+	return SendReject(aLabel, EAvdtpStart, aResult, &badSEID);
+	}
+	
+TInt CSignallingChannel::SendSuspendAccept(TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	return SendAccept(aLabel, EAvdtpSuspend);
+	}
+
+TInt CSignallingChannel::SendSuspendReject(TAvdtpTransactionLabel aLabel,
+											TBluetoothAvDistributionError aResult,
+											TSEID aBadSEID)
+	{
+	LOG_FUNC
+	TPckg<TUint8> badSEID(aBadSEID.PacketValue());
+	return SendReject(aLabel, EAvdtpSuspend, aResult, &badSEID);
+	}
+	
+/**
+Places a message (defined by the transaction) into the outbound queue
+At this point the transaction label for commands is determined
+Certain commands (such as Abort) may be placed at the head of the queue - it is this function that decides
+If a packet is added to the queue, and the bearer is not blocked, then async send callback is kicked
+@internalComponent
+**/
+TInt CSignallingChannel::EnqueueMessage(CSignallingTransaction& aTransaction)
+	{
+	LOG_FUNC
+	// from transaction get the message
+	CAvdtpOutboundSignallingMessage& message = aTransaction.Message();
+	
+	TInt result=KErrNone;
+
+	//OutBound Signalling message should never be EReserved
+	__ASSERT_DEBUG(message.iSignal!= EReserved,Panic(EAvdtpInvalidReservedValueInOutboundSignallingMessage));
+	if (message.iMessageType==ECommand)
+		{
+		result = message.AllocateTransactionLabel(iLabelGen);
+		LOG1(_L("Allocated label %d"), message.TransactionLabel());
+		}
+	
+	// remove from draft que, whether error occurred or not
+	message.Deque(); 					
+	
+	if (result==KErrNone)
+		{
+		// remember the packet label in the transaction object
+		aTransaction.SetLabel(message.TransactionLabel());
+		// ok to send, figure out priority		
+		if (aTransaction.Signal()==EAvdtpAbort)
+			{
+			// add to outbound queue (high priority)
+			iQueuedMessages.AddFirst(message);
+			}
+		else
+			{
+			// add to outbound queue	
+			iQueuedMessages.AddLast(message);
+			}
+		// kick off sending
+		if (!Blocked())
+			{
+			StartTryToSendCallback();
+			}	
+		}
+	
+	return result;	
+	}
+
+/**
+Creates a reponse packet
+@param aMessageType whether accept or reject
+@param aMessage the signalling response to be put in the packet
+@param aLabel the transaction label - typically that used in the inbound command
+@internalComponent
+**/
+CSignallingTransaction* CSignallingChannel::PrepareSignallingResponse(
+												TAvdtpMessageType aMessageType,
+												TAvdtpMessage aMessage,
+												TAvdtpTransactionLabel aLabel)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = PrepareSignallingPacket(aMessageType, aMessage);
+	if (transaction)
+		{		
+		transaction->Message().SetTransactionLabel(aLabel);
+		}
+	return transaction;
+	}
+
+/**
+Creates a command packet and returns a transaction to the caller
+@param aReceiver a reference to the caller - used for determining who sent the packet
+@param aMessage the signalling command to be put in the packet
+@internalComponent
+**/
+CSignallingTransaction* CSignallingChannel::PrepareSignallingCommand(
+												XAvdtpSignalReceiver& aReceiver,
+												TAvdtpMessage aMessage)
+	{
+	LOG_FUNC
+	CSignallingTransaction* transaction = PrepareSignallingPacket(ECommand, aMessage);
+	if (transaction)
+		{
+		transaction->SetUser(&aReceiver);
+		}
+	return transaction;
+	}
+
+
+/*
+common private method
+ownership not returned - transaction remains in signalling channel transaction queue
+@internalComponent
+*/
+CSignallingTransaction* CSignallingChannel::PrepareSignallingPacket(TAvdtpMessageType aMessageType,
+													TAvdtpMessage aMessage)
+	{
+	LOG_FUNC
+	//todo: KErrInUse if SAP already preparing a message?
+	CSignallingTransaction* transaction = CSignallingTransaction::New(*this,
+												aMessage,
+												aMessageType);
+	
+	if (transaction)
+		{
+		// until the packet is finalised, set to be on draft message queue
+		iDraftMessages.AddLast(transaction->Message());
+		iTransactions.AddLast(*transaction);
+	
+		// see what post-send action is required (timer etc - see GAVDP spec)
+		transaction->SetSentAction();
+		}
+	return transaction;
+	}
+
+/*
+Helper that factors similarity between SetConfiguration and Reconfigure confirms
+@param aCategory this may be meaningless if aResult==KErrNone
+@internalComponent
+*/
+void CSignallingChannel::ConfigConfirm(TAvdtpTransactionLabel aLabel,
+											  TInt aResult,
+											  TAvdtpServiceCategory aCategory,
+											  TBool aReconfigure)
+	{	
+	LOG_FUNC
+	CSignallingTransaction* transaction = FindTransaction(aLabel);
+	RETURN_IF_NO_TRANSACTION(transaction);
+	RETURN_IF_SIGNAL_BAD(transaction, aReconfigure ? EAvdtpReconfigure : EAvdtpSetConfiguration);
+	
+	// get acp seid from cookie
+	TSEID seid(reinterpret_cast<TUint>(transaction->Cookie()));
+	
+	if (!aReconfigure)
+		{
+		transaction->User()->SetConfigConfirm(aResult, seid, aCategory);
+   		// return label back to pool
+   		// for error the setconfigconfirm will destroy the stream which in turn clears the transaction already
+   		// don't want to try a double clean up - it doesn't work well :-)
+ 		// It is possible that SetConfigConfirm was an error and causes stream release
+ 		// which deletes all the streams transactions - including the one we
+ 		// just found. To guard against that check it exists (again)
+ 		transaction = FindTransaction(aLabel);
+ 		if ((transaction) && (aResult == KErrNone))
+			{
+			RemoveTransaction(*transaction); //clears RTX timer
+			}
+		}
+	else
+		{
+		transaction->User()->ReconfigConfirm(aResult, seid, aCategory);
+		// return label back to pool
+		RemoveTransaction(*transaction); //clears RTX timer
+		}	
+	}
+
+
+/**
+Sends a rejection response
+The response can be to any of the signalling messages.
+@param aError The error code to place in the packet
+@param aRejectionData Trailing extended error information
+@internalComponent
+*/
+TInt CSignallingChannel::SendReject(TAvdtpTransactionLabel aLabel,
+									TAvdtpMessage aMessage,
+									TBluetoothAvDistributionError aError,
+									const TDesC8* aRejectionData)
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iBearer, Panic(EAvdtpSignallingChannelLogicalChannelNotReady));	
+	__ASSERT_DEBUG(!(aMessage==EAvdtpDiscover && aError==EAvdtpBadACPSEID), Panic(EAvdtpBadErrorCase));
+	
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+	
+	CSignallingTransaction* transaction = NULL;
+	TInt result = KErrNone;
+	
+	//If its a valid signal identifier then send the 'Reject Response' otherwise send 'General Reject' 
+	if (aMessage < EAvdtpLargestValidSignalIndentifier)
+		{
+		transaction = PrepareSignallingResponse(EResponseReject, aMessage, aLabel);	
+		// now need to append more data for certain packets													 
+		switch (aMessage)
+			{
+			// those that just have error code
+			case EAvdtpDiscover:
+			case EAvdtpGetCapabilities:
+			case EAvdtpGetConfiguration:
+			case EAvdtpOpen:
+			case EAvdtpRelease:
+			case EAvdtpSecurityControl:
+				{
+				__ASSERT_DEBUG(aRejectionData == NULL, Panic(EAvdtpSignallingMessageResponseNoTrailingDataExpected));
+				result = transaction ? AvdtpSignallingMessage::Reject::Format(transaction->Message(), aError) : KErrNoMemory;
+				}
+			break;
+			
+			// those with extra rejection info
+			case EAvdtpSetConfiguration:
+			case EAvdtpReconfigure:
+			case EAvdtpSuspend:
+			case EAvdtpStart:
+				{
+				__ASSERT_DEBUG(aRejectionData != NULL, Panic(EAvdtpSignallingMessageResponseTrailingDataExpected));
+				// need to append data to the packet (SEID etc)
+				result = transaction ? AvdtpSignallingMessage::Reject::Format(transaction->Message(), aError, aRejectionData) : KErrNoMemory;
+				}
+			break;
+			default:
+				break;			// unsupported, just leave to time out
+			}
+		}
+	else
+		{
+		__ASSERT_DEBUG(aRejectionData == NULL, Panic(EAvdtpSignallingMessageResponseNoTrailingDataExpected));
+		//For General Reject send the invalid signal identifier which is causing this general reject	
+		transaction = PrepareSignallingResponse(EGeneralReject, aMessage, aLabel);
+		}
+
+	if (!transaction)
+		{
+		result = KErrNoMemory;
+		}
+
+	if (result==KErrNone)
+		{
+		(void)EnqueueMessage(*transaction);
+		}
+	else
+		{
+		delete transaction;
+		}
+	return result;
+	}
+
+TInt CSignallingChannel::SendAccept(TAvdtpTransactionLabel aLabel, TAvdtpMessage aMessage, const TDesC8* aOptionalData /*= NULL*/)
+	{
+	LOG_FUNC
+	if (!iBearer)
+		{
+		return KErrNotReady;
+		}
+	
+	TInt result = KErrNone;
+	CSignallingTransaction*	transaction = PrepareSignallingResponse(EResponseAccept, aMessage, aLabel);
+	if (transaction)
+		{
+		if (aOptionalData)
+			{
+			// no other messages have data in accept in avdtp 1.0
+			__ASSERT_DEBUG(aMessage==EAvdtpSecurityControl, Panic(EAvdtpSignallingMessageResponseNoTrailingDataExpected));
+			result = AvdtpSignallingMessageSecurityControl::Accept::Format(transaction->Message(), aOptionalData);
+			}
+		}
+	else
+		{
+		result = KErrNoMemory;
+		}
+	
+	if (result == KErrNone)
+		{
+		result=EnqueueMessage(*transaction);
+		}
+	else
+		{
+		delete transaction;
+		}
+		
+	return result;	
+	}
+
+TBool CSignallingChannel::CheckSignal(const CSignallingTransaction& aTransaction, TAvdtpMessage aSignal) const
+	{
+	LOG_FUNC
+	return aTransaction.Signal() == aSignal;
+	}
+
+