bluetooth/gavdp/source/gavdpHelpers.cpp
changeset 0 29b1cd4cb562
child 22 786b94c6f0a4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/gavdp/source/gavdpHelpers.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1040 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implementation of the helper active objects that talk to AVDTP
+// 
+//
+
+/**
+ @publishedPartner
+*/
+
+#include "gavdpInternal.h"
+#include "gavdpinterface.h"
+
+/**
+The default helper has EPriorityStandard.  Some of the derived helpers
+will set their priority to something different when running.  This enables
+enforcement of orderings, as because both a helper and an indication may
+have an outstanding completion we need to ensure that these are scheduled
+in the order that will cause the notifications to the client in the correct
+order.
+
+An example of this:
+AVDTP recieves an Open, which it indicates to GAVDP.  
+On receipt of the Open GAVDP will issue socket connects.
+AVDTP completes the socket connects.
+AVDTP receives an incoming Start and issues a Start indication to GAVDP by Ioctl completion.
+GAVDP now has two outstanding completed requests: 
+	- the Start indication (leading to GAVDP_StartIndication).
+	- the UPlaneConnect completion (leading to GAVDP_BearerReady).
+Unless we ensure that the connect is processed before the start, the client
+may receive the start indication before it has sockets available.
+*/
+CGavdpHelper::CGavdpHelper(CGavdp& aGavdp, MGavdpUser& aUser)
+: CActive(EPriorityStandard),
+  iGavdp(&aGavdp),
+  iUser(aUser)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+TInt CGavdpHelper::RunError(TInt aError)
+	{
+	RDebug::Print(_L("GAVDP::RunError %d"), aError);
+	
+	if (iGavdp)
+		{	
+		Gavdp().ServiceComplete(aError);
+		}
+	
+	User().GAVDP_Error(aError, KNullDesC8); // helpers with extended error can't use this path
+	//delete this whether or not we know about our CGavdp owner:
+	//if we do - it will no longer know about us (see CGavdp::ServiceComplete)
+	//if we don't - it will have detached from us earlier and expect us to
+	//clean ourselves up
+	delete this;
+	
+	return KErrNone;
+	}	
+
+void CGavdpHelper::CheckFailedL()
+	{
+	// if failed, leave and tell Gavdp service is complete
+	User::LeaveIfError(iStatus.Int());
+	}
+	
+/**
+Called by helpers to inform GAVDP they no-longer need its services, but still have
+calls to make to the User
+The helper will be detached from GAVDP, and upon completion of their duties they should
+delete themselves
+This enables GAVDP to do more for the client while the helper carries on
+**/
+void CGavdpHelper::DetachFromGavdp(TInt aError)
+	{
+	Gavdp().ServiceComplete(aError);
+	iGavdp = NULL;
+	}
+	
+inline MGavdpUser& CGavdpHelper::User()
+	{
+	return iUser;
+	}
+	
+CGavdpDiscover* CGavdpDiscover::NewL(CGavdp& aGavdp, MGavdpUser& aUser)
+	{
+	return new (ELeave) CGavdpDiscover(aGavdp, aUser);
+	}
+	
+CGavdpDiscover::CGavdpDiscover(CGavdp& aGavdp, MGavdpUser& aUser)
+								   
+: CGavdpHelper(aGavdp, aUser)
+	{
+	}
+
+CGavdpDiscover::~CGavdpDiscover()
+	{
+	Cancel();
+	}
+	
+void CGavdpDiscover::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}
+	
+void CGavdpDiscover::RunL()
+	{
+	CheckFailedL();
+	// found n SEPs - create a buffer into which to place the details
+	// short circuit this if zero SEPs found
+	User::LeaveIfError(iConfirm().iResult);
+	DetachFromGavdp(KErrNone);
+
+	TFixedArray<TAvdtpSEPInfo, KMaxAvdtpNumSEPs>& sepInfos = iConfirm().iDiscoveredSEPs();
+	for (TInt i=0;i<=iConfirm().iNumSEPs-1;i++)
+		{
+		const TAvdtpSEPInfo info = sepInfos[i];
+		User().GAVDP_SEPDiscovered(info);
+		}
+
+	User().GAVDP_SEPDiscoveryComplete();
+	
+	delete this;
+	}
+	
+	
+void CGavdpDiscover::Begin()
+	{
+	AvdtpRequester().Ioctl(EDiscoverSEPs, iStatus, &iConfirm, KSolBtAVDTPSignalling);
+	SetActive();	
+	}
+
+
+CGavdpGetCaps* CGavdpGetCaps::NewL(CGavdp& aGavdp,
+					  			  MGavdpUser& aUser,
+					  			  TSEID aSEID,
+					  			  TAvdtpServiceCategories aInterestingCategories)
+	{
+	CGavdpGetCaps* g = new (ELeave) CGavdpGetCaps(aGavdp, aUser, aSEID, aInterestingCategories);
+	CleanupStack::PushL(g);
+	g->ConstructL();
+	CleanupStack::Pop(g);
+	return g;
+	}
+	
+void CGavdpGetCaps::ConstructL()
+	{
+	TPckg<TSEID> seidPckg(iSEID);
+	iSEPCapBuf = seidPckg.AllocL();
+	iSEPCapPtr.Set(iSEPCapBuf->Des());
+	}
+	
+
+CGavdpGetCaps::CGavdpGetCaps(CGavdp& aGavdp, MGavdpUser& aUser,
+							 TSEID aSEID, TAvdtpServiceCategories aInterestingCategories)
+: CGavdpHelper(aGavdp, aUser), iSEPCapPtr(0,0), iSEID(aSEID), iInteresting(aInterestingCategories)
+	{
+	}
+	
+CGavdpGetCaps::~CGavdpGetCaps()
+	{
+	Cancel();
+	delete iSEPCapBuf;
+	}
+
+void CGavdpGetCaps::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}
+
+void CGavdpGetCaps::Begin()
+	{
+	AvdtpRequester().Ioctl(EGetCapabilities, iStatus ,&iSEPCapPtr, KSolBtAVDTPSignalling);
+	SetActive();
+	}
+
+void CGavdpGetCaps::RunL()
+	{
+	CheckFailedL();
+	
+	// iSEPCapPtr now has mask of capabilities at this point
+	TAvdtpServiceCatBitMask sepCapMask = *reinterpret_cast<const TAvdtpServiceCatBitMask*>(iSEPCapPtr.Ptr());
+	// don't trouble user with ones they'd ignore anyway
+	sepCapMask &= iInteresting();
+		
+	if (!sepCapMask)
+		{
+		// the remote sep has no capabilities the user is interested in
+		// tell them NotSupported
+		User::Leave(KErrNotSupported);
+		}
+
+	for (TInt index=0; index<ENumberOfServiceCategories; index++)
+		{
+		// go through each bit
+		if (sepCapMask & (1<<index)) // test for bit set
+			{		
+			// it's set - create a buffer big enough to receive the value
+			const TAvdtpServiceCategory servcat = static_cast<TAvdtpServiceCategory>(index+1);
+			
+			TInt bufsize =0;
+			
+			switch (servcat)
+				{
+				case EServiceCategoryMediaTransport:
+					{
+					bufsize = sizeof(TAvdtpMediaTransportCapabilities);
+					}
+					break;
+				case EServiceCategoryReporting:
+					{
+					bufsize = sizeof(TAvdtpReportingCapabilities);
+					}
+					break;
+				case EServiceCategoryRecovery:
+					{
+					bufsize = sizeof(TAvdtpRecoveryCapabilities);
+					}
+					break;
+				case EServiceCategoryContentProtection:
+					{
+					bufsize = sizeof(TAvdtpContentProtectionCapabilities);
+					}
+					break;
+				case EServiceCategoryHeaderCompression:
+					{
+					bufsize = sizeof(TAvdtpHeaderCompressionCapabilities);	
+					}
+					break;
+				case EServiceCategoryMultiplexing:
+					{
+					bufsize = sizeof(TAvdtpMultiplexingCapability);
+					}
+					break;
+				case EServiceCategoryMediaCodec:
+					{
+					// to handle an arbitrary codec (different LOSCs)
+					// we need to assume largest LOSC.  It's not around
+					// for long, so should be ok to make it big.
+					bufsize = KUnknownLOSC;
+					}
+					break;
+				}
+			
+			if (iSEPCapBuf->Length() < bufsize)
+				{
+				iSEPCapBuf = iSEPCapBuf->ReAllocL(Max(bufsize, sizeof(TInternalGetSEPCapability)));
+				}
+			
+			TPckgBuf<TInternalGetSEPCapability> capbuf;
+			capbuf().iSEID = iSEID;
+			capbuf().iServiceCategory = servcat;
+			
+			// send into socket, output will be capability
+			iSEPCapPtr.Set(iSEPCapBuf->Des());
+			iSEPCapPtr.Copy(capbuf);
+			
+			User::LeaveIfError(AvdtpRequester().GetOpt(EGetAVDTPCapabilityResponse, KSolBtAVDTPSignalling, iSEPCapPtr));
+
+			TAvdtpServiceCapability* cap = NULL;
+			
+			TRAPD(err, cap = TAvdtpServiceCapability::AllocFromPDUL(servcat, *iSEPCapBuf));
+			
+			if (err == KErrNone)
+				{
+				User().GAVDP_SEPCapability(cap); //ownership transferred!!
+				}
+			else if (err == KErrNoMemory)
+				{
+				// Special case OOM conditions to allow the client code to see them.
+				// Otherwise the 'assume capability unsupported' block below hides the
+				// error.
+				User::Leave(err);
+				}
+			else
+				{
+				// probably a capability not supported by us, so no point telling user
+				// we don't want to leave though - try to process next capability
+				}
+			}
+		}
+
+	DetachFromGavdp(KErrNone);		
+	User().GAVDP_SEPCapabilityComplete();
+	// in future - should prob go back to scheduler and do one at a time		
+	// we've got them all
+	delete this;
+	}
+
+CGavdpAbort* CGavdpAbort::NewL(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSEID)
+	{
+	return new (ELeave) CGavdpAbort(aGavdp, aUser, aSEID);
+	}
+	
+CGavdpAbort::CGavdpAbort(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSEID)
+: CGavdpHelper(aGavdp, aUser)
+	{
+	iSEID() = aSEID;
+	}
+
+CGavdpAbort::~CGavdpAbort()
+	{
+	Cancel();
+	}
+
+void CGavdpAbort::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}
+
+void CGavdpAbort::Begin()
+	{
+	SetPriority(EPriorityHigh);
+	AvdtpRequester().Ioctl(EAbortStream, iStatus ,&iSEID, KSolBtAVDTPSignalling);
+	SetActive();
+	}
+
+void CGavdpAbort::RunL()
+	{
+	CheckFailedL();
+	DetachFromGavdp(KErrNone);	
+
+	User().GAVDP_AbortStreamConfirm();
+	
+	delete this;
+	}
+
+
+
+CGavdpStart* CGavdpStart::NewL(CGavdp& aGavdp,
+					  		   MGavdpUser& aUser,
+					  		   TSEID aSeid)
+	{
+	return new (ELeave) CGavdpStart(aGavdp, aUser, aSeid);
+	}
+	
+CGavdpStart::CGavdpStart(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSeid)
+: CGavdpHelper(aGavdp, aUser), iSeidPckg(aSeid)
+	{
+	}
+
+CGavdpStart::~CGavdpStart()
+	{
+	Cancel();
+	}
+	
+void CGavdpStart::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}
+
+	
+void CGavdpStart::Begin()
+	{
+	AvdtpRequester().Ioctl(EStartStreaming, iStatus, &iSeidPckg, KSolBtAVDTPSignalling);
+	SetActive();
+	}
+	
+void CGavdpStart::RunL()
+	{
+	// at present since GAVDP only allows one seid to start at a time then there is
+	// no need for extended info, AVDTP also makes this assumption
+	CheckFailedL();
+	DetachFromGavdp(KErrNone);
+	
+	User().GAVDP_StartStreamsConfirm();
+
+	delete this;
+	}
+
+
+
+
+CGavdpSuspend* CGavdpSuspend::NewL(CGavdp& aGavdp,
+					  		   MGavdpUser& aUser,
+					  		   TSEID aSeid)
+	{
+	return new (ELeave) CGavdpSuspend(aGavdp, aUser, aSeid);
+	}
+	
+CGavdpSuspend::CGavdpSuspend(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSeid)
+: CGavdpHelper(aGavdp, aUser), iSeidPckg(aSeid)
+	{
+	}
+
+CGavdpSuspend::~CGavdpSuspend()
+	{
+	Cancel();
+	}
+
+void CGavdpSuspend::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}
+
+void CGavdpSuspend::Begin()
+	{
+	AvdtpRequester().Ioctl(ESuspendStreaming, iStatus, &iSeidPckg, KSolBtAVDTPSignalling);
+	SetActive();
+	}
+	
+void CGavdpSuspend::RunL()
+	{
+	// at present since GAVDP only allows one seid to suspend at a time then there is
+	// no need for extended info, AVDTP also makes this assumption
+	CheckFailedL();
+	DetachFromGavdp(KErrNone);
+	
+	User().GAVDP_SuspendStreamsConfirm();
+
+	delete this;
+	}
+
+
+
+CGavdpSelectSEP* CGavdpSelectSEP::NewL(CGavdp& aGavdp, MGavdpUser& aUser)
+	{
+	return new (ELeave) CGavdpSelectSEP(aGavdp, aUser);
+	}
+	
+CGavdpSelectSEP::CGavdpSelectSEP(CGavdp& aGavdp, MGavdpUser& aUser)
+: CGavdpHelper(aGavdp, aUser)
+	{
+	}
+
+
+CGavdpSelectSEP::~CGavdpSelectSEP()
+	{
+	Cancel();
+	}
+	
+void CGavdpSelectSEP::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}
+
+void CGavdpSelectSEP::Begin()
+	{
+	AvdtpRequester().Ioctl(ESelectSEP, iStatus, &iRejDataBuf, KSolBtAVDTPSignalling);
+	SetActive();
+	}
+	
+void CGavdpSelectSEP::RunL()
+	{
+	// if the Ioctl itself failed then we might have an error in the iStatus...
+	TInt result = iStatus.Int();
+	CheckFailedL();
+	DetachFromGavdp(KErrNone);	
+
+	// the ioctl mechanism may have worked but the signalling failed - with extended data...
+	result = iRejDataBuf().iError;
+	if (result!=KErrNone)
+		{
+		// the error buffer contains extended failure data
+		User().GAVDP_Error(result, iRejDataBuf);
+		}
+	else
+		{
+		User().GAVDP_ConfigurationConfirm();
+		}
+	delete this;
+	}
+
+	
+
+CGavdpConnector* CGavdpConnector::NewL(CGavdp& aGavdp, MGavdpUser& aUser, const TBTDevAddr& aAddr)
+	{
+	return new (ELeave) CGavdpConnector(aGavdp, aUser, aAddr);
+	}
+	
+CGavdpConnector::CGavdpConnector(CGavdp& aGavdp, MGavdpUser& aUser, const TBTDevAddr& aAddr)
+: CGavdpHelper(aGavdp, aUser)
+	{
+	iSocketAddress.SetBTAddr(aAddr);
+	iSocketAddress.SetSession(ESignalling);
+	}
+
+CGavdpConnector::~CGavdpConnector()
+	{
+	Cancel();
+	}
+
+void CGavdpConnector::DoCancel()
+	{
+	AvdtpRequester().CancelAll(); // ESOCK has better semantics to SAP than CancelConnect.
+	}
+
+
+void CGavdpConnector::Begin()
+	{
+	// Ensure that once this is completed the RunL is scheduled
+	// before handling completion of the indication ioctl.
+	SetPriority(EPriorityStandard+1);
+	AvdtpRequester().Connect(iSocketAddress, iStatus);
+	SetActive();
+	}
+
+void CGavdpConnector::RunL()
+	{
+		
+	// Do not call CGavdpHelper::CheckFailedL() here - avdtp will indicate a failure to connect, 
+	// and GAVDP is informed via CGavdpIndicator::RunL().
+	
+	TInt error = iStatus.Int();
+	DetachFromGavdp(error);	
+	
+	if (error == KErrNone)
+		{
+		User().GAVDP_ConnectConfirm(iSocketAddress.BTAddr());	// reuse the same callback to make life easier for app
+		}
+	else
+		{
+		User().GAVDP_Error(error, KNullDesC8);
+		}
+		
+	delete this;
+	}
+
+CGavdpIndicator::~CGavdpIndicator()
+	{
+	Cancel();
+	}
+	
+void CGavdpIndicator::DoCancel()
+	{
+	AvdtpIndicator().CancelAll();
+	}
+
+CGavdpIndicator* CGavdpIndicator::NewL(CGavdp& aGavdp, MGavdpUser& aUser)
+	{
+	return new (ELeave) CGavdpIndicator(aGavdp, aUser);
+	}
+	
+CGavdpIndicator::CGavdpIndicator(CGavdp& aGavdp, MGavdpUser& aUser)
+: CGavdpHelper(aGavdp, aUser)
+	{
+	}
+
+
+void CGavdpIndicator::RunL()
+	{
+	// this service is not-one shot, so don't call DetachFromGavdp
+	User::LeaveIfError(iStatus.Int());
+		
+	// reinterpret our now complete descriptor as a TAvdtpIndicationPckg
+	// then raise appropriate indication
+	
+	const TUint8* ptr = iIndication.Ptr();
+	const TInternalAvdtpIndication& indtype = *reinterpret_cast<const TInternalAvdtpIndication*>(ptr);
+
+	if (indtype.iType == TInternalAvdtpIndication::EError)
+		{
+		const TInternalAvdtpErrorIndication& error = reinterpret_cast<const TInternalAvdtpErrorIndication&>(indtype);
+		// if avdtp errors, so does Gavdp
+		Gavdp().Error(error.iError); // GAVDP tells the user if needed: ESOCK DEF - that may delete GAVDP
+		}
+		
+	else if (indtype.iType == TInternalAvdtpIndication::EObject)
+		{
+		const TInternalAvdtpObjectIndication& ind = *reinterpret_cast<const TInternalAvdtpObjectIndication*>(ptr);
+		switch (ind.iObjectIndication)
+			{
+			case TInternalAvdtpObjectIndication::ESignallingReady:
+			TBTDevAddr addr(ind.iBuf);
+			Gavdp().BindSignallingL(addr);			
+			break;
+			
+			}
+		}
+	
+	else if (indtype.iType == TInternalAvdtpIndication::EAir)
+		{		
+		TInt res = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+		const TInternalAvdtpAirIndication& ind = *reinterpret_cast<const TInternalAvdtpAirIndication*>(ptr);
+
+		switch (ind.iIndication)
+			{
+			// only ones the stack doesn't deal with completely
+			case EAvdtpSetConfiguration:
+			case EAvdtpReconfigure:
+				{
+				// app must have a say in determining if the configuration is OK
+				// the remote has selected the sep it is interested in
+				// and checked the caps the apps has already set
+				// but stack would find it "hard" to semantically compare optional caps etc
+				// need to get the payload from the stack
+				const TInternalAvdtpConfigurationIndication& cfgInd=static_cast<const TInternalAvdtpConfigurationIndication&>(ind);
+				HBufC8* resp = HBufC8::NewMaxLC(Max(cfgInd.iPayloadLength, sizeof(TInternalGetProposedConfiguration)));
+				TPtr8 des = resp->Des();
+				
+				TInternalGetProposedConfiguration& getConfBuf = *const_cast<TInternalGetProposedConfiguration*>(reinterpret_cast<const TInternalGetProposedConfiguration*>(resp->Des().Ptr()));
+				getConfBuf.iSEID = ind.iSEID;
+								
+				// get remainder of configuration from AVDTP
+				TInt err = AvdtpRequester().GetOpt(EGetProposedConfiguration,
+													KSolBtAVDTPSignalling,
+													des);
+
+				__ASSERT_DEBUG(err==KErrNone, Fault(EGavdpUnexpectedAvdtpError));
+				
+				TAvdtpServiceCategories cats;
+				cats.SetCapability(EAllServiceCategories);
+				
+				CCapabilityParseVisitor* parser = new (ELeave) CCapabilityParseVisitor(cats);
+				parser->Process(des);
+				TCapabilitiesArray caps = parser->GetCapabilities();
+				delete parser;
+				
+				// tell app they're abuot to be offered configuration details
+				
+				User().GAVDP_ConfigurationStartIndication(cfgInd.iSEID, cfgInd.iINTSEID);
+				
+				for (TInt i=0; i<ENumberOfServiceCategories; i++)
+					{
+					// go through each capability...
+					if (EServiceCategoryMultiplexing==i)
+						{
+						// don't offer this one to user, it's not for them
+						// as it's part of AVDTP adaptation services...
+						continue;
+						}
+					TAvdtpServiceCapability*& cap = caps[i];
+					if (cap)
+						{
+						// and tell client
+						res = User().GAVDP_ConfigurationIndication(cap);
+						CheckClientResult(res);
+						if (res!=KErrNone)
+							{
+							TAvdtpServiceCategory cat = cap->Category();
+							
+							Gavdp().SendResponse(cfgInd, res, &cat);
+							// protocol says we finish config when anything is rejected
+							break;
+							}
+						else
+							{
+							// passed ownership for the error-free case
+							cap = NULL;
+							}
+						}
+					}
+				if (res==KErrNone)
+					{				
+					// tell app there's no more
+					res = User().GAVDP_ConfigurationEndIndication();
+					CheckClientResult(res);
+					// As we don't have a particular category to refer to we pass in
+					// the null category (0x0) in case GAVDP_ConfigurationEndIndication 
+					// returned an error. (Bluetooth Errata ID 332)
+					TAvdtpServiceCategory nullcat(EServiceCategoryNull);
+					// whatever user has said is now their final answer
+					Gavdp().SendResponse(cfgInd, res, &nullcat);
+					}
+
+				CleanupStack::PopAndDestroy(resp);
+				caps.DeleteAll();
+				break;
+				}
+			
+			case EAvdtpOpen:
+				{
+				 // need to process to stop deadlock if the other end doesnt do Start as INT
+				 // which it might do annoyingly if it wrongly relies on AVRCP
+				// we can just connect up sockets
+				const TInternalAvdtpStreamReadyIndication& r = reinterpret_cast<const TInternalAvdtpStreamReadyIndication&>(ind);
+			
+				Gavdp().BindBearersL(r.iRemoteSEID, r.iReportingPresent, r.iRecoveryPresent);
+				// no response to send
+				break;
+				}
+				
+			case EAvdtpRelease:
+				{
+				// just tell the user the stream has gone, AVDTP has already replied
+				User().GAVDP_ReleaseIndication(ind.iSEID);
+				break;
+				}
+		
+			case EAvdtpStart:
+				{
+				// although the packet may contain muliple SEIDs by this point
+				// each indication will have one as the ordering of the SEIDs
+				// in the packet relative to GAVDP user / session ordering is
+				// not specified.
+				res = User().GAVDP_StartIndication(ind.iSEID);
+				CheckClientResult(res);
+				Gavdp().SendResponse(ind, res);
+				break;
+				}
+			case EAvdtpSuspend:
+				{
+				// although the packet may contain muliple SEIDs by this point
+				// each indication will have one as the ordering of the SEIDs
+				// in the packet relative to GAVDP user / session ordering is
+				// not specified.
+				
+				res = User().GAVDP_SuspendIndication(ind.iSEID);
+				CheckClientResult(res);
+				Gavdp().SendResponse(ind, res);
+				break;
+				}
+			case EAvdtpSecurityControl:
+				{
+				TInt length = ind.iPayloadLength;
+				if (length < sizeof(TInternalGetSecurityControl))
+					{
+					length = sizeof(TInternalGetSecurityControl);
+					}
+				
+				HBufC8* resp = HBufC8::NewMaxLC(length);
+				TPtr8 securityData = resp->Des();
+				
+				TInternalGetSecurityControl& getSecBuf = *const_cast<TInternalGetSecurityControl*>(reinterpret_cast<const TInternalGetSecurityControl*>(resp->Des().Ptr()));
+				getSecBuf.iSEID = ind.iSEID;
+								
+				// get remainder of securitycontrol from AVDTP
+				TInt err = AvdtpRequester().GetOpt(EGetSecurityControl,
+													KSolBtAVDTPSignalling,
+													securityData);
+
+				__ASSERT_DEBUG(err==KErrNone, Fault(EGavdpUnexpectedAvdtpError));
+
+
+				res = User().GAVDP_SecurityControlIndication(ind.iSEID, securityData);
+				CheckClientResult(res);
+				// the client is allowed to change the buffer contents to supply data in response
+				Gavdp().SendResponse(ind, res, securityData.Ptr(), securityData.Length());
+				CleanupStack::PopAndDestroy(resp);
+				break;
+				}
+			case EAvdtpAbort:
+				{
+				// no return from client - there's nothing they can do
+				User().GAVDP_AbortIndication(ind.iSEID);
+				// stack already responded
+				break;
+				}
+			default:
+				{
+				}
+			};
+		}
+
+		// This service is never complete, reissue ioctl.  We do this once we have finished using
+		// the iIndication data as once the ioctl has been issued the data may be overwritten.
+		// If AVDTP has an indication to pass to us and an ioctl has not been issued the
+		// indication will be queued within AVDTP until we have issued the ioctl again.
+		Begin();
+	}
+	
+/**
+RunError overriden for CGavdpIndicator only. This GAVDP helper is used in its own right by GAVDP.
+It is not treated as a 'general' GAVDP helper, and, unlike a 'general' GAVDP helper,
+should live for the duration of GAVDP.
+Note, however that hitting this RunError is deemed fatal, and so we kill GAVDP completely. The 
+user will have to re-open it to recover.
+*/
+TInt CGavdpIndicator::RunError(TInt aError)
+	{
+	RDebug::Print(_L("GAVDP::Fatal Error %d"), aError);
+	Gavdp().FatalError();
+	
+	//*****No code below here please - call to CGAVDP::FatalError will delete us****
+	return KErrNone;
+	}	
+
+void CGavdpIndicator::CheckClientResult(TInt aResult)
+	{
+	__ASSERT_ALWAYS(aResult<=KErrNone, Panic(EGavdpClientHasRepliedInCorrectly));
+	}
+	
+/**
+@internalComponent
+Start the Indicator helper
+*/
+void CGavdpIndicator::Begin()
+	{
+	AvdtpIndicator().Ioctl(EAwaitIndication, iStatus, &iIndication, KSolBtAVDTPSignalling);
+	SetActive();	
+	}
+
+
+/**
+@internalComponent
+Create a User-plane bearer connector helper
+*/
+CGavdpUPlaneConnector* CGavdpUPlaneConnector::NewL(CGavdp& aGavdp,
+												   MGavdpUser& aUser,
+												   const TAvdtpSockAddr& aAddr,
+											 	   TBool aRequireReporting,
+											 	   TBool aRequireRecovery,
+											 	   RSocketServ& aClientSession)
+	{
+	CGavdpUPlaneConnector* s = new (ELeave) CGavdpUPlaneConnector(aGavdp, aUser, aAddr,
+																	aRequireReporting,
+																	aRequireRecovery,
+																	aClientSession);
+	CleanupStack::PushL(s);
+	s->ConstructL(aRequireReporting, aRequireRecovery);
+	CleanupStack::Pop(s);																	
+	return s;
+	}
+	
+CGavdpUPlaneConnector::CGavdpUPlaneConnector(CGavdp& aGavdp, MGavdpUser& aUser,
+											 const TAvdtpSockAddr& aSockAddr,
+											 TBool aRequireReporting,
+											 TBool aRequireRecovery,
+						  					 RSocketServ& aClientSession)
+: CGavdpHelper(aGavdp, aUser),
+  iClientSession(aClientSession)
+	{
+	iAddress = aSockAddr;
+	iNumBearersRequired = AvdtpInternalUtils::NumberOfTransportObjects(aRequireReporting, aRequireRecovery);
+	}
+
+void CGavdpUPlaneConnector::ConstructL(TBool aRequireReporting, TBool aRequireRecovery)
+	{
+	TAvdtpSockAddr addr = iAddress;
+	addr.SetSession(EMedia);
+	iSocketConnectors[0]=CSocketConnector::NewL(*this, AvdtpSession(), addr);
+
+	if (aRequireReporting)
+		{
+		addr.SetSession(EReporting);
+		iSocketConnectors[1]=CSocketConnector::NewL(*this, AvdtpSession(), addr);
+		}
+
+	if (aRequireRecovery)
+		{
+		addr.SetSession(ERecovery);
+		iSocketConnectors[2]=CSocketConnector::NewL(*this, AvdtpSession(), addr);
+		}
+	}
+	
+CGavdpUPlaneConnector::~CGavdpUPlaneConnector()
+	{
+	Cancel();
+	iSocketConnectors.DeleteAll();
+	}
+
+void CGavdpUPlaneConnector::DoCancel()
+	{
+	for (TInt i=0; i<iSocketConnectors.Count()-1; i++)
+		{
+		if (iSocketConnectors[i])
+			{
+			iSocketConnectors[i]->Cancel();
+			}
+		}
+	}
+
+void CGavdpUPlaneConnector::Begin()
+	{
+	// Ensure that once this is completed the RunL is scheduled
+	// before handling completion of the indication ioctl.
+	SetPriority(EPriorityStandard+1);
+	for (TInt i=0; i<iSocketConnectors.Count()-1; i++)
+		{
+		if (iSocketConnectors[i])
+			{
+			iSocketConnectors[i]->Begin();
+			}
+		}
+	}
+
+void CGavdpUPlaneConnector::ConnectComplete(TInt aErr)
+	{
+	DoConnectComplete(aErr);
+
+	if (aErr)
+		{
+		DoCancel();	// now not active, but we need to cancel the remaining socketconnectors
+		}
+	}
+	
+void CGavdpUPlaneConnector::DoConnectComplete(TInt aErr)
+	{
+	--iNumBearersRequired;
+	
+	if(aErr >= EGavdpMinPanicErr && aErr <= EGavdpMaxPanicErr)
+		{
+		Panic (static_cast<TGavdpPanic>(aErr));
+		}
+	
+	if (!iNumBearersRequired || aErr!=KErrNone)
+		{
+		// service is complete
+		TRequestStatus* ours = &iStatus;
+		*ours = KRequestPending;
+		SetActive();
+		User::RequestComplete(ours, aErr);
+		}
+	}
+	
+void CGavdpUPlaneConnector::RunL()
+	{
+	CheckFailedL();
+
+	// all required bearers connected, helper can detach from gavdp
+	DetachFromGavdp(KErrNone);
+	
+	AllBearersReadyL();
+
+	delete this;
+	}
+	
+void CGavdpUPlaneConnector::AllBearersReadyL()
+	{
+	// transfer our sockets onto the client session
+	for (TInt i=0; i<=iSocketConnectors.Count()-1; i++)
+		{
+		CSocketConnector* const connector = iSocketConnectors[i];
+		if (connector)
+			{
+			RSocket& socket = connector->Socket();
+			// take socket and transfer to client session
+			TName socketName;
+			User::LeaveIfError(socket.Name(socketName));
+
+			RSocket clientSocket;
+
+			//plat sect stuff to transfer sockets - to this same process
+			TSecurityPolicy secPol(RProcess().SecureId());
+			TPckgBuf<TSecurityPolicy> secPolBuf(secPol);
+			User::LeaveIfError(socket.SetOpt(KSOEnableTransfer, KSOLSocket, secPolBuf));
+			User::LeaveIfError(clientSocket.Transfer(iClientSession, socketName));
+			
+			User().GAVDP_BearerReady(clientSocket, connector->Address());
+			}
+		}
+	}
+	
+
+CSocketConnector* CSocketConnector::NewL(CGavdpUPlaneConnector& aParent,
+									RSocketServ& aSocketServer,
+									const TAvdtpSockAddr& aSockAddr)
+
+	{
+	CSocketConnector* self = new(ELeave) CSocketConnector(aParent, aSocketServer, aSockAddr);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CSocketConnector::ConstructL()
+	{
+	User::LeaveIfError(iSocket.Open(iSocketServer, KAVDTPProtocolName));
+	}
+	
+void CSocketConnector::Begin()
+	{
+	iSocket.Connect(iSockAddr, iStatus);
+	SetActive();
+	}
+	
+CSocketConnector::CSocketConnector(CGavdpUPlaneConnector& aParent,
+									RSocketServ& aSocketServer,
+									const TAvdtpSockAddr& aSockAddr)
+: CActive(EPriorityStandard+1), iParent(aParent),
+iSocketServer(aSocketServer), iSockAddr(aSockAddr)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CSocketConnector::~CSocketConnector()
+	{
+	Cancel();
+
+	if (iSocket.SubSessionHandle())
+		{
+		iSocket.Close();
+		}
+	}
+	
+void CSocketConnector::RunL()
+	{
+	iParent.ConnectComplete(iStatus.Int());
+	}
+	
+void CSocketConnector::DoCancel()
+	{
+	if (iSocket.SubSessionHandle())
+		{
+		iSocket.CancelAll();
+		}
+	}
+	
+
+CGavdpSecurityControl* CGavdpSecurityControl::NewL(CGavdp& aGavdp,
+					  		  MGavdpUser& aUser,
+					  		  TSEID aSeid,
+					  		  const TDesC8& aSecurityControl)
+	{
+	return new (ELeave) CGavdpSecurityControl(aGavdp, aUser, aSeid, aSecurityControl);
+	}
+	
+void CGavdpSecurityControl::Begin()
+	{
+	AvdtpRequester().Ioctl(ESendSecurityControl, iStatus, &iSecurityControlPckgBuf, KSolBtAVDTPSignalling);
+	SetActive();		
+	}
+	
+CGavdpSecurityControl::~CGavdpSecurityControl()
+	{
+	Cancel();
+	}
+	
+CGavdpSecurityControl::CGavdpSecurityControl(CGavdp& aGavdp, MGavdpUser& aUser, TSEID aSeid, const TDesC8& aSecurityData)
+: CGavdpHelper(aGavdp, aUser)
+	{
+	iSecurityControlPckgBuf().iRemoteSEID = aSeid;
+	iSecurityControlPckgBuf().iSecurityControlInfo = aSecurityData;
+	}
+	
+void CGavdpSecurityControl::RunL()
+	{
+	CheckFailedL();
+	DetachFromGavdp(KErrNone);	
+
+	User().GAVDP_SecurityControlConfirm(iSecurityControlPckgBuf().iSecurityControlInfo);
+
+	delete this;
+	}
+	
+void CGavdpSecurityControl::DoCancel()
+	{
+	AvdtpRequester().CancelAll();
+	}