diff -r 000000000000 -r 29b1cd4cb562 bluetooth/gavdp/source/gavdpImp.cpp --- /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 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 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 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(aResponseData); + } + + TPckg 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(aResponseData), aResponseDataLen); + } + + TPckg 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 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 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 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); + }