bluetooth/btstack/avdtp/avdtpStreamStates.cpp
changeset 0 29b1cd4cb562
child 8 2b6718f05bdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avdtp/avdtpStreamStates.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1422 @@
+// 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 stream statemachine
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include "avdtpStream.h"
+#include "avdtp.h"
+#include "avdtpSignallingChannel.h"
+#include "avdtpSignallingSession.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVDTP);
+#endif
+
+#ifdef _DEBUG
+#define DEBUGPANICINSTATE(aPanic) PanicInState(aPanic)
+#else
+#define DEBUGPANICINSTATE(aPanic)
+#endif
+
+// state ctors
+
+TAVStreamState::TAVStreamState(CAVStreamStateFactory& aFactory)
+: iFactory(aFactory)
+	{
+	STATENAME("BASE");
+	}
+
+TAVStreamStateIdle::TAVStreamStateIdle(CAVStreamStateFactory& aFactory)
+: TAVStreamState(aFactory)
+	{
+	STATENAME("Idle");
+	}
+	
+TAVStreamStateOpen::TAVStreamStateOpen(CAVStreamStateFactory& aFactory)
+: TAVStreamStateIdle(aFactory)
+	{
+	STATENAME("Open");
+	}
+
+TAVStreamStateReady::TAVStreamStateReady(CAVStreamStateFactory& aFactory)
+: TAVStreamStateOpen(aFactory)
+	{
+	STATENAME("Ready");
+	}
+
+TAVStreamStateWaitForSessions::TAVStreamStateWaitForSessions(CAVStreamStateFactory& aFactory)
+: TAVStreamStateIdle(aFactory)
+	{
+	STATENAME("WaitForSessions");
+	}
+
+TAVStreamStateWaitForSessionsStartReceived::TAVStreamStateWaitForSessionsStartReceived(CAVStreamStateFactory& aFactory)
+: TAVStreamStateWaitForSessions(aFactory)
+	{
+	STATENAME("WaitForSessionsStartReceived");
+	}
+
+TAVStreamStateConfiguring::TAVStreamStateConfiguring(CAVStreamStateFactory& aFactory)
+: TAVStreamStateIdle(aFactory)
+	{
+	STATENAME("Configuring");
+	}
+
+TAVStreamStateConfigured::TAVStreamStateConfigured(CAVStreamStateFactory& aFactory)
+: TAVStreamStateIdle(aFactory)
+	{
+	STATENAME("**Abstract** Configure");
+	}
+	
+TAVStreamStateINTConfigured::TAVStreamStateINTConfigured(CAVStreamStateFactory& aFactory)
+: TAVStreamStateConfigured(aFactory)
+	{
+	STATENAME("INTConfigured");
+	}
+	
+TAVStreamStateACPConfigured::TAVStreamStateACPConfigured(CAVStreamStateFactory& aFactory)
+: TAVStreamStateConfigured(aFactory)
+	{
+	STATENAME("ACPConfigured");
+	}	
+
+TAVStreamStateOpening::TAVStreamStateOpening(CAVStreamStateFactory& aFactory)
+: TAVStreamStateIdle(aFactory)
+	{
+	STATENAME("Opening");
+	}
+
+TAVStreamStateCreatingLogicalChannels::TAVStreamStateCreatingLogicalChannels(CAVStreamStateFactory& aFactory)
+: TAVStreamStateOpen(aFactory)
+	{
+	STATENAME("CreatingLogicalChannels");
+	}
+
+TAVStreamStateReleasing::TAVStreamStateReleasing(CAVStreamStateFactory& aFactory)
+: TAVStreamStateReady(aFactory)
+	{
+	STATENAME("Releasing");
+	}
+
+TAVStreamStateAborting::TAVStreamStateAborting(CAVStreamStateFactory& aFactory)
+: TAVStreamStateReady(aFactory)
+	{
+	STATENAME("Aborting");
+	}
+
+TAVStreamStateStreaming::TAVStreamStateStreaming(CAVStreamStateFactory& aFactory)
+: TAVStreamStateReady(aFactory)
+	{
+	STATENAME("Streaming");
+	}
+
+TAVStreamStateStarting::TAVStreamStateStarting(CAVStreamStateFactory& aFactory)
+: TAVStreamStateReady(aFactory)
+	{
+	STATENAME("Starting");
+	}
+
+TAVStreamStateSuspending::TAVStreamStateSuspending(CAVStreamStateFactory& aFactory)
+: TAVStreamStateReady(aFactory)
+	{
+	STATENAME("Suspending");
+	}
+
+TAVStreamStateWaitingForLogicalChannels::TAVStreamStateWaitingForLogicalChannels(CAVStreamStateFactory& aFactory)
+: TAVStreamStateOpen(aFactory)
+	{
+	STATENAME("WaitingForLogicalChannels");
+	}
+
+TAVStreamStateReconfiguring::TAVStreamStateReconfiguring(CAVStreamStateFactory& aFactory)
+: TAVStreamStateReady(aFactory)
+	{
+	STATENAME("Reconfiguring");
+	}
+
+
+// default state actions
+
+void TAVStreamState::Enter(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// do nothing by default
+	}
+	
+void TAVStreamState::Exit(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// do nothing by default
+	}
+	
+void TAVStreamState::Release(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	// it already has been Released
+	aStream.Released();
+	}
+
+void TAVStreamState::AwaitLogicalChannelsL(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedAwaitLogicalChannelsEvent);
+	}
+
+void TAVStreamState::LogicalChannelsAvailable(CAVStream& /*aStream*/, TLogicalChannelFactoryTicket /*aTicket*/, TInt /*aError*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedLogicalChannelsAvailableEvent);
+	}
+
+void TAVStreamState::WatchdogFired(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedWatchdogFiredEvent);
+	}
+
+void TAVStreamState::Configured(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedConfiguredEvent);
+	}
+
+void TAVStreamState::SetConfigurationL(CAVStream& /*aStream*/, 
+										RBuf8& /*aPacketBuffer*/, CSignallingChannel& /*aSignallingChannel*/,
+										TBool /*aReportingConfigured*/,
+								  		TBool /*aRecoveryConfigured*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedSetConfigurationEvent);
+	User::Leave(KErrNotReady);
+	}
+
+void TAVStreamState::SetConfigConfirm(CAVStream& /*aStream*/, TInt /*aResult*/, 
+									TSEID /*aRemoteSEID*/, TAvdtpServiceCategory /*aFailedCategory*/) const
+	{
+	// throw away
+	}
+
+void TAVStreamState::ReconfigConfirm(CAVStream& /*aStream*/, TInt /*aResult*/, 
+									TSEID /*aRemoteSEID*/, TAvdtpServiceCategory /*aFailedCategory*/) const
+	{
+	LOG_FUNC
+	// throw away
+	}
+		
+void TAVStreamState::StartConfirm(CAVStream& /*aStream*/, TInt /*aResult*/, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	// throw away
+	}
+		
+void TAVStreamState::AbortConfirm(CAVStream& /*aStream*/, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	// throw away
+	}
+	
+void TAVStreamState::OpenConfirm(CAVStream& /*aStream*/, TInt /*aResult*/, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	// default, throw away weirdo response from remote
+	}
+
+void TAVStreamState::ReleaseConfirm(CAVStream& /*aStream*/, TInt /*aResult*/, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	// throw away
+	}
+
+void TAVStreamState::SuspendConfirm(CAVStream& /*aStream*/, TInt /*aResult*/, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	// throw away
+	}	
+	
+TInt TAVStreamState::AddSession(CAVStream& /*aStream*/, 
+							TAvdtpTransportSessionType /*aType*/,
+							CUserPlaneTransportSession& /*aSession*/,
+							CTransportChannel*& /*aTransportChannel*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedAddSessionEvent);
+	return KErrNotReady;
+	}
+								
+void TAVStreamState::DropSession(CAVStream& /*aStream*/, TAvdtpTransportSessionType /*aType*/,
+							 CUserPlaneTransportSession& /*aSession*/) const
+	{
+	LOG_FUNC
+	DEBUGPANICINSTATE(EAvdtpUnexpectedDropSession);
+	}
+
+TInt TAVStreamState::StartReceived(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+
+TBool TAVStreamState::IsStreaming(const CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return EFalse;
+	}
+
+TInt TAVStreamState::Start(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+	
+TInt TAVStreamState::Suspend(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+
+void TAVStreamState::Started(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// signalling session should have sanity checked with previous StartReceived()
+	DEBUGPANICINSTATE(EAvdtpUnexpectedStartedEvent);
+	}
+	
+void TAVStreamState::Suspended(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// signalling session should have sanity checked with previous IsStreaming
+	DEBUGPANICINSTATE(EAvdtpUnexpectedSuspendedEvent);
+	}
+
+void TAVStreamState::ChangeState(CAVStream& aContext, CAVStreamStateFactory::TAVStreamStates aState) const
+	{
+	LOG_FUNC
+	aContext.iState->Exit(aContext);
+
+#ifdef __FLOG_ACTIVE
+	const TAVStreamState* const newState=&iFactory.GetState(aState);
+	LOG2(_L("Stream: State %S -> %S"), &aContext.iState->iName, &newState->iName);
+#endif //__FLOG_ACTIVE
+
+	aContext.iState=&iFactory.GetState(aState);
+	aContext.iState->Enter(aContext);
+	}
+
+void TAVStreamState::PanicInState(TAvdtpPanic aPanic) const
+	{
+	Panic(aPanic, iFactory.StateIndex(this));
+	}
+
+
+// derived states and state changes
+
+void TAVStreamStateIdle::Configured(CAVStream& aStream) const
+	{
+	// ah - going ACP
+	ChangeState(aStream, CAVStreamStateFactory::EStreamStateACPConfigured);
+	}
+	
+void TAVStreamStateIdle::SetConfigurationL(CAVStream& aStream, 
+											RBuf8& aPacketBuffer,
+											CSignallingChannel& aSignallingChannel,
+										  	TBool aReportingConfigured,
+								  			TBool aRecoveryConfigured) const
+	{
+	LOG_FUNC
+// An INT procedure to add in extra options the stack wishes to do, regardless of client
+// At present this is limited to mux&frag - which we do if local and remote have
+// the *capability* to do so, even if the proposed *configuration* doesnt mention it
+	
+// AVDTP is daft, so have to arrange for IDs before objects exist if muxing used
+
+// we also need to base this on the number of sessions we know we're going to run	
+// see 8.19.8
+// 5.4.6 allow fors no reporting session so it's not *obvious* when the 2nd element is
+// bit like not obvious what the 2nd L2cap channel will bear
+
+// further, if we're muxing, we need to see what optional sessions are proposed
+// in the configuration to see what to configure in the mux capability
+	
+	TBool canMux;
+	TBool canFrag;
+	aStream.CanMuxFrag(canMux, canFrag);
+
+	TInt err = KErrNone;
+	
+	if (canMux)
+		{
+		// muxing is awkward - must identify the TCs and TSs that are going to be used NOW
+		TAvdtpMultiplexingCapability* mux = aStream.CreateMuxCapabilityL(aReportingConfigured, aRecoveryConfigured, aSignallingChannel);
+
+		// ok to create packetstructure - only exchange IDs if do mux
+		err = mux->AsProtocol(aPacketBuffer);
+		}
+		
+	if (!err)
+		{
+		// First check that we are in a state to send a set configuration command as
+		// we don't want to send one unless we can commit the pending configuration
+		err = aStream.iLocalSEP->CheckConfigurationState(EFalse);
+ 
+ 		if (!err)
+			{
+			err = aSignallingChannel.SendSetConfiguration(aStream, 
+								aStream.LocalSEID(), aStream.RemoteSEID(), aPacketBuffer);
+			if (!err)
+				{
+				// tell SEP
+				err = aStream.iLocalSEP->SetPendingConfiguration(aPacketBuffer, EFalse); //takes ownership of RBuf
+			
+				// we should not get an error here as we called CheckConfigurationState above
+				__ASSERT_DEBUG(!err, PanicInState(EAvdtpInconsistentPendingConfigurationState));
+
+				if (!err)
+					{
+					aPacketBuffer.Assign(NULL); // since ownership transfer succeeded
+					ChangeState(aStream, CAVStreamStateFactory::EStreamStateConfiguring);
+					}
+				}
+			}
+		}
+
+	if (err)
+		{
+		// clean up and don't bother proceeding
+		aStream.DeallocateUnclaimedTransportSessionIDs();
+		User::Leave(err);
+		}
+	}
+
+void TAVStreamStateIdle::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+		
+
+void TAVStreamStateConfiguring::SetConfigConfirm(CAVStream& aStream, TInt aResult, 
+												TSEID /*aRemoteSEID*/, TAvdtpServiceCategory aFailedCategory) const
+	{
+	LOG_FUNC
+	//update our state before telling others
+	TRAPD(res, aStream.iLocalSEP->CommitPendingConfigurationL(aResult==KErrNone, EFalse));
+	
+	if (res!=KErrNone)
+		{
+		aResult = res;
+		}
+		
+	if (aResult==KErrNone)
+		{
+		TBool rp = aStream.CheckConfigured(EServiceCategoryReporting);
+		TBool rc = aStream.CheckConfigured(EServiceCategoryRecovery);
+		aStream.iNumSessionsRequired = AvdtpInternalUtils::NumberOfTransportObjects(rp, rc);
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateINTConfigured);			
+		}
+
+	aStream.iStreamNotify.StreamConfigured(aStream.LocalSEID(), aResult, aFailedCategory);
+
+	if (aResult!=KErrNone)
+		{
+		// remove the stream as the configure failed the stream is invalid
+		aStream.Released();	// deletes stream
+		}
+	}
+
+void TAVStreamStateConfiguring::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateConfigured::Release(CAVStream& aStream) const
+	{
+	// in this state to Release a stream object (cos it errored say)
+	// needs us to send an Abort rather than a Close to remote
+	// this is because the remote will need to mark its SEP as not in use,
+	// but we haven't yet sent an Open.
+	LOG_FUNC
+	CSignallingChannel* sigch = aStream.iProtocol.FindSignallingChannel(aStream.iRemoteAddress.BTAddr());
+	
+	if (sigch)
+		{
+		TInt err = sigch->SendAbort(aStream, aStream.RemoteSEID());
+		if (err==KErrNone)
+			{
+			ChangeState(aStream, CAVStreamStateFactory::EStreamStateAborting);
+			}
+		else
+			{
+			// just have to die
+			aStream.Released();
+			}
+		}	
+	}
+
+void TAVStreamStateConfigured::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+/**
+An INT primitive
+A session is adding itself to the stream.
+Record its details and find a channel for it to use.
+Record the binding between session and channel.
+Once all the required sessions are added the stream tries to open the remote
+*/
+TInt TAVStreamStateINTConfigured::AddSession(CAVStream& aStream,
+									TAvdtpTransportSessionType aType,
+						   			CUserPlaneTransportSession& aSession,
+						   			CTransportChannel*& aChannel) const
+	{
+	LOG_FUNC
+	TInt ret = KErrNone;
+	// check GAVDP isn't being naughty and asking for an unconfigured session
+	if ((aType==EReporting && !aStream.CheckConfigured(EServiceCategoryReporting))
+		|| (aType==ERecovery && !aStream.CheckConfigured(EServiceCategoryRecovery)))
+		{
+		// gavdp is trying to use a session it has never configured
+		ret = KErrNotSupported;
+		}
+	
+	if (ret == KErrNone)
+		{
+		TBool useMux;
+		TBool useFrag;	//ignored
+		aStream.CanMuxFrag(useMux, useFrag);
+		
+		aChannel = aStream.iProtocol.GetTransportChannel(aStream.iRemoteAddress, useMux);
+		
+		if (aChannel)
+			{
+			// bind session to channel
+			ret = aChannel->AttachTransportSession(aSession, aType);
+			if (ret==KErrNone)
+				{
+				// keep a copy of this binding
+				TTransportBinding binding;
+				binding.iSession = &aSession;
+				binding.iChannel = aChannel;
+				
+				// keep object bindings
+				TTransportBinding* b = NULL;
+				
+				switch (aType)
+					{
+					case EMedia:
+						b = &aStream.iMediaBinding;
+						break;
+					case EReporting:
+						b = &aStream.iReportingBinding;
+						break;
+					case ERecovery:
+						b = &aStream.iRecoveryBinding;
+						break;
+					}
+		
+				__ASSERT_DEBUG(b, PanicInState(EAvdtpBadSessionAttachingToStream));
+				// remember binding
+				*b = binding;
+				}
+			TryToOpen(aStream);
+			}
+		else
+			{
+			ret = KErrNotReady; // TC went down...
+			}
+		}
+	return ret;
+	}
+
+/**
+One of the sessions in the stream is dropping from the stream.
+At this point the stream hadn't been opened, so don't Release stream
+Just cancel oustanding logical channel factory request
+*/	
+void TAVStreamStateINTConfigured::DropSession(CAVStream& aStream, TAvdtpTransportSessionType /*aType*/, CUserPlaneTransportSession& /*aSession*/) const
+	{
+	LOG_FUNC
+	aStream.iProtocol.LogicalChannelFactory().Cancel(aStream.iFactoryJob);
+	}
+
+void TAVStreamStateINTConfigured::TryToOpen(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	// check how many sessions we think we need
+	// if all have added to us then we find signalling ch and issue an open
+	
+	TInt numSessionsBound = (aStream.iMediaBinding.iSession ?1:0) +
+							(aStream.iReportingBinding.iSession ?1:0) +
+							(aStream.iRecoveryBinding.iSession ?1:0);
+
+
+	__ASSERT_DEBUG(numSessionsBound>=1 && numSessionsBound<=3, PanicInState(EAVDTPBadSessionCount));
+	if (numSessionsBound == aStream.iNumSessionsRequired)
+		{
+		// GO!
+		CSignallingChannel* sigch = aStream.iProtocol.FindSignallingChannel(aStream.DeviceAddress());
+		TInt err = sigch ? sigch->SendOpenStream(aStream, aStream.RemoteSEID()) : KErrNotReady;
+		if (err==KErrNone)
+			{
+			// all sessions joined - so Open
+			ChangeState(aStream, CAVStreamStateFactory::EStreamStateOpening);
+			}
+		else
+			{
+			aStream.NotifyUserPlaneTransportSessionsError(NULL, err);
+			// no need to release stream - leave gavdp client to decide
+			}
+		}
+	}
+
+void TAVStreamStateINTConfigured::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateINTConfigured::SetConfigurationL(CAVStream& /*aStream*/, 
+									RBuf8& /*aPacketBuffer*/,
+									CSignallingChannel& /*aSignallingChannel*/,
+									TBool /*aReportingConfigured*/,
+									TBool /*aRecoveryConfigured*/) const
+	{
+	// GAVDP spec v1.1 sect4.1.5 forbids this - must be at OPEN state before reconfiguring
+	// in our implementation this means we need to be in Ready state (thus have transport channels)
+	// yes it is weird...
+	User::Leave(KErrAvdtpInvalidStateForReconfigure);
+	}
+
+/**
+ACP configured, now need to await the Open
+*/
+	
+void TAVStreamStateACPConfigured::AwaitLogicalChannelsL(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	const TBool requireReporting = aStream.CheckConfigured(EServiceCategoryReporting);
+	const TBool requireRecovery = aStream.CheckConfigured(EServiceCategoryRecovery);
+	
+	TAvdtpMultiplexingCapability* const muxCap = static_cast<TAvdtpMultiplexingCapability*>
+										(aStream.iLocalSEP->Configuration()[EServiceCategoryMultiplexing]);
+	
+	if (muxCap)
+		{
+		TAvdtpMultiplexingCapabilityHelper helper(*muxCap, requireReporting, requireRecovery);
+		DoAwaitMuxedChannelsL(aStream, helper, requireReporting, requireRecovery);
+		}
+	else
+		{
+		DoAwaitDirectChannelsL(aStream, requireReporting, requireRecovery);
+		}
+	}
+	
+	
+void TAVStreamStateACPConfigured::DoAwaitMuxedChannelsL(CAVStream& aStream,
+												TAvdtpMultiplexingCapabilityHelper& aHelper,
+												TBool aRequireReporting,
+												TBool aRequireRecovery) const
+	{
+	LOG_FUNC
+	TInt numExtraLogicalChannelsNeeded=0;
+	TAvdtpSockAddr address = aStream.iRemoteAddress;
+	// get TCIDs for the sessions in the mux record
+	// this will indicate the TCIDs that the INT has proposed
+	
+	// we look for mux channels with any TCIDs proposed
+	// and reduce thus reduce the number of TCs we expect
+	CTransportChannel** tcPtr = &aStream.iMediaBinding.iChannel;
+	
+	*tcPtr = aStream.iProtocol.FindMuxChannel(aHelper.MediaCID());
+	if (!*tcPtr)
+		{
+		address.SetSession(EMedia);	
+		*tcPtr = aStream.iProtocol.GetTransportChannel(address, ETrue, aHelper.MediaCID());
+		User::LeaveIfNull(*tcPtr);
+		numExtraLogicalChannelsNeeded++;
+		}
+
+	tcPtr = &aStream.iReportingBinding.iChannel;
+	if (aRequireReporting)
+		{
+		__ASSERT_DEBUG(aHelper.ReportingCID() != KInvalidTCID, PanicInState(EAVDTPBadMuxConfiguration));
+		*tcPtr = aStream.iProtocol.FindMuxChannel(aHelper.ReportingCID());
+		if (!*tcPtr)
+			{
+			// might need a new channel
+			if (aHelper.ReportingCID()!=aHelper.MediaCID())
+				{
+				address.SetSession(EReporting);	
+				*tcPtr = aStream.iProtocol.GetTransportChannel(address, ETrue, aHelper.ReportingCID());
+				User::LeaveIfNull(*tcPtr);
+				numExtraLogicalChannelsNeeded++;
+				}
+			// else remote has proposed putting reporting in same channel as media
+			}
+		}
+			
+	tcPtr = &aStream.iRecoveryBinding.iChannel;
+	if (aRequireRecovery)
+		{
+		__ASSERT_DEBUG(aHelper.RecoveryCID() != KInvalidTCID, PanicInState(EAVDTPBadMuxConfiguration));
+		*tcPtr = aStream.iProtocol.FindMuxChannel(aHelper.RecoveryCID());
+		if (!*tcPtr)
+			{
+			// might need a new channel
+			if (aHelper.RecoveryCID()!=aHelper.MediaCID() && aHelper.RecoveryCID()!=aHelper.ReportingCID())
+				{
+				address.SetSession(ERecovery);	
+				*tcPtr = aStream.iProtocol.GetTransportChannel(address, ETrue, aHelper.RecoveryCID());
+				User::LeaveIfNull(*tcPtr);
+				numExtraLogicalChannelsNeeded++;
+				}
+			else if (aHelper.RecoveryCID()==aHelper.MediaCID())
+				{
+				__DEBUGGER();
+				User::Leave(KErrCorrupt); // remote has contravened spec
+				}
+			}
+		}
+
+	if (!numExtraLogicalChannelsNeeded)
+		{
+		// everything we need is already here, kick state machine and wait for sessions to attach
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateWaitForSessions);
+		// tell signalling session
+		aStream.iStreamNotify.StreamAccepted(aStream.LocalSEID(),
+												aStream.RemoteSEID(), aRequireReporting, aRequireRecovery);
+		}
+	else
+		{
+		// TCs were created above, now wait for appropriate logical channels	
+		aStream.iFactoryJob = aStream.iProtocol.LogicalChannelFactory().
+												ExpectSessionLogicalChannelsL(aStream,
+												numExtraLogicalChannelsNeeded);
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateWaitingForLogicalChannels);
+		}
+	}
+	
+	
+void TAVStreamStateACPConfigured::DoAwaitDirectChannelsL(CAVStream& aStream,
+												TBool aRequireReporting,
+												TBool aRequireRecovery) const
+	{
+	LOG_FUNC
+	// create the necessary Transport Channels ready for the logical channels
+	// assume all inbound TCs are mux -our seps always do muxing, and allows for "upgrades"
+	// if others SEPs want to add sessions to them later
+	
+	TInt numExtraLogicalChannelsNeeded = 0;
+	TAvdtpSockAddr address = aStream.iRemoteAddress;
+	address.SetSession(EMedia);	
+
+#ifdef __SYMBIAN_AVDTP_HIDE_MUX 
+    #define CAN_BECOME_MUX EFalse
+#else
+#pragma message("Not sure if this true - remember morgan, cannot upgrade as dont know which "direct" channel has which TCID")
+    #define CAN_BECOME_MUX ETrue
+#endif   
+
+	aStream.iMediaBinding.iChannel = aStream.iProtocol.GetTransportChannel(address, CAN_BECOME_MUX);
+	User::LeaveIfNull(aStream.iMediaBinding.iChannel);
+	numExtraLogicalChannelsNeeded++;
+
+	if (aRequireReporting)
+		{
+		address.SetSession(EReporting);	
+		aStream.iReportingBinding.iChannel = aStream.iProtocol.GetTransportChannel(address, CAN_BECOME_MUX);
+		User::LeaveIfNull(aStream.iReportingBinding.iChannel);
+		numExtraLogicalChannelsNeeded++;
+		}
+	
+	if (aRequireRecovery)
+		{
+		address.SetSession(ERecovery);	
+		aStream.iRecoveryBinding.iChannel = aStream.iProtocol.GetTransportChannel(address, CAN_BECOME_MUX);
+		User::LeaveIfNull(aStream.iRecoveryBinding.iChannel);
+		numExtraLogicalChannelsNeeded++;
+		}
+
+  	LOG1(_L8("Awaiting %d logical channels"), numExtraLogicalChannelsNeeded);
+  
+	// wait for appropriate logical channels	
+	aStream.iFactoryJob = aStream.iProtocol.LogicalChannelFactory().
+												ExpectSessionLogicalChannelsL(aStream,
+												numExtraLogicalChannelsNeeded);
+
+	ChangeState(aStream, CAVStreamStateFactory::EStreamStateWaitingForLogicalChannels);
+	}
+	
+TInt TAVStreamStateACPConfigured::AddSession(CAVStream& /*aStream*/, 
+							TAvdtpTransportSessionType /*aType*/,
+							CUserPlaneTransportSession& /*aSession*/,
+							CTransportChannel*& /*aTransportChannel*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+
+void TAVStreamStateACPConfigured::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+
+void TAVStreamStateOpen::DropSession(CAVStream& aStream, TAvdtpTransportSessionType /*aType*/, CUserPlaneTransportSession& /*aSession*/) const
+	{	
+	LOG_FUNC
+	// if any session in the stream is shutdown
+	// we invalidate the stream, and thus send a Release
+			
+	// we leave the GC to actually shutdown the session saps
+	DoRelease(aStream);	
+	// leave unbinding transport objects until ReleaseConfirm	
+	}
+
+void TAVStreamStateOpen::Release(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	// we need to Release this as the object is going
+	DoRelease(aStream);
+	}
+
+void TAVStreamStateOpen::DoRelease(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	CSignallingChannel* sigch = aStream.iProtocol.FindSignallingChannel(aStream.iRemoteAddress.BTAddr());
+	
+	if (sigch)
+		{
+		sigch->SendRelease(aStream, aStream.RemoteSEID());
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateReleasing);
+		}
+	}
+
+void TAVStreamStateOpen::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+TInt TAVStreamStateReady::AddSession(CAVStream& /*aStream*/, 
+		TAvdtpTransportSessionType /*aType*/,
+		CUserPlaneTransportSession& /*aSession*/,
+		CTransportChannel*& /*aTransportChannel*/) const
+{
+LOG_FUNC
+#ifdef _DEBUG
+return KErrPanicAvdtpOpenInBadState;
+#else
+return KErrNotReady;
+#endif
+}
+
+void TAVStreamStateReady::SetConfigurationL(CAVStream& aStream, 
+									RBuf8& aPacketBuffer,
+									CSignallingChannel& aSignallingChannel,
+									TBool __DEBUG_ONLY(aReportingConfigured),
+									TBool __DEBUG_ONLY(aRecoveryConfigured)) const
+	{
+	// this is a Reconfigure - see GAVDP spec
+	LOG_FUNC
+	__ASSERT_DEBUG(!aReportingConfigured && !aRecoveryConfigured, PanicInState(EAvdtpReconfigurationCapabilitiesNotChecked));
+
+	// First check that we are in a state to send a reconfigure command as
+	// we don't want to send one unless we can commit the pending configuration
+	TInt err = aStream.iLocalSEP->CheckConfigurationState(ETrue);
+	
+	if (!err)
+		{
+		err = aSignallingChannel.SendReconfigure(aStream, aStream.RemoteSEID(), aPacketBuffer);
+		
+		if (!err)
+			{
+			// tell SEP
+			err = aStream.iLocalSEP->SetPendingConfiguration(aPacketBuffer, ETrue); //takes ownership of RBuf
+
+			// we should not get an error here as we called CheckConfigurationState above
+			__ASSERT_DEBUG(!err, PanicInState(EAvdtpInconsistentPendingReconfigurationState));
+
+			if (!err)
+				{
+				aPacketBuffer.Assign(NULL); // since ownership transfer succeeded
+				// release configuration buffer as we own it in this state
+				ChangeState(aStream, CAVStreamStateFactory::EStreamStateReconfiguring);
+				}
+			}
+		}
+		
+	User::LeaveIfError(err);
+	}
+
+/**
+ * Before the OpenStream returns, gavdp might get Cancel()ed. At this point we have an outstanding
+ * request on the signalling channel. We can't issue a cancel on the individual request, and we
+ * can't close sigch down as it's shared, but there should only be one outstanding for this stream,
+ * so we can cancel all transactions for it.
+ */
+void TAVStreamStateOpening::DropSession(CAVStream& aStream, TAvdtpTransportSessionType /*aType*/,
+		 CUserPlaneTransportSession& /*aSession*/) const
+	{
+		LOG_FUNC
+		CSignallingChannel* sigch = aStream.iProtocol.FindSignallingChannel(aStream.DeviceAddress());
+		__ASSERT_DEBUG(sigch, PanicInState(EAvdtpSignallingChannelShouldExist));
+		sigch->CancelTransactions(aStream);
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateIdle);
+	}
+
+void TAVStreamStateOpening::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateOpening::OpenConfirm(CAVStream& aStream, TInt aResult, TSEID __DEBUG_ONLY(aRemoteSEID)) const
+	{
+	LOG_FUNC
+	// good!
+	__ASSERT_DEBUG(aRemoteSEID == aStream.RemoteSEID(), PanicInState(EAvdtpConfirmAddressedToWrongRequester));
+	TInt ret = KErrNone;
+	
+// now we kick TCs into life
+	if (aResult)
+		{
+		// can return to Idle, user could try this operation again
+		// the way Open works means we have transport sessions interested in result of this
+		// they need to tell their sockets that their connects failed
+		
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateIdle);
+		
+		// no need to tell signalling session as Opening is not available to RGavdp
+		// Opening is performed when the necessary sockets are created and connected in a stream
+		aStream.NotifyUserPlaneTransportSessionsError(NULL, aResult);
+		}
+	else
+		{
+		// create a job - see what logical channels need creating
+		TInt numLogicalChannelsRequired =
+				aStream.iMediaBinding.iChannel->IsConnected() ? 0 : 1;
+		
+		if (aStream.iReportingBinding.iChannel)
+			{
+			// a reporting transport channel is required - but is it available?
+			if (!aStream.iReportingBinding.iChannel->IsConnected())
+				{
+				// this is required, so add into job
+				numLogicalChannelsRequired++;
+				}
+			}
+			
+		if (aStream.iRecoveryBinding.iChannel)
+			{
+			// a recovery transport channel is required - but is it available?
+			if (!aStream.iRecoveryBinding.iChannel->IsConnected())
+				{
+				// this is required, so add into job
+				numLogicalChannelsRequired++;
+				}
+			}
+		
+		if (numLogicalChannelsRequired)
+			{
+			// if either required, kick off request...
+			ChangeState(aStream, CAVStreamStateFactory::EStreamStateCreatingLogicalChannels);
+			TLogicalChannelFactoryTicket ticket;
+			TRAP(ret, ticket=aStream.iProtocol.LogicalChannelFactory().CreateSessionLogicalChannelsL(
+												aStream.iRemoteAddress.BTAddr(),
+										  		aStream, numLogicalChannelsRequired));
+			if (ret==KErrNone)
+				{
+				aStream.iFactoryJob = ticket; // record this, so we can cancel if needed
+				}
+			else
+				{
+				// stay in same state
+				ChangeState(aStream, CAVStreamStateFactory::EStreamStateOpening);
+				}
+			}		
+		else
+			{
+			ChangeState(aStream, CAVStreamStateFactory::EStreamStateOpen);
+			// all TCs appear to be available without creating new ones
+			aStream.TransportChannelsReady();
+			}
+		}
+	}
+
+
+TInt TAVStreamStateReady::StartReceived(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	
+	aStream.ReadyForStartIndication();
+	
+	return KErrNone;
+	}
+
+TInt TAVStreamStateReady::Start(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	TInt retVal = KErrNone;
+	CSignallingChannel* sigch = aStream.iProtocol.FindSignallingChannel(aStream.iRemoteAddress.BTAddr());
+		
+	// should always have sigch here - hence function signature
+	__ASSERT_DEBUG(sigch, PanicInState(EAvdtpSignallingChannelShouldExist));
+	if (sigch)
+		{
+		retVal = sigch->SendStartStream(aStream, aStream.RemoteSEID());
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateStarting);
+		}
+	return retVal;
+	}
+
+void TAVStreamStateReady::Started(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	ChangeState(aStream, CAVStreamStateFactory::EStreamStateStreaming);
+	}
+	
+void TAVStreamStateReady::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateStarting::Enter(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	// Tell the physical link that encryption keys could be refreshed now, to prevent an auto refresh later
+	aStream.TryToAndThenPreventHostEncryptionKeyRefresh();
+	}
+
+
+void TAVStreamStateStarting::StartConfirm(CAVStream& aStream, TInt aResult, TSEID /*aRemoteSEID*/) const
+	{
+	LOG_FUNC
+	// just change state
+	if (aResult==KErrNone)
+		{
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateStreaming);
+		aStream.iStreamNotify.StreamStarted(aStream.LocalSEID());
+		}
+	else
+		{
+		// whether suspended or idle, we return to ready 
+		// but first release the prevent encryption key refresh token
+		aStream.AllowHostEncryptionKeyRefresh();
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateReady);
+		aStream.iStreamNotify.StreamInitiatedServiceFailed(aStream, aResult);		
+		}
+	}
+	
+TInt TAVStreamStateStarting::StartReceived(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+
+	// we need to tell the other end 'nope we're busy' because the starts 'crossed in the post'
+	// returning KErrInUse will tell the other end to go away (politely of course)
+	return KErrInUse;
+	}
+
+
+void TAVStreamStateReleasing::Release(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// we are already releasing so do nothing.
+	}
+	
+void TAVStreamStateReleasing::ReleaseConfirm(CAVStream& aStream, TInt /*aResult*/, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	// ignore error - proceed anyway
+	aStream.Released();
+	}
+	
+void TAVStreamStateReleasing::DropSession(CAVStream& /*aStream*/, TAvdtpTransportSessionType /*aType*/, CUserPlaneTransportSession& /*aSession*/) const
+	{
+	LOG_FUNC
+	// to guard against sending multiple Releases per dropped session
+	// since we're releasing, we don't need to send a Release, but we just consume
+	}
+	
+void TAVStreamStateReleasing::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+	
+
+void TAVStreamStateAborting::AbortConfirm(CAVStream& aStream, TSEID /*aSEID*/) const
+	{
+	LOG_FUNC
+	aStream.Released();
+	}
+
+void TAVStreamStateAborting::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+	
+
+void TAVStreamStateAborting::Release(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// we are already releasing so do nothing.
+	}
+		
+
+void TAVStreamStateCreatingLogicalChannels::LogicalChannelsAvailable(CAVStream& aStream, TLogicalChannelFactoryTicket aTicket, TInt aError) const
+	{
+	LOG_FUNC
+	aStream.iFactoryJob = aTicket;
+	aStream.BindLogicalAndTransportChannels(aTicket, aError);
+			
+	if (aError==KErrNone)
+		{
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateReady);
+		// tell sessions...
+		aStream.TransportChannelsReady();		
+		}
+	else
+		{
+		aStream.iStreamNotify.StreamInitiatedServiceFailed(aStream, aError);
+		}
+	}
+	
+
+void TAVStreamStateCreatingLogicalChannels::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateWaitingForLogicalChannels::Enter(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	
+	// start guard timer in case logical channels never arrive for TCs
+	aStream.StartWatchdog();
+	}
+
+void TAVStreamStateWaitingForLogicalChannels::LogicalChannelsAvailable(CAVStream& aStream, TLogicalChannelFactoryTicket aResponse, TInt aError) const
+	{
+	LOG_FUNC
+	// we created the transport channels in :Await, so now we can bind
+	// then the sessions can call :AddSession and scoop up the TCs
+	aStream.iFactoryJob = aResponse;
+	aStream.BindLogicalAndTransportChannels(aResponse, aError);
+
+	if (aError==KErrNone)
+		{	
+		const TBool reportingPresent = aStream.iReportingBinding.iChannel ? ETrue : EFalse;
+		const TBool recoveryPresent = aStream.iRecoveryBinding.iChannel ? ETrue : EFalse;
+
+		aStream.iNumSessionsRequired = AvdtpInternalUtils::NumberOfTransportObjects(reportingPresent, recoveryPresent);
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateWaitForSessions);
+		// tell signalling session		
+		aStream.iStreamNotify.StreamAccepted(aStream.LocalSEID(),
+												aStream.RemoteSEID(), reportingPresent, recoveryPresent);
+		}
+	else
+		{
+		aStream.iStreamNotify.StreamInitiatedServiceFailed(aStream, aError);
+		}
+	}
+
+void TAVStreamStateWaitingForLogicalChannels::DropSession(CAVStream& aStream, TAvdtpTransportSessionType /*aType*/,
+		 CUserPlaneTransportSession& /*aSession*/) const
+	{
+		LOG_FUNC
+		aStream.iProtocol.LogicalChannelFactory().Cancel(aStream.iFactoryJob);
+	}
+
+void TAVStreamStateWaitingForLogicalChannels::Exit(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	// start guard timer in case logical channels never arrive for TCs
+	aStream.StopWatchdog();
+	}
+
+void TAVStreamStateWaitingForLogicalChannels::WatchdogFired(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	// need to tidy TCs, and Abort stream and cancel job
+	TLogicalChannelFactoryTicket nullTicket;
+	
+	aStream.BindLogicalAndTransportChannels(nullTicket, KErrTimedOut);
+	
+	aStream.iStreamNotify.StreamInitiatedServiceFailed(aStream, KErrTimedOut);
+	}
+
+
+/**
+An ACP primitive: the TCs & LCs are ready, now we are awaiting the sessions
+to come in and connect to the TCs.  The sessions do so at the behest of GAVDP
+*/
+TInt TAVStreamStateWaitForSessions::AddSession(CAVStream& aStream,
+									TAvdtpTransportSessionType aType,
+						   			CUserPlaneTransportSession& aSession,
+						   			CTransportChannel*& aChannel) const
+	{
+	LOG_FUNC
+	TInt ret = KErrNone;
+
+	// bind session to channel - the channel is there, we'd have been told if it had gone
+	TTransportBinding* b = NULL;
+	
+	switch (aType)
+		{
+		case EMedia:
+			b = &aStream.iMediaBinding;
+			break;
+		case EReporting:
+			// check GAVDP isn't being naughty and asking for an unconfigured session
+			if (aStream.CheckConfigured(EServiceCategoryReporting))
+				{
+				b = &aStream.iReportingBinding;
+				}
+			else
+				{
+				// GAVDP asking for a bearer that is not configured
+				ret = KErrNotSupported;
+				}
+			break;
+		case ERecovery:
+			// check GAVDP isn't being naughty and asking for an unconfigured session
+			if (aStream.CheckConfigured(EServiceCategoryRecovery))
+				{
+				b = &aStream.iRecoveryBinding;
+				}
+			else
+				{
+				// GAVDP asking for a bearer that is not configured
+				ret = KErrNotSupported;
+				}
+			break;
+		default:
+			PanicInState(EAvdtpBadSessionAttachingToStream);
+		}
+	
+	if (ret == KErrNone)
+		{
+		ret = b->iChannel->AttachTransportSession(aSession, aType);
+		if (ret==KErrNone)
+			{
+			// stream needs to remember binding
+			b->iSession = &aSession;
+			// and session need to know channel
+			aChannel = b->iChannel;
+			// check if all sessions have bound
+			if (!--aStream.iNumSessionsRequired)
+				{
+				ChangeState(aStream, CAVStreamStateFactory::EStreamStateReady);
+				aStream.TransportChannelsReady();
+				}
+			}
+		}
+	return ret;
+	}	
+
+TInt TAVStreamStateWaitForSessions::StartReceived(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	ChangeState(aStream, CAVStreamStateFactory::EStreamStateWaitForSessionsStartReceived);
+	return KErrNone;	
+	}	
+
+void TAVStreamStateWaitForSessions::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+/**
+Overrides the method in TAVStreamStateWaitForSessions. The start has already been received by
+CSignallingSession::StartIndication, so after changing the state to EStreamStateReady data
+stored in the CAVStream object will be used to pass a start indication to GAVDP.
+*/
+TInt TAVStreamStateWaitForSessionsStartReceived::AddSession(CAVStream& aStream,
+												TAvdtpTransportSessionType aType,
+						   						CUserPlaneTransportSession& aSession,
+						   						CTransportChannel*& aChannel) const
+	{
+	LOG_FUNC
+	// Call the function from the parent class to bind the session
+	TInt ret = TAVStreamStateWaitForSessions::AddSession(aStream,aType,aSession,aChannel);
+	
+	// if that worked, and all the channels are bound, we can now issue the delayed start
+	if((ret == KErrNone) && (!aStream.iNumSessionsRequired))
+		{
+		aStream.ReadyForStartIndication();
+		}
+
+	return ret;
+	}
+	
+TInt TAVStreamStateWaitForSessionsStartReceived::StartReceived(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}	
+
+void TAVStreamStateWaitForSessionsStartReceived::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateSuspending::SuspendConfirm(CAVStream& aStream, TInt aResult, TSEID /*aRemoteSEID*/) const
+	{
+	LOG_FUNC
+	// just change state
+	if (aResult==KErrNone)
+		{
+		// no difference between a "suspended" state, and ready
+		// making them the same helps support reconfig in more states
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateReady);
+		aStream.iStreamNotify.StreamSuspended(aStream.LocalSEID());
+		}
+	else
+		{
+		// stay in streaming state and notify the user of the error
+		ChangeState(aStream, CAVStreamStateFactory::EStreamStateStreaming);
+		aStream.iStreamNotify.StreamInitiatedServiceFailed(aStream, aResult);
+		}
+	}
+
+void TAVStreamStateSuspending::Suspended(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	// throw away
+	}
+	
+
+void TAVStreamStateSuspending::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+
+void TAVStreamStateReconfiguring::ReconfigConfirm(CAVStream& aStream, TInt aResult, 
+												TSEID /*aRemoteSEID*/, TAvdtpServiceCategory aFailedCategory) const
+	{
+	LOG_FUNC
+	// ok to return to ready on success or failure
+	ChangeState(aStream, CAVStreamStateFactory::EStreamStateReady);
+	TRAPD(err, aStream.iLocalSEP->CommitPendingConfigurationL(aResult==KErrNone, ETrue));
+	if (err!=KErrNone)
+		{
+		aStream.iStreamNotify.StreamInitiatedServiceFailed(aStream, aResult);
+		}
+	aStream.iStreamNotify.StreamConfigured(aStream.LocalSEID(), aResult, aFailedCategory);
+	}
+
+void TAVStreamStateReconfiguring::Enter(CAVStream& __DEBUG_ONLY(aStream)) const
+	{
+	LOG_FUNC
+	//We should not be preventing the encryption key refresh in this state. Asserting this condition. 
+	__ASSERT_DEBUG(!aStream.IsHostEncryptionKeyRefreshPrevented(),Panic(EUnexpectedEncryptionKeyRefreshPrevent));
+	}
+	
+
+void TAVStreamStateStreaming::Enter(CAVStream& aStream) const
+	{                              
+	LOG_FUNC
+ // experiments with window dragging show not much change if thread priority bumped
+ // maybe due to trying to get into esock in the first place
+ // Changing the role of the Esock_BT thread in the cmi file, from player to 
+ // DealerPlayer allows messages to be passed directly to the Esock_BT thread
+ 
+ 	aStream.iOriginalESockBTPriority = RThread().Priority(); //save the original priority of the Esock_BT thread.
+ 	RThread().SetPriority(EPriorityRealTime);
+	
+	}
+
+void TAVStreamStateStreaming::Exit(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	RThread().SetPriority(aStream.iOriginalESockBTPriority);//set the priority of the thread back to the original value.
+	
+	// Tell the physical link that encryption keys could be refreshed now, to prevent an auto refresh later
+	aStream.AllowHostEncryptionKeyRefresh();
+	}
+	
+TInt TAVStreamStateStreaming::Suspend(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	TInt retVal = KErrNone;
+	CSignallingChannel* sigch = aStream.iProtocol.FindSignallingChannel(aStream.iRemoteAddress.BTAddr());
+		
+	__ASSERT_DEBUG(sigch, PanicInState(EAvdtpSignallingChannelShouldExist));
+	if (sigch)
+		{
+		retVal = sigch->SendSuspendStream(aStream, aStream.RemoteSEID());
+		if (retVal==KErrNone)
+			{
+			ChangeState(aStream, CAVStreamStateFactory::EStreamStateSuspending);
+			}
+		}
+	return retVal;
+	}
+	
+void TAVStreamStateStreaming::Suspended(CAVStream& aStream) const
+	{
+	LOG_FUNC
+	ChangeState(aStream, CAVStreamStateFactory::EStreamStateReady);
+	}
+
+TBool TAVStreamStateStreaming::IsStreaming(const CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return ETrue;
+	}
+	
+TInt TAVStreamStateStreaming::Start(CAVStream& /*aStream*/) const
+	{
+	// don't want to tell remote to Start when already Streaming, cos it's BadState
+	return KErrNotReady;
+	}
+ 
+TInt TAVStreamStateStreaming::StartReceived(CAVStream& /*aStream*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+