bluetooth/gavdp/source/gavdpImp.cpp
changeset 0 29b1cd4cb562
child 35 14e279d2bbb7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/gavdp/source/gavdpImp.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,573 @@
+// 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 Generic Audio-Video Distribution Profile - GAVDP
+// The CGavdp class acts as a "Body" implementation to the RGavdp "Handle"
+// 
+//
+
+/**
+ @publishedPartner
+*/
+
+
+#include "gavdpInternal.h"
+
+CGavdp* CGavdp::NewL(MGavdpUser& aServiceUser, RSocketServ& aSocketServer, RGavdp& aHandle)
+	{
+#ifndef BLUETOOTH_NO_AV
+	CGavdp* gavdp = new(ELeave) CGavdp(aServiceUser, aSocketServer, aHandle);
+	CleanupStack::PushL(gavdp);
+	gavdp->ConstructL();
+	CleanupStack::Pop(gavdp);
+	return gavdp;
+#else
+	User::Leave(KErrNotSupported);
+	return NULL; // not reached
+#endif
+	}
+	
+CGavdp::~CGavdp()
+	{
+	DeAllocSocketsAndHelpers();
+	iSocketServer.Close();
+	}
+	
+void CGavdp::DeAllocSocketsAndHelpers()
+	{
+	delete iRequesterHelper;
+	iRequesterHelper = NULL;
+	delete iIndicatorHelper;
+	iIndicatorHelper = NULL;
+	AvdtpRequester().Close();
+	AvdtpIndicator().Close();
+	}
+	
+void CGavdp::ConstructL()
+	{
+	User::LeaveIfError(iSocketServer.Connect());
+	ConstructSocketsAndHelpersL();
+	}
+	
+void CGavdp::Cancel()
+	{
+	if (iRequesterHelper)
+		{
+		delete iRequesterHelper;
+		iRequesterHelper = NULL;
+		iState = EIdle;
+		// it is the client's job to recover state, so they should send an Abort.
+		}
+	// leave indications running.
+	}
+
+void CGavdp::ConstructSocketsAndHelpersL()
+	{
+	User::LeaveIfError(AvdtpRequester().Open(iSocketServer, KAVDTPProtocolName));
+
+	// mark as for signalling purposes
+	TAvdtpSockAddr addr;
+	addr.SetSession(ESignalling);
+	User::LeaveIfError(AvdtpRequester().Bind(addr));
+
+	// start reading for AVDTP indications
+	User::LeaveIfError(AvdtpIndicator().Open(iSocketServer, KAVDTPProtocolName));
+
+	User::LeaveIfError(AvdtpIndicator().SetOpt(ESetAsSecondarySAP,
+								  KSolBtAVDTPInternal,
+								  KNullDesC8));
+								  
+	User::LeaveIfError(AvdtpRequester().SetOpt(EBindToSecondarySAP,
+									  KSolBtAVDTPInternal,
+									  KNullDesC8));
+	iIndicatorHelper = CGavdpIndicator::NewL(*this, iServiceUser);
+	iIndicatorHelper->Begin();
+	}
+	
+CGavdp::CGavdp(MGavdpUser& aServiceUser, RSocketServ& aClientSocketServer, RGavdp& aHandle)
+: iClientSocketServer(aClientSocketServer), iServiceUser(aServiceUser), iHandle(aHandle)
+	{
+	}
+	
+void CGavdp::Connect(const TBTDevAddr& aRemoteAddr)
+	{
+	__ASSERT_ALWAYS((iState == EIdle || iState == EListening), Panic(EGavdpBadState));
+	__ASSERT_ALWAYS(iNumSEPsRegistered, Panic(EGavdpSEPMustBeRegisteredBeforeConnect));
+	__ASSERT_ALWAYS(aRemoteAddr!=TBTDevAddr(0), Panic(EGavdpBadRemoteAddress));
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	
+	AvdtpRequester().SetOpt(EStopAwaitPassiveSignallingChannel, KSolBtAVDTPSignalling, NULL);
+		
+	TRAPD(err, iRequesterHelper = CGavdpConnector::NewL(*this, iServiceUser, aRemoteAddr));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iState = EConnecting;
+		iRequesterHelper->Begin();	
+		}	
+	}
+
+void CGavdp::DiscoverRemoteSEPs()
+	{
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	
+	TRAPD(err, iRequesterHelper = CGavdpDiscover::NewL(*this, iServiceUser));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();	
+		}
+	}
+
+void CGavdp::GetRemoteSEPCapabilities(TSEID aSEID, const TAvdtpServiceCategories& aInterestingCategories)
+	{
+	__ASSERT_ALWAYS(!iRequesterHelper /*&& iServiceUser*/, Panic(EGavdpBadState));
+	CheckSEID(aSEID);
+	
+	TRAPD(err, iRequesterHelper = CGavdpGetCaps::NewL(*this,
+											 iServiceUser,
+											 aSEID,
+											 aInterestingCategories));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();	
+		}
+	}
+	
+TInt CGavdp::BeginConfiguringRemoteSEP(TSEID aRemoteSEID, TSEID aLocalSEID)
+	{
+	__ASSERT_ALWAYS(iState!=EConfiguringRemoteSEP, Panic(EGavdpBadState));
+	CheckSEID(aRemoteSEID);
+	CheckSEID(aLocalSEID);
+
+	TInternalSelectRemoteSEP select;
+	select.iLocalSEID = aLocalSEID;
+	select.iRemoteSEID = aRemoteSEID;
+	
+	TPckg<TInternalSelectRemoteSEP> seidpckg(select);
+	TInt err = AvdtpRequester().SetOpt(EStartConfiguringRemote, KSolBtAVDTPSignalling, seidpckg);
+	if (err==KErrNone)
+		{
+		iState = EConfiguringRemoteSEP;
+		}
+	return err;
+	}
+	
+TInt CGavdp::BeginConfiguringLocalSEP(TSEID aSEID)
+	{
+	__ASSERT_ALWAYS(iState!=EConfiguringLocalSEP, Panic(EGavdpBadState));
+	TPckg<TSEID> seidpckg(aSEID);
+	TInt err = AvdtpRequester().SetOpt(EStartConfiguringLocal, KSolBtAVDTPSignalling, seidpckg);
+	if (err==KErrNone)
+		{
+		iState = EConfiguringLocalSEP;
+		}
+	return err;
+	}
+	
+	
+TInt CGavdp::AddSEPCapability(const TAvdtpServiceCapability& aCapability)
+	{
+	__ASSERT_ALWAYS(iState==EConfiguringLocalSEP || iState==EConfiguringRemoteSEP,
+																Panic(EGavdpBadState));
+
+	// convert into protocol form - this is a handy way to get a descriptor for IPC purposes
+	// if AVDTP requires the reverse operation it is of course allowed to get back to the T class form
+	RBuf8 buf;
+	TInt err = aCapability.AsProtocol(buf);
+	if (err==KErrNone)
+		{
+		err = AvdtpRequester().SetOpt(EAddCapabilitySelection,KSolBtAVDTPSignalling, buf);
+		}
+		
+	buf.Close();
+	return err; 
+	}
+
+void CGavdp::CommitSEPConfiguration()
+	{
+	__ASSERT_ALWAYS(iState == EConfiguringLocalSEP || iState == EConfiguringRemoteSEP, Panic(EGavdpBadState));
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	
+	TRAPD(err, iRequesterHelper = CGavdpSelectSEP::NewL(*this, iServiceUser));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();
+		}
+	}
+
+void CGavdp::StartStream(TSEID aSEID)
+	{
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	
+	TRAPD(err, iRequesterHelper = CGavdpStart::NewL(*this, iServiceUser, aSEID));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();	
+		}	
+	}
+
+void CGavdp::SuspendStream(TSEID aSEID)
+	{
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	
+	TRAPD(err, iRequesterHelper = CGavdpSuspend::NewL(*this, iServiceUser, aSEID));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();	
+		}	
+	}
+
+void CGavdp::AbortStream(TSEID aSEID)	
+	{
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	CheckSEID(aSEID);
+	
+	TRAPD(err, iRequesterHelper = CGavdpAbort::NewL(*this, iServiceUser, aSEID));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();	
+		}
+	}
+
+void CGavdp::SendSecurityControl(TSEID aSEID, const TDesC8& aSecurityData)	
+	{
+	__ASSERT_ALWAYS(!iRequesterHelper, Panic(EGavdpBadState));
+	CheckSEID(aSEID);
+	
+	TRAPD(err, iRequesterHelper = CGavdpSecurityControl::NewL(*this, iServiceUser, aSEID, aSecurityData));
+	
+	if (err)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	else
+		{
+		iRequesterHelper->Begin();	
+		}
+	}
+	
+
+TInt CGavdp::RegisterSEP(TAvdtpSEPInfo& aInfo)
+	{
+	// note this is a GetOpt - but it also sets:
+	// in goes the info, without SEID
+	// out comes the same structure with SEID filled in
+	TPckg<TAvdtpSEPInfo> sepInfo(aInfo);
+	TInt err = AvdtpRequester().GetOpt(ERegisterSEP, KSolBtAVDTPSignalling, sepInfo);
+	if (err==KErrNone)
+		{
+		iNumSEPsRegistered++;
+		}
+	return err;
+	}
+
+
+/**
+Called when gavdp client has registed all seps and is ready
+May be short lived as they may try to connect out quickly
+*/
+TInt CGavdp::Listen()
+	{
+	__ASSERT_ALWAYS(iNumSEPsRegistered, Panic(EGavdpSEPMustBeRegisteredBeforeListen));
+	TInt ret = KErrNone;
+	
+	if (iState!=EConnected)
+		{
+		// start awaiting for signalling channel as as SEP has been successfully registered
+		ret = AvdtpRequester().SetOpt(EAwaitPassiveSignallingChannel, KSolBtAVDTPSignalling, NULL);
+		if (KErrNone==ret)
+			{
+			iState = EListening;
+			}
+		}
+	else
+		{
+		ret = KErrInUse;
+		}
+	return ret;
+	}
+	
+
+// private
+
+void CGavdp::SendResponse( TInternalAvdtpAirIndication aIndication,
+						  TInt aResult,
+						  const TAny* aResponseData/*=NULL*/,
+						  TInt aResponseDataLen/*=0*/)
+	{
+	TInt err = KErrNone;
+	
+	switch (aIndication.iIndication)
+		{
+		case EAvdtpSetConfiguration:
+		case EAvdtpReconfigure:
+			{
+			TAvdtpInternalConfigurationResponse rsp;
+			rsp.iSEID = aIndication.iSEID;
+			rsp.iTransactionLabel = aIndication.iTransactionLabel;
+			rsp.iResult = aResult;
+			rsp.iIsReconfigure = aIndication.iIndication==EAvdtpReconfigure;
+			
+			if (aResult!=KErrNone)
+				{
+				__ASSERT_DEBUG(aResponseData, Panic(EGavdpResponseDataExpected));
+				rsp.iCategory = *static_cast<const TAvdtpServiceCategory*>(aResponseData);
+				}
+	
+			TPckg<TAvdtpInternalConfigurationResponse> pckg(rsp);
+			
+			err = AvdtpRequester().SetOpt(ESendConfigurationResponse, KSolBtAVDTPSignalling, pckg);
+			
+			break;
+			}
+		case EAvdtpSecurityControl:
+			{
+			// optional to send data in response
+			TAvdtpInternalSecurityControlResponse rsp;
+			rsp.iSEID = aIndication.iSEID;
+			rsp.iTransactionLabel = aIndication.iTransactionLabel;
+			rsp.iResult = aResult;
+
+			if (aResult==KErrNone)
+				{
+				rsp.iSecurityControlInfo.Copy(static_cast<const TUint8*>(aResponseData), aResponseDataLen);
+				}
+	
+			TPckg<TAvdtpInternalSecurityControlResponse> pckg(rsp);			
+			err = AvdtpRequester().SetOpt(ESendSecurityControlResponse, KSolBtAVDTPSignalling, pckg);
+			
+			break;
+			}
+		case EAvdtpStart:
+			{
+			TAvdtpInternalStartResponse rsp;
+			rsp.iSEID = aIndication.iSEID;
+			rsp.iTransactionLabel = aIndication.iTransactionLabel;
+			rsp.iResult = aResult;
+
+			TPckg<TAvdtpInternalStartResponse> pckg(rsp);
+			err = AvdtpRequester().SetOpt(ESendStartResponse, KSolBtAVDTPSignalling, pckg);		
+			
+			break;
+			}
+		case EAvdtpSuspend:
+			{
+			TAvdtpInternalSuspendResponse rsp;
+			rsp.iSEID = aIndication.iSEID;
+			rsp.iTransactionLabel = aIndication.iTransactionLabel;
+			rsp.iResult = aResult;
+
+			TPckg<TAvdtpInternalSuspendResponse> pckg(rsp);
+			err = AvdtpRequester().SetOpt(ESendSuspendResponse, KSolBtAVDTPSignalling, pckg);
+			
+			break;
+			}
+		}	
+
+	if (err!=KErrNone)
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	}
+		
+	
+void CGavdp::ServiceComplete(TInt aResult)
+	{
+	__ASSERT_DEBUG(iRequesterHelper, Fault(EGavdpHelperCompletingBadly));
+	iRequesterHelper = NULL;
+	
+	if (aResult==KErrNone)
+		{
+		switch (iState)
+			{
+			case EConfiguringRemoteSEP:
+			case EListening:
+			case EConnecting:
+				iState = EConnected;
+				break;
+			case EConfiguringLocalSEP:
+				{
+				iState = EIdle;
+				break;
+				}
+				
+			}
+		}
+	else
+		{
+		iState = EIdle; // or perhaps errored? 
+		}
+	}
+	
+void CGavdp::Error(TInt aError)
+	{
+	// helper tells user - here we do whatever we need to tidy ourselves
+	delete iRequesterHelper;
+	iRequesterHelper = NULL;
+	iState = EIdle;
+	// and tell the user
+	iServiceUser.GAVDP_Error(aError, KNullDesC8);
+	}
+
+void CGavdp::FatalError()
+	{
+	//Unbind from the body before informing the user
+	iHandle.UnbindBody();
+	//Now tell the user we are DEAD
+	iServiceUser.GAVDP_Error(KErrDied, KNullDesC8);
+	//Cleanup: we've unbound from the body, We are no longer owned. Delete ourselves
+	delete this;
+	}
+
+/*
+Forms the binding between passively created signalling and sockets
+*/
+void CGavdp::BindSignallingL(const TBTDevAddr& aRemoteAddress)
+	{
+	// use the same helper as if we originated the signalling channel
+	if (iRequesterHelper)
+		{
+		// the client has just issued another command
+		// this is likely to be something that renders the connections invalid anyway
+		// eg Abort, Config
+		User::Leave(KErrInUse);
+		}
+	iRequesterHelper = CGavdpConnector::NewL(*this, iServiceUser, aRemoteAddress);
+	iRequesterHelper->Begin();
+	}
+	
+/*
+Forms the binding between passively created transport sessions and sockets
+*/
+void CGavdp::BindBearersL(TSEID aSEID, TBool aRequireReporting, TBool aRequireRecovery)
+	{
+	// which bearers? spy on set config to see if rec&rep in use
+	// or from the indication?
+	//certainly media
+	CheckSEID(aSEID);
+	
+	TAvdtpSockAddr addr;
+	AvdtpRequester().RemoteName(addr);	
+	addr.SetSEID(aSEID);
+	
+	if (iRequesterHelper)
+		{
+		// the client has just issued another command
+		// this is likely to be something that renders the connections invalid anyway
+		// eg Abort, Config
+		User::Leave(KErrInUse);
+		}
+	
+	iRequesterHelper = CGavdpUPlaneConnector::NewL(*this,
+										  iServiceUser,
+										  addr,
+										  aRequireReporting,
+										  aRequireRecovery,
+										  iClientSocketServer
+										  );
+	iRequesterHelper->Begin();
+	}
+
+TInt CGavdp::CreateBearerSockets(TSEID aSEID)
+	{	
+	// form socket address and connect
+	// should be in state listening. if we are told to create bearers then of course stop listening
+	CheckSEID(aSEID);
+	
+	TAvdtpSockAddr addr;
+	
+	// get remote BDAddr for this session
+	AvdtpRequester().RemoteName(addr);
+	
+	// now set SEID and Session type
+	addr.SetSEID(aSEID);
+	
+	// ask avdtp if reporting and recovery are configured
+	TReportingAndRecovery rar;
+	rar.iSEID = aSEID;
+	TPckg<TReportingAndRecovery> rarBuf(rar);
+	TInt err = AvdtpRequester().GetOpt(EGetReportingAndRecoveryConfig, KSolBtAVDTPSignalling, rarBuf);
+	if(err == KErrNone)
+		{
+		// helper sets session types	
+		TRAP(err, iRequesterHelper = CGavdpUPlaneConnector::NewL(*this,
+																iServiceUser,
+																addr,
+																rar.iReporting,
+																rar.iRecovery,
+																iClientSocketServer));
+		if (err)
+			{
+			iServiceUser.GAVDP_Error(err, KNullDesC8);
+			}
+		else
+			{
+			iRequesterHelper->Begin();	
+			}
+		}
+	else
+		{
+		iServiceUser.GAVDP_Error(err, KNullDesC8);
+		}
+	return err;	
+	}
+
+
+inline TBool CGavdp::CheckSEID(TSEID aSEID)
+	{
+	TBool ok = aSEID.IsValid();
+	__ASSERT_ALWAYS(ok, Panic(EGavdpUserSuppliedBadSEID));
+	return ok;
+	}
+	
+
+TInt CGavdp::Shutdown()
+	{
+	Cancel();
+	iState=EIdle;
+	return AvdtpRequester().SetOpt(EShutdown, KSolBtAVDTPSignalling, NULL);
+	}