--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avdtp/avdtpSignallingSession.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1837 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implements the avdtp signalling session
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include "avdtpSignallingSession.h"
+#include "avdtpSignallingChannel.h"
+#include "avdtp.h"
+#include "avdtpsap.h"
+#include "avdtpStream.h"
+#include "avdtpLogicalChannelFactory.h"
+#include "avdtpConfigurators.h"
+#include "avdtputil.h"
+#include "avdtpDirectChannel.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVDTP);
+#endif
+
+#ifdef _DEBUG
+PANICCATEGORY("avdtpsigse");
+#endif
+
+CSignallingSession* CSignallingSession::NewLC(CAvdtpProtocol& aProtocol, CAvdtpSAP& aSAP)
+ {
+ LOG_STATIC_FUNC
+ CSignallingSession* s = new (ELeave) CSignallingSession(aProtocol, aSAP);
+ CleanupStack::PushL(s);
+ s->ConstructL();
+ return s;
+ }
+
+CSignallingSession* CSignallingSession::NewL(CAvdtpProtocol& aProtocol, CAvdtpSAP& aSAP)
+ {
+ LOG_STATIC_FUNC
+ CSignallingSession* s = CSignallingSession::NewLC(aProtocol, aSAP);
+ CleanupStack::Pop();
+ return s;
+ }
+
+CSignallingSession::CSignallingSession(CAvdtpProtocol& aProtocol, CAvdtpSAP& aSAP)
+: CTransportSession(aProtocol, aSAP, ESignalling),
+ iLocalSEPs(_FOFF(CLocalSEP, iSignallingSessionLink))
+ {
+ LOG_FUNC
+ }
+
+CSignallingSession::~CSignallingSession()
+ {
+ LOG_FUNC
+ DestroyLocalSEPs();
+ ClearSignallingChannel();
+ delete iSEPConfigurator;
+ }
+
+
+void CSignallingSession::ConstructL()
+ {
+ LOG_FUNC
+ CTransportSession::ConstructL();
+ }
+
+TInt CSignallingSession::ActiveOpen()
+ {
+ LOG_FUNC
+ // esock will protect us from an accidental double connect
+ TInt ret = KErrNone;
+ if (iSignallingChannel)
+ {
+ if (!iSignallingChannel->IsListening())
+ {
+ // already got a suitable SC - probably due to a passive connection
+ // just say it's done (we're already attached)
+ iSAP.Ready();
+ }
+ else
+ {
+ // signalling channel is listening - detach from it, user has decided to connect
+ // drop through afterwards
+ ClearSignallingChannel();
+ }
+ }
+ // not else as ClearSignallingChannel will NULL iSignallingChannel
+ if (!iSignallingChannel)
+ {
+ iSignallingChannel = iProtocol.GetSignallingChannel(RemoteAddress());
+ if (iSignallingChannel)
+ {
+ ret = iSignallingChannel->AttachSignallingUser(*this);
+ }
+ else
+ {
+ ret = KErrNoMemory;
+ }
+ }
+
+ return ret;
+ }
+
+void CSignallingSession::ClearSignallingChannel()
+ {
+ LOG_FUNC
+ if (iSignallingChannel)
+ {
+ iSignallingChannel->DetachSignallingUser(*this);
+ }
+ iSignallingChannel = NULL;
+ }
+
+void CSignallingSession::DestroyLocalSEPs()
+ {
+ LOG_FUNC
+ while (!iLocalSEPs.IsEmpty())
+ {
+ CLocalSEP* sep = iLocalSEPs.First();
+ sep->iSignallingSessionLink.Deque();
+ // inform codman - it'll clear bits as necessary since it reference coutns
+ iProtocol.CodMan().RemoveCodService(sep->Info().IsSink() ? EMajorServiceRendering :
+ EMajorServiceCapturing);
+ delete sep;
+ }
+ }
+
+void CSignallingSession::DoShutdown()
+ {
+ LOG_FUNC
+
+ TDblQueIter<CLocalSEP> iter(iLocalSEPs);
+ while(iter)
+ {
+ iter++->SetInUse(EFalse);
+ }
+
+ ClearSignallingChannel();
+
+ if (iSAPShutdown == ENormal)
+ {
+ iSAP.CanClose();
+ }
+ else
+ {
+ // base class has detached us so that we own ourselves
+ // nothing more to do, apart from die.
+ delete this;
+ }
+ }
+
+TInt CSignallingSession::Send(RMBufChain& /*aData*/, TUint /*aOptions*/, TSockAddr* /*aAddr*/)
+ {
+ LOG_FUNC
+ // not supported in signalling - only ioctls and opts allowed
+ return 0;
+ }
+
+TInt CSignallingSession::GetData(RMBufChain& /*aData*/)
+ {
+ LOG_FUNC
+ return KErrNotSupported;
+ }
+
+// stuff forwarded from SAP
+TInt CSignallingSession::SetOption(TUint aLevel, TUint aName, const TDesC8 &aOption)
+ {
+ LOG_FUNC
+ TInt ret = KErrNotSupported;
+
+ if (aLevel == KSolBtAVDTPSignalling)
+ {
+ switch (aName)
+ {
+ case EAwaitPassiveSignallingChannel:
+ {
+ if (iIsListening && iSignallingChannel && iSignallingChannel->IsListening())
+ {
+ ret = KErrAlreadyExists;
+ }
+ else if (iSignallingChannel && !iSignallingChannel->IsListening())
+ {
+ ret = KErrInUse;
+ }
+ else
+ {
+ iSignallingChannel=iProtocol.FindListeningSignallingChannel();
+ // For ACP - triggered when client is ready for listening
+ // (would be nice to be "automatic", but needs client to be happy they've registered all their seps
+ if (!iSignallingChannel)
+ {
+ iSignallingChannel = iProtocol.CreateSignallingChannelForListening();
+ }
+
+ if (iSignallingChannel)
+ {
+ ASSERT_DEBUG(iSignallingChannel->IsListening());
+ ret = iSignallingChannel->AttachSignallingUser(*this);
+ if (ret == KErrNone)
+ {
+ iIsListening = ETrue;
+ }
+ else
+ {
+ // if we didn't manage to tell anyone else
+ // then no one else knows so actually we're best
+ // off cleaning up after ourselves.
+ iSignallingChannel->DetachSignallingUser(*this);
+ iSignallingChannel = NULL;
+ }
+ }
+ else
+ {
+ ret = KErrNoMemory;
+ }
+ }
+ break;
+ }
+
+ case EStopAwaitPassiveSignallingChannel:
+ {
+ if (!iSignallingChannel)
+ {
+ ret = KErrNotReady;
+ }
+
+ else
+ {
+ iIsListening = EFalse;
+ ClearSignallingChannel();
+ }
+ break;
+ }
+
+ // also for reconfigure - the configurator decides
+ case EStartConfiguringRemote:
+ {
+ if (iSEPConfigurator)
+ {
+ ret = KErrInUse;
+ }
+ else
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TInternalSelectRemoteSEP))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ // get Remote SEID we're configuring, and the binding local SEP SEID
+ // avdtp spec makes us have to do the binding now
+ TInternalSelectRemoteSEP select = *reinterpret_cast<const TInternalSelectRemoteSEP*>(aOption.Ptr());
+
+ if (!select.iLocalSEID.IsLocal())
+ {
+ ret = KErrArgument;
+ }
+ else
+ {
+ CLocalSEP* localSEP = FindLocalSEP(select.iLocalSEID);
+ if (!localSEP)
+ {
+ // client supplied bad SEID
+ ret = KErrArgument;
+ }
+ else
+ {
+ // don't support reconfiguring of an active stream - client must suspend
+ CAVStream* stream = localSEP->Stream();
+ if (stream && stream->IsStreaming())
+ {
+ ret = KErrInUse;
+ }
+ else
+ {
+ TRAP(ret, iSEPConfigurator = CRemoteSEPConfigurator::NewL(*this,
+ iProtocol,
+ select.iLocalSEID,
+ select.iRemoteSEID,
+ stream ? ETrue : EFalse));
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ case EStartConfiguringLocal:
+ {
+ if (iSEPConfigurator)
+ {
+ ret = KErrInUse;
+ }
+ else
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TSEID))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ // get Local SEID we're configuring
+ TSEID localseid = *reinterpret_cast<const TSEID*>(aOption.Ptr());
+ TRAP(ret, iSEPConfigurator = CLocalSEPConfigurator::NewL(*this, iProtocol, localseid));
+ }
+ }
+ break;
+ }
+
+ case EAddCapabilitySelection:
+ {
+ if (iSEPConfigurator)
+ {
+ ret = iSEPConfigurator->AddCapability(aOption);
+ }
+ else
+ {
+ ret = KErrNotReady;
+ }
+ break;
+ }
+
+ case ESendConfigurationResponse:
+ {
+ if (iSignallingChannel)
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TAvdtpInternalConfigurationResponse))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ const TAvdtpInternalConfigurationResponse rsp = *reinterpret_cast<const TAvdtpInternalConfigurationResponse*>(aOption.Ptr());
+ // check SEID is ok
+ CLocalSEP* sep = FindLocalSEP(rsp.iSEID);
+ if (sep)
+ {
+ // need to tell sep of the outcome so it can clear its state
+ // this needs to occur for config and reconfig
+ // first param is true if result is kerrnone- i.e. all ok, false otherwise
+ TRAP(ret, sep->CommitPendingConfigurationL(rsp.iResult == KErrNone,rsp.iIsReconfigure));
+ if (!rsp.iIsReconfigure)
+ {
+ if (rsp.iResult == KErrNone)
+ {
+ if (ret==KErrNone)
+ {
+ ret = iSignallingChannel->SendSetConfigurationAccept(rsp.iTransactionLabel);
+ if (ret==KErrNone)
+ {
+ // time to spawn that (ACP) stream
+ TRAP(ret, sep->ExpectStreamL(RemoteAddress(), *this, iProtocol));
+ }
+ }
+ }
+ else
+ {
+ ret = iSignallingChannel->SendSetConfigurationReject(rsp.iTransactionLabel,
+ AvdtpInternalUtils::SymbianErrorToAvdtpError(rsp.iResult),
+ rsp.iCategory);
+ }
+ }
+ else
+ {
+ if (!sep->InUse())
+ {
+ // almost assertable since we shouldnt have forwarded the indication if not
+ // but we don't want a DoS if bad client
+ ret = KErrNotReady;
+ }
+ else
+ {
+ if (rsp.iResult == KErrNone)
+ {
+ ret = iSignallingChannel->SendReconfigureAccept(rsp.iTransactionLabel);
+ }
+ else
+ {
+ ret = iSignallingChannel->SendReconfigureReject(rsp.iTransactionLabel,
+ AvdtpInternalUtils::SymbianErrorToAvdtpError(rsp.iResult),
+ rsp.iCategory);
+ }
+ }
+ }
+ if (ret==KErrNone && rsp.iResult == KErrNone && !rsp.iIsReconfigure)
+ {
+ // now in use, and from AVDTP spec sect6.3 we now do not expect other transactions until stream started
+ // not point resetting for reconfigure
+ sep->SetInUse(ETrue);
+ }
+ }
+ else
+ {
+ ret = KErrArgument;
+ }
+ }
+ }
+ else
+ {
+ ret = KErrDisconnected;
+ }
+ break;
+ }
+
+ case ESendStartResponse:
+ {
+ if (iSignallingChannel)
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TAvdtpInternalStartResponse))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ const TAvdtpInternalStartResponse rsp = *reinterpret_cast<const TAvdtpInternalStartResponse*>(aOption.Ptr());
+ // check SEID is ok
+ CLocalSEP* sep = FindLocalSEP(rsp.iSEID);
+
+ if (sep && sep->Stream() && rsp.iResult == KErrNone)
+ {
+ ret = iSignallingChannel->SendStartAccept(rsp.iTransactionLabel);
+ if (ret==KErrNone)
+ {
+ sep->Stream()->Started();
+ }
+ }
+ else if (sep && !(sep->Stream()))
+ {
+ ret = KErrUnknown;
+ }
+ else if (sep)
+ {
+ // The AVDTP error code (spec... ACP to INT error code table) is offset by -18045
+ ret = iSignallingChannel->SendStartReject(rsp.iTransactionLabel, AvdtpInternalUtils::SymbianErrorToAvdtpError(rsp.iResult), rsp.iSEID);
+ }
+ else
+ {
+ ret = KErrArgument;
+ }
+ }
+ }
+ else
+ {
+ ret = KErrDisconnected;
+ }
+ break;
+ }
+ case ESendSuspendResponse:
+ {
+ if (iSignallingChannel)
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TAvdtpInternalSuspendResponse))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ const TAvdtpInternalSuspendResponse rsp = *reinterpret_cast<const TAvdtpInternalSuspendResponse*>(aOption.Ptr());
+ // check SEID is ok
+ CLocalSEP* sep = FindLocalSEP(rsp.iSEID);
+ if (sep && sep->Stream() && rsp.iResult == KErrNone)
+ {
+ ret = iSignallingChannel->SendSuspendAccept(rsp.iTransactionLabel);
+ if (ret==KErrNone)
+ {
+ sep->Stream()->Suspended();
+ }
+ }
+ else if (sep && !(sep->Stream()))
+ {
+ ret = KErrUnknown;
+ }
+ else if (sep)
+ {
+ // The AVDTP error code (spec... ACP to INT error code table) is offset by -18045
+ ret = iSignallingChannel->SendSuspendReject(rsp.iTransactionLabel, AvdtpInternalUtils::SymbianErrorToAvdtpError(rsp.iResult), rsp.iSEID);
+ }
+ else
+ {
+ ret = KErrArgument;
+ }
+ }
+ }
+ else
+ {
+ ret = KErrDisconnected;
+ }
+ break;
+ }
+ case ESendSecurityControlResponse:
+ {
+ if (iSignallingChannel)
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TAvdtpInternalSecurityControlResponse))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ const TAvdtpInternalSecurityControlResponse secRsp = *reinterpret_cast<const TAvdtpInternalSecurityControlResponse*>(aOption.Ptr());
+ // check SEID is ok
+ CLocalSEP* sep = FindLocalSEP(secRsp.iSEID);
+ if (!sep)
+ {
+ ret = KErrArgument;
+ }
+ else
+ {
+ if(secRsp.iResult == KErrNone)
+ {
+ const TDesC8* rspInfo = secRsp.iSecurityControlInfo.Length() ? &secRsp.iSecurityControlInfo : NULL;
+ ret = iSignallingChannel->SendSecurityControlAccept(secRsp.iTransactionLabel, rspInfo);
+ }
+ else
+ {
+ ret = iSignallingChannel->SendSecurityControlReject(secRsp.iTransactionLabel,
+ AvdtpInternalUtils::SymbianErrorToAvdtpError(secRsp.iResult));
+ }
+ }
+ }
+ }
+ else
+ {
+ ret = KErrDisconnected;
+ }
+ break;
+ }
+ case EShutdown:
+ {
+ ret=KErrNone;
+ TDblQueIter<CLocalSEP> iter(iLocalSEPs);
+ while(iter)
+ {
+ if (iter++->Stream())
+ {
+ ret=KErrNotReady;
+ }
+ }
+ if (ret==KErrNone)
+ {
+ iter.SetToFirst();
+ while(iter)
+ {
+ iter++->SetInUse(EFalse);
+ }
+
+ ClearSignallingChannel();
+ iSAP.SessionDisconnect();
+ }
+ break;
+ }
+ }
+ }
+ return ret;
+ }
+
+
+
+void CSignallingSession::Ioctl(TUint aLevel, TUint aName, const TDesC8* aOption)
+ {
+ LOG_FUNC
+ TInt res = KErrNotSupported;
+
+ if (aLevel == KSolBtAVDTPSignalling)
+ {
+ const TUint8* optionPtr=NULL;
+ if (aOption)
+ {
+ optionPtr = aOption->Ptr();
+ }
+
+ switch (aName)
+ {
+ case EDiscoverSEPs:
+ {
+ res=iSignallingChannel ? iSignallingChannel->SendDiscoverSEPs(*this) : KErrNotReady;
+ break;
+ }
+ case EGetCapabilities:
+ {
+ // Check the integrity of the descriptor
+ if (!optionPtr || aOption->Length() != sizeof(TSEID))
+ {
+ res = KErrBadDescriptor;
+ }
+ else
+ {
+ TSEID seid = *reinterpret_cast<const TSEID*>(optionPtr);
+
+ if (seid.IsLocal())
+ {
+ // meaningless to try to associate with a remote sep at this stage
+ // getting local capabilities not supported
+ res = KErrArgument;
+ }
+ else
+ {
+ // client doesn't need to have populated remote sep cache at this point, so just try to send
+ res=iSignallingChannel ? iSignallingChannel->SendGetCapabilities(*this, seid) : KErrNotReady;
+ }
+ }
+ break;
+ }
+ case EAbortStream:
+ {
+ // Check the integrity of the descriptor
+ if (!optionPtr || aOption->Length() != sizeof(TSEID))
+ {
+ res = KErrBadDescriptor;
+ }
+ else
+ {
+ res = KErrNone;
+ // check seid exists
+ const TSEID& seid = *reinterpret_cast<const TSEID*>(optionPtr);
+ TSEID packetSeid;
+
+ if (seid.IsLocal())
+ {
+ CLocalSEP* sep = FindLocalSEP(seid);
+ // check local sep exists
+ if (!sep || !(sep->Stream()))
+ {
+ res = KErrArgument;
+ }
+ else
+ {
+ packetSeid = sep->Stream()->RemoteSEID();
+ }
+ }
+ else
+ {
+ // remote was specified - again, check it'ok
+ if (!FindStreamFromRemoteSEID(seid))
+ {
+ res = KErrArgument;
+ }
+ else
+ {
+ packetSeid = seid;
+ }
+ }
+ if (res==KErrNone)
+ {
+ res = SendAbort(packetSeid);
+ }
+ }
+ break;
+ }
+ case ESelectSEP:
+ {
+ if (iSEPConfigurator)
+ {
+ TInt cfgRes = iSEPConfigurator->Finalise();
+ // user doesn't need to know whether we sync or async
+ res = cfgRes == KRequestPending ? KErrNone : cfgRes;
+ if (cfgRes==KErrNone)
+ {
+ // can complete the service now
+ iSAP.ServiceComplete(NULL);
+ }
+ delete iSEPConfigurator;
+ iSEPConfigurator = NULL;
+ }
+ else
+ {
+ res = KErrNotReady;
+ }
+ break;
+ }
+ case EStartStreaming:
+ {
+ if (iSignallingChannel==NULL)
+ {
+ res = KErrNotReady;
+ }
+ else
+ {
+ // Check the integrity of the descriptor
+ if (!optionPtr || aOption->Length() != sizeof(TSEID))
+ {
+ res = KErrBadDescriptor;
+ }
+ else
+ {
+ const TSEID& clientSeid = *reinterpret_cast<const TSEID*>(optionPtr);
+
+ // see whether it was a local or remote seid - either is ok
+ CAVStream* stream = NULL;
+
+ if (clientSeid.IsLocal())
+ {
+ CLocalSEP* sep = FindLocalSEP(clientSeid);
+ if (sep)
+ {
+ stream = sep->Stream();
+ }
+ }
+ else
+ {
+ // client supplied remote seid so just check
+ stream = FindStreamFromRemoteSEID(clientSeid);
+ }
+ res = stream ? stream->Start() : KErrUnknown;
+ }
+ }
+ break;
+ }
+ case ESuspendStreaming:
+ {
+ if (iSignallingChannel==NULL)
+ {
+ res = KErrNotReady;
+ }
+ else
+ {
+ // Check the integrity of the descriptor
+ if (!optionPtr || aOption->Length() != sizeof(TSEID))
+ {
+ res = KErrBadDescriptor;
+ }
+ else
+ {
+ const TSEID& clientSeid = *reinterpret_cast<const TSEID*>(optionPtr);
+ // see whether it was a local or remote seid - either is ok
+ CAVStream* stream = NULL;
+
+ if (clientSeid.IsLocal())
+ {
+ CLocalSEP* sep = FindLocalSEP(clientSeid);
+ if (sep)
+ {
+ stream = sep->Stream();
+ }
+ }
+ else
+ {
+ // client supplied remote seid so just check
+ stream = FindStreamFromRemoteSEID(clientSeid);
+ }
+ res = stream ? stream->Suspend() : KErrUnknown;
+ }
+ }
+ break;
+ }
+ case ESendSecurityControl:
+ {
+ //GAVDP is wishing to send security control command (allowed any time if capable)
+ // needs to be remote
+ // Check the integrity of the descriptor
+ if (!optionPtr || aOption->Length() != sizeof(TAvdtpInternalSendSecurityControl))
+ {
+ res = KErrBadDescriptor;
+ }
+ else
+ {
+ const TAvdtpInternalSendSecurityControl& security = *reinterpret_cast<const TAvdtpInternalSendSecurityControl*>(optionPtr);
+ if (!security.iRemoteSEID.IsLocal())
+ {
+ // check capability
+ if (iSignallingChannel)
+ {
+ if (iProtocol.RemoteSEPCache().HasCapability(RemoteAddress(),
+ security.iRemoteSEID,
+ EServiceCategoryContentProtection))
+ {
+ res = iSignallingChannel->SendSecurityControl(*this,
+ security.iRemoteSEID,
+ security.iSecurityControlInfo);
+ }
+ else
+ {
+ // remote doesnt support CP
+ res = KErrNotSupported;
+ }
+ }
+ else
+ {
+ res = KErrNotReady;
+ }
+ }
+ else
+ {
+ res = KErrArgument;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ res = KErrNotSupported;
+ }
+ }
+ if (res!=KErrNone)
+ {
+ iSAP.Error(res);
+ }
+ }
+ }
+
+#ifdef _DEBUG
+void CSignallingSession::CancelIoctl(TUint aLevel, TUint /*aName*/)
+#else
+void CSignallingSession::CancelIoctl(TUint /*aLevel*/, TUint /*aName*/)
+#endif
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aLevel==KSolBtAVDTPSignalling, Panic(EAvdtpBadIoctl));
+ // none at present
+ }
+
+
+TInt CSignallingSession::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const
+ {
+ LOG_FUNC
+ TInt ret = KErrNotSupported;
+
+ if (aLevel == KSolBtAVDTPSignalling)
+ {
+ switch (aName)
+ {
+ case EGetProposedConfiguration:
+ {
+ // Check the integrity of the descriptor. The option length is variable, subject to the payload length.
+ if (!aOption.Ptr() || aOption.Length() < sizeof(TInternalGetProposedConfiguration))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ TInternalGetProposedConfiguration& conf = *const_cast<TInternalGetProposedConfiguration*>(reinterpret_cast<const TInternalGetProposedConfiguration*>(aOption.Ptr()));
+ CLocalSEP* s = FindLocalSEP(conf.iSEID);
+ if (s)
+ {
+ // Check that the option buffer size is sufficient
+ TPtrC8 pendingConf(s->PendingConfiguration());
+ if (aOption.MaxLength() < pendingConf.Length())
+ {
+ ret = KErrUnderflow;
+ }
+ else
+ {
+ // would be nice to use a return struct
+ // but gets tricky - we don't know how big the option is
+ // so can't use TBuf. TPtr falls foul of IPC.
+ aOption.Copy(pendingConf);
+ ret = KErrNone;
+ }
+ }
+ else
+ {
+ ret = KErrArgument;
+ }
+ }
+ break;
+ }
+
+ case EGetSecurityControl:
+ {
+ // Check the integrity of the descriptor. The option length is variable, subject to the payload length.
+ if (!aOption.Ptr() || aOption.Length() < sizeof(TInternalGetSecurityControl))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ TInternalGetSecurityControl& sec = *const_cast<TInternalGetSecurityControl*>(reinterpret_cast<const TInternalGetSecurityControl*>(aOption.Ptr()));
+ CLocalSEP* s = FindLocalSEP(sec.iSEID);
+ if (s)
+ {
+ // Check that the option buffer size is sufficient
+ TPtrC8 securityData(s->SecurityControl());
+ if (aOption.MaxLength() < securityData.Length())
+ {
+ ret = KErrUnderflow;
+ }
+ else
+ {
+ aOption.Copy(securityData);
+ ret = KErrNone;
+ }
+ }
+ else
+ {
+ ret = KErrArgument;
+ }
+ }
+ break;
+ }
+ case EGetAVDTPCapabilityResponse:
+ {
+ // Check the integrity of the descriptor. The option length is variable, subject to the payload length.
+ if (!aOption.Ptr() || aOption.Length() < sizeof(TInternalGetSEPCapability))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ TInternalGetSEPCapability cap = *reinterpret_cast<const TInternalGetSEPCapability*>(aOption.Ptr());
+ TPtrC8 ptr;
+ // get the required capability from the SEP cache (in 'air' form)
+ TRAP(ret, ptr.Set(iProtocol.RemoteSEPCache().GetCapabilityL(
+ RemoteAddress(),
+ cap.iSEID,
+ cap.iServiceCategory));)
+
+ if (ret==KErrNone)
+ {
+ // Check that the option buffer size is sufficient
+ if (aOption.MaxLength() < ptr.Length())
+ {
+ ret = KErrUnderflow;
+ }
+ else
+ {
+ aOption.Copy(ptr);
+ }
+ }
+ }
+ break;
+ }
+
+ case ERegisterSEP:
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TAvdtpSEPInfo))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ TAvdtpSEPInfo info = *reinterpret_cast<const TAvdtpSEPInfo*>(aOption.Ptr());
+ // client doesn't manage inUse field - we do
+ info.SetInUse(EFalse);
+
+ TRAP(ret, const_cast<CSignallingSession*>(this)->CreateLocalSEPL(info));
+
+ TPckg<TAvdtpSEPInfo> pckg(info);
+ aOption.Copy(pckg);
+ }
+ break;
+ }
+
+ case EGetReportingAndRecoveryConfig:
+ {
+ // Check the integrity of the descriptor
+ if (!aOption.Ptr() || aOption.Length() != sizeof(TReportingAndRecovery))
+ {
+ ret = KErrBadDescriptor;
+ }
+ else
+ {
+ TReportingAndRecovery rar;
+ TPckg<TReportingAndRecovery> rarBuf(rar);
+ rarBuf.Copy(aOption);
+ CAVStream* stream = FindStreamFromRemoteSEID(rar.iSEID);
+ if(stream == NULL)
+ {
+ ret = KErrNotFound;
+ }
+ else
+ {
+ rar.iReporting = stream->CheckConfigured(EServiceCategoryReporting);
+ rar.iRecovery = stream->CheckConfigured(EServiceCategoryRecovery);
+ aOption.Copy(rarBuf);
+ ret = KErrNone;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+
+
+TInt CSignallingSession::OpenIndication(TSEID aSEID)
+ {
+ LOG_FUNC
+ // now create the full Stream Object
+ CLocalSEP* sep = FindLocalSEP(aSEID);
+ if (sep && sep->Stream())
+ {
+ // this will tell channel factory to expect n channels on sending resp
+ TRAPD(err, sep->Stream()->AwaitLogicalChannelsL());
+ return err;
+ }
+ else if (sep && !sep->Stream())
+ {
+ // the remote must have decided that a GetConfig yielded just what they wanted
+ // and have proceeded directly with Open
+ // this *violates* GAVDP - see p 16
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+
+TInt CSignallingSession::DiscoverIndication(TAvdtpTransactionLabel /*aLabel*/, CAvdtpOutboundSignallingMessage& aDiscoverResponseMessage)
+ {
+ LOG_FUNC
+ // iterate over all idle SEPs returning their capabilities
+ // need to return the label back to the Signalling Channel to tie up response
+
+ // this is *far* easier if we process this synchronously
+ // otherwise the design is tricky - we'd need to call a primitive bacxk on SigCh
+ // and it would need to know our last SEP info etc
+ TDblQueIter<CLocalSEP> iter(iLocalSEPs);
+ CLocalSEP* sep;
+ while(iter)
+ {
+ sep = iter++;
+
+ TRAPD(overFlow, aDiscoverResponseMessage.AddSEPInfoL(sep->Info()));
+
+ if (overFlow)
+ {
+ // no more will go, try continuing with usecase though
+ // so NOT releaving - cos the message is ok
+ break;
+ }
+ }
+ return KErrNone;
+ }
+
+
+TInt CSignallingSession::GetCapsIndication(TAvdtpTransactionLabel /*aLabel*/,
+ TSEID aSEID,
+ CAvdtpOutboundSignallingMessage& aGetCapsResponseMessage)
+ {
+ LOG_FUNC
+ // client has set caps now - if they haven't then we will prob just send empty stuff back
+ // i.e. we send whatever we've got (but possibly "knowing" this fact
+
+ // find the idle SEP with aSEID
+ CLocalSEP* sep = FindLocalSEP(aSEID);
+ // this uses the same pattern as :DiscoverIndication
+ if (!sep)
+ {
+ return KErrNotFound;
+ }
+
+ TInt ret = KErrNone;
+
+ for (TInt i=0; i<sep->Capabilities().Count(); i++)
+ {
+ // one at a time - easier for us to cope if we OOM
+ if (sep->Capabilities()[i])
+ {
+ // local sep has capability
+ TRAPD(overFlow, aGetCapsResponseMessage.AddSEPCapabilityL(*sep->Capabilities()[i]));
+ if (overFlow)
+ {
+ // no more will go
+ // if even the first capability didn't go then we have to forget replying
+ if (i==0)
+ {
+ // there are no caps in the response, so it's meaningless
+ ret = KErrUnderflow;
+ }
+ // otherwise we can try continuing with usecase though
+ // so NOT erroring - cos the message is ok
+ break;
+ }
+ }
+
+ }
+ return ret;
+ }
+
+TInt CSignallingSession::SetConfigIndication(TAvdtpTransactionLabel aLabel,
+ TSEID aACPSEID,
+ TSEID aINTSEID,
+ RBuf8& aConfig)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+
+/*
+we check to see if the remote has (wrongly) set capabilities that the idle sep has not
+if the remote has then we reject the request
+else pass onto gavdp
+*/
+
+ CCapabilityNotAllowedVisitor* checker =
+ new CCapabilityNotAllowedVisitor(sep->Categories());
+
+ if (!checker)
+ {
+ return KErrNoMemory;
+ }
+
+ checker->Process(aConfig);
+
+ if (!checker->IsValid())
+ {
+ // signalling channel expects us to put the duff category in the aConfig
+ // take the first one (as suggested by spec)
+ TPckgBuf<TAvdtpServiceCategory> catBuf(checker->WrongCategory());
+ aConfig.Copy(catBuf);
+ delete checker;
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadServCategory);
+ }
+
+ delete checker;
+ checker = NULL;
+
+ // update the SEP to contain the pending configuration
+ // commited when gavdp says ok
+ TInt res = sep->SetPendingConfiguration(aConfig, EFalse); // transfers aConfig ownership
+ if (res==KErrNone)
+ {
+ sep->SetRemoteSEID(aINTSEID);
+
+ // all ok, so pass on an indication to GAVDP as they need to configure too
+ TInternalAvdtpConfigurationIndication ind;
+ ind.iIndication = EAvdtpSetConfiguration;
+ ind.iPayloadLength = aConfig.Length();
+ ind.iSEID = aACPSEID;
+ ind.iINTSEID = aINTSEID;
+ ind.iTransactionLabel = aLabel;
+
+ TPckg<TInternalAvdtpConfigurationIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+ }
+
+ return res;
+ }
+
+TInt CSignallingSession::GetConfigIndication(TAvdtpTransactionLabel /*aLabel*/, TSEID aLocalSEID,
+ CAvdtpOutboundSignallingMessage& aGetConfigResponseMessage)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aLocalSEID);
+
+ if (!sep)
+ {
+ return KErrNotFound;
+ }
+
+ // remote may not have sent SetConfiguration
+ if (sep->PreConfigured())
+ {
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+ }
+
+ TInt ret = KErrNone;
+
+ for (TInt i=0; i<sep->Configuration().Count(); i++)
+ {
+ // one at a time - easier for us to cope if we OOM
+ if (sep->Configuration()[i])
+ {
+ // local sep has capability
+ TRAPD(overFlow, aGetConfigResponseMessage.AddSEPCapabilityL(*sep->Configuration()[i]));
+ if (overFlow)
+ {
+ // no more will go
+ // if even the first capability didn't go then we have to forget replying
+ if (i==0)
+ {
+ // there are no caps in the response, so it's meaningless
+ ret = KErrUnderflow;
+ }
+ // otherwise we can try continuing with usecase though
+ // so NOT erroring - cos the message is ok
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+TInt CSignallingSession::ReconfigIndication(TAvdtpTransactionLabel aLabel,
+ TSEID aACPSEID,
+ RBuf8& aNewConfig)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+
+ if (!sep->Stream())
+ {
+ // remote has been bad
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+ }
+
+/*
+we check to see if the remote has (wrongly) set capabilities that the spec forbids
+see 8.10.1 avdtp sepc
+if the remote has then we reject the request
+else pass onto gavdp
+*/
+ TAvdtpServiceCategories allowed;
+ allowed.SetCapability(EServiceCategoryMediaCodec);
+ allowed.SetCapability(EServiceCategoryContentProtection);
+
+ CCapabilityNotAllowedVisitor* checker = new CCapabilityNotAllowedVisitor(allowed);
+
+ if (!checker)
+ {
+ return KErrNoMemory;
+ }
+
+ checker->Process(aNewConfig);
+
+ if (!checker->IsValid())
+ {
+ // signalling channel expects us to put the duff category in the aConfig
+ // take the first one (as suggested by spec)
+ TPckg<TUint8> catBuf(checker->WrongCategory());
+ aNewConfig.Copy(catBuf);
+ delete checker;
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpInvalidCapabilities);
+ }
+
+ delete checker;
+ checker = NULL;
+
+//take ownership of config buffer
+ TInt res = sep->SetPendingConfiguration(aNewConfig, ETrue);
+
+ if (res==KErrNone)
+ {
+ // all ok, so pass on an indication to GAVDP as they need to reconfigure too
+ TInternalAvdtpConfigurationIndication ind;
+ ind.iIndication = EAvdtpReconfigure;
+ ind.iPayloadLength = aNewConfig.Length();
+ ind.iSEID = aACPSEID;
+ // to give consistent API for Set and Re-configure , give the INT SEID again
+ ind.iINTSEID = sep->Stream()->RemoteSEID();
+
+ ind.iTransactionLabel = aLabel;
+
+ TPckg<TInternalAvdtpAirIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+ }
+
+ return res;
+ }
+
+/** Handle a Start Indication from remote.
+
+The decision about when to issue the start indication to the client is taken by
+the stream.
+
+@param aLabel The transaction label of the start command.
+@param aACPSEID The (local) seid referring to the stream to be started.
+*/
+TInt CSignallingSession::StartIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+
+ TInt err = KErrUnknown;
+ if (sep->Stream())
+ {
+ // If the stream is in a valid state it will call back to the sig session
+ // to cause the indication to be passed to the client.
+ err = sep->Stream()->StartIndication(aLabel, aACPSEID);
+ }
+
+ if(err == KErrNone)
+ {
+ return KErrNone;
+ }
+ else
+ {
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+ }
+ }
+
+TInt CSignallingSession::ReleaseIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+
+ if (sep->Stream())
+ {
+ // dont ask GAVDP to confirm
+ // we also know that if we have a stream it must be releaseable
+ (void)iSignallingChannel->SendReleaseAccept(aLabel);
+
+ sep->SetInUse(EFalse);
+
+ // We try and hand off the channels to be closed. This is because it is
+ // the responsibility of the INT to release these so we can't just
+ // shut them down straight away. We don't want to have to deal with the
+ // complication of funny stream states and clearup by leaving them with the
+ // stream once it's effectively dead. If it fails however, we just let the
+ // channels go away.
+ // This is only done for non-muxed streams, otherwise we just revert to
+ // closing the channels ourselves.
+#ifndef __SYMBIAN_AVDTP_HIDE_MUX
+#warning ("Release ACP channel release must be fixed for muxed case")
+#endif
+ if(!sep->MultiplexingConfigured())
+ {
+ // Take the channels from the stream to disconnect
+ // Note that although some of these may be the same CloseLogicalChannels will
+ // deal with correctly closing each channel once.
+ TFixedArray<CDirectChannel*, KAvdtpChannelArraySize> channels;
+ channels[0] = static_cast<CDirectChannel*>(sep->Stream()->iMediaBinding.iChannel);
+ channels[1] = static_cast<CDirectChannel*>(sep->Stream()->iReportingBinding.iChannel);
+ channels[2] = static_cast<CDirectChannel*>(sep->Stream()->iRecoveryBinding.iChannel);
+ TArray<CDirectChannel*> array = channels.Array();
+
+ TRAP_IGNORE(iProtocol.LogicalChannelFactory().CloseSessionLogicalChannelsL(array, KAvdtpACPReleaseChannelCloseTimeout));
+ }
+
+ // just error the stream - it will tell the user-plane sessions
+ // they'll then tell the user
+ // so , like open, we don't let user directly see this as an indication
+ DestroyStream(sep->Stream(), KErrDisconnected);
+
+ // all ok, so pass on an indication to GAVDP
+ TInternalAvdtpAirIndication ind;
+ ind.iIndication = EAvdtpRelease;
+ ind.iPayloadLength = 0;
+ ind.iSEID = aACPSEID;
+ ind.iTransactionLabel = aLabel; // not used
+
+ TPckg<TInternalAvdtpAirIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+
+ return KErrNone;
+ }
+ else
+ {
+ // remote is in bad state
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+ }
+ }
+
+TInt CSignallingSession::SuspendIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+
+ // check that we think stream suspendable
+ if (sep->Stream() && sep->Stream()->IsStreaming())
+ {
+ // all ok, so pass on an indication to GAVDP
+ TInternalAvdtpAirIndication ind;
+ ind.iIndication = EAvdtpSuspend;
+ ind.iPayloadLength = 0;
+ ind.iSEID = aACPSEID;
+ ind.iTransactionLabel = aLabel;
+
+ TPckg<TInternalAvdtpAirIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+ return KErrNone;
+ }
+ else
+ {
+ return SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadState);
+ }
+ }
+
+TInt CSignallingSession::AbortIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+ else
+ {
+ // tell the sep, stream, then the user (only if we have a stream though)
+ sep->SetInUse(EFalse);
+
+ if (sep->Stream())
+ {
+ DestroyStream(sep->Stream(),KErrAbort);
+ }
+ // Pass on an indication to GAVDP as they need to know too
+ TInternalAvdtpAirIndication ind;
+ ind.iIndication = EAvdtpAbort;
+ ind.iSEID = aACPSEID;
+ ind.iTransactionLabel = aLabel; // not that useful, client cant respond
+
+ TPckg<TInternalAvdtpAirIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+ }
+ return KErrNone;
+ }
+
+void CSignallingSession::AbortConfirm(TSEID aRemoteSEID)
+ {
+ LOG_FUNC
+ // tell client
+ CompleteBasicService(KErrNone);
+
+ // error stream associated with remote
+ CAVStream* stream = FindStreamFromRemoteSEID(aRemoteSEID);
+ if (stream)
+ {
+ DestroyStream(stream, KErrAbort);
+ }
+ }
+
+TInt CSignallingSession::SecurityControlIndication(TAvdtpTransactionLabel aLabel, TSEID aACPSEID, const HBufC8* aSecurityData)
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aACPSEID);
+
+ if (!sep)
+ {
+ // for a SEP not on this session
+ return KErrNotFound;
+ }
+ else
+ {
+ // pass ownership of HBuf to SEP
+ sep->SetSecurityControl(aSecurityData);
+
+ // all ok, so pass on an indication to GAVDP as they need to do the actual security control response
+ TInternalAvdtpAirIndication ind;
+ ind.iIndication = EAvdtpSecurityControl;
+ ind.iSEID = aACPSEID;
+ ind.iPayloadLength = aSecurityData->Length();
+ ind.iTransactionLabel = aLabel;
+
+ TPckg<TInternalAvdtpAirIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+
+ return KErrNone;
+ }
+ }
+
+void CSignallingSession::SecurityControlConfirm(TInt aResult, TSEID aRemoteSEID, const TDesC8& aResponseData)
+ {
+ LOG_FUNC
+ if (aResult==KErrNone)
+ {
+ TPckgBuf<TAvdtpInternalSendSecurityControl> securityControlPckgBuf;
+ securityControlPckgBuf().iRemoteSEID = aRemoteSEID;
+ securityControlPckgBuf().iSecurityControlInfo = aResponseData;
+ iSAP.ServiceComplete(&securityControlPckgBuf);
+ }
+ else
+ {
+ iSAP.Error(aResult);
+ }
+ }
+
+
+void CSignallingSession::DiscoverConfirm(TInt aResult, const TAvdtpInternalDiscoverConfirm* const aConfirm)
+ {
+ LOG_FUNC
+ if (aResult==KErrNone)
+ {
+ __ASSERT_DEBUG(aConfirm, Panic(EAvdtpSignallingSessionReceivedBadIndication));
+ //complete the client request with the number of SEPs
+ TPckgBuf<TAvdtpInternalDiscoverConfirm> buf(*aConfirm);
+ iSAP.ServiceComplete(&buf);
+ }
+ else
+ {
+ //either we were rejected by the peer or there was an internal
+ //error in the signalling channel
+ iSAP.Error(aResult);
+ }
+ }
+
+
+void CSignallingSession::GetCapsConfirm(TInt aResult, TSEID /*aRemoteSEID*/, TAvdtpServiceCatBitMask aSeen)
+ {
+ LOG_FUNC
+ if (aResult==KErrNone)
+ {
+ TPckgC<TAvdtpServiceCatBitMask> buf(aSeen);
+ iSAP.ServiceComplete(&buf);
+ }
+ else
+ {
+ iSAP.Error(aResult);
+ }
+ }
+
+void CSignallingSession::StreamStarted(TSEID aLocalSEID)
+ {
+ LOG_FUNC
+ if (FindLocalSEP(aLocalSEID))
+ {
+ // now tell client
+ CompleteBasicService(KErrNone);
+ }
+ }
+
+void CSignallingSession::StreamSuspended(TSEID aLocalSEID)
+ {
+ LOG_FUNC
+ if (FindLocalSEP(aLocalSEID))
+ {
+ // now tell client
+ CompleteBasicService(KErrNone);
+ }
+ }
+
+void CSignallingSession::StreamAccepted(TSEID aLocalSEID, TSEID aRemoteSEID, TBool aWithReporting, TBool aWithRecovery)
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aLocalSEID.IsLocal(), Panic(EAvdtpSEIDHasWrongDomain));
+ TInternalAvdtpStreamReadyIndication ind;
+ ind.iSEID = aLocalSEID;
+ ind.iRemoteSEID = aRemoteSEID;
+ ind.iReportingPresent = aWithReporting;
+ ind.iRecoveryPresent = aWithRecovery;
+ TPckg<TInternalAvdtpStreamReadyIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+ }
+
+void CSignallingSession::StreamConfigured(TSEID /*aLocalSEID*/, TInt aResult, TAvdtpServiceCategory aFailedCategory)
+ {
+ LOG_FUNC
+ // tell the user in all cases
+ TPckgBuf<TAvdtpConfigReject> rejDataBuf;
+ rejDataBuf().iError = aResult;
+ rejDataBuf().iFailedCategory = aFailedCategory;
+
+ // GAVDP will call back to client with Error upcall, so no need to error SAP
+ iSAP.ServiceComplete(&rejDataBuf);
+ }
+
+/*
+This callback is for the stream to inform gavdp of a failure in its state machine
+The signalling session SHALL NOT mutate the stream based on this; the stream should
+proceed, or die, or error in line with its present state and potential GAVDP recovery of that stream
+*/
+void CSignallingSession::StreamInitiatedServiceFailed(const CAVStream& /*aStream*/, TInt aError)
+ {
+ LOG_FUNC
+ ServiceError(aError);
+ }
+
+/**
+This should be called from the stream when it is ready for a start indication
+to be passed up to the client.
+*/
+void CSignallingSession::StreamReadyForStartIndication(const TAvdtpTransactionLabel aLabel, const TSEID aSeid)
+ {
+ LOG_FUNC
+
+ // pass on an indication to GAVDP
+ TInternalAvdtpAirIndication ind;
+ ind.iIndication = EAvdtpStart;
+ ind.iPayloadLength = 0;
+ ind.iSEID = aSeid;
+ ind.iTransactionLabel = aLabel;
+
+ TPckg<TInternalAvdtpAirIndication> indPckg(ind);
+
+ iSAP.Indication(indPckg);
+ }
+
+TInt CSignallingSession::SendAbort(TSEID aRemoteSEID)
+ {
+ LOG_FUNC
+ return iSignallingChannel ? iSignallingChannel->SendAbort(*this, aRemoteSEID) : KErrNotReady;
+ }
+
+/*inline*/void CSignallingSession::CompleteBasicService(TInt aErr)
+ {
+ LOG_FUNC
+ // basic services have no data to return
+ aErr ? iSAP.Error(aErr) : iSAP.ServiceComplete(NULL);
+ }
+
+
+/**
+Called as an INT - create the Stream object when we're setting configuration
+*/
+void CSignallingSession::DoConfigureStreamL(RBuf8& aConfigBuffer,
+ CLocalSEP& aLocalSEP,
+ TSEID aRemoteSEID,
+ TBool aReportingConfigured,
+ TBool aRecoveryConfigured)
+ {
+ LOG_FUNC
+
+ // check to see if SignallingChannel went down during configuration
+ if (iSignallingChannel)
+ {
+ TBool streamCreated = EFalse;
+
+ // if there is no stream then we create one now
+ // a stream would exist if this is a reconfigure
+ CAVStream* stream = FindStreamFromRemoteSEID(aRemoteSEID);
+ if (!stream)
+ {
+ TAvdtpSockAddr addr;
+ addr.SetBTAddr(RemoteAddress());
+ addr.SetSEID(aRemoteSEID);
+ stream = &aLocalSEP.CreateStreamL(addr, *this, iProtocol);
+
+ streamCreated = ETrue;
+ CleanupStack::PushL(stream);
+ }
+ else
+ {
+ __ASSERT_DEBUG(stream->RemoteSEID()==aRemoteSEID, Panic(EAvdtpSignallingSessionFoundWrongStream));
+ }
+
+ stream->SetConfigurationL(aConfigBuffer, *iSignallingChannel,
+ aReportingConfigured, aRecoveryConfigured);
+
+ if (streamCreated)
+ {
+ // SetConfigurationL ok, pop stream if we created one
+ CleanupStack::Pop();
+ }
+ }
+ else
+ {
+ User::Leave(KErrDisconnected);
+ }
+ }
+
+
+void CSignallingSession::CreateLocalSEPL(TAvdtpSEPInfo& aSEPInfo)
+ {
+ LOG_FUNC
+ // create an idle sep into queue for later discovery and selection
+ CLocalSEP* idleSEP = CLocalSEP::NewL(aSEPInfo, iProtocol.SEIDManager());
+ iLocalSEPs.AddFirst(*idleSEP);
+ // return the SEID to GAVDP via the reference paramter
+
+ // adjust the service class of CoD, using reference counting of codman
+ iProtocol.CodMan().RegisterCodService(aSEPInfo.IsSink() ? EMajorServiceRendering :
+ EMajorServiceCapturing);
+ }
+
+CLocalSEP* CSignallingSession::FindLocalSEP(TSEID aSEID) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(aSEID.IsLocal(), Panic(EAvdtpSEIDHasWrongDomain));
+ CLocalSEP* s = NULL;
+ TDblQueIter<CLocalSEP> iter(iLocalSEPs);
+
+ while (iter)
+ {
+ s = iter++;
+ if (s->SEID()==aSEID)
+ {
+ return s;
+ }
+ }
+ return NULL;
+ }
+
+
+CLocalSEP& CSignallingSession::FindLocalSEPL(TSEID aSEID) const
+ {
+ LOG_FUNC
+ CLocalSEP* sep = FindLocalSEP(aSEID);
+ if (!sep)
+ {
+ User::Leave(KErrNotFound);
+ }
+ return *sep;
+ }
+
+CAVStream* CSignallingSession::FindStreamFromRemoteSEID(const TSEID& aRemoteSEID) const
+ {
+ LOG_FUNC
+ __ASSERT_DEBUG(!aRemoteSEID.IsLocal(), Panic(EAvdtpSEIDHasWrongDomain));
+ TDblQueIter<CLocalSEP> iter(iLocalSEPs);
+
+ while (iter)
+ {
+ CAVStream* s = iter++->Stream();
+ if (s && s->RemoteSEID()==aRemoteSEID)
+ {
+ return s;
+ }
+ }
+ return NULL;
+ }
+
+void CSignallingSession::SignallingChannelError(TInt aError)
+ {
+ LOG_FUNC
+ // set all SEPs to be not in use
+ TDblQueIter<CLocalSEP> iter(iLocalSEPs);
+ while(iter)
+ {
+ CLocalSEP* sep = iter++;
+
+ sep->SetInUse(EFalse);
+ // need to inform sessions - so tell stream
+ if (sep->Stream())
+ {
+ DestroyStream(sep->Stream(),aError);
+ }
+ }
+ // leave the channel
+ ClearSignallingChannel();
+ // tell the user, on all channels
+ iSAP.Error(aError);
+ iSAP.SessionDisconnect();
+ TPckgBuf<TInternalAvdtpErrorIndication> error;
+ error().iError = aError;
+ iSAP.Indication(error);
+ }
+
+// sigsession has two error paths - one by being a channel user, and the other for protocol errors
+void CSignallingSession::ServiceError(TInt aError)
+ {
+ LOG_FUNC
+ iSAP.Error(aError);
+ }
+
+void CSignallingSession::SignallingChannelReady(CSignallingChannel& aNewChannel)
+ {
+ LOG_FUNC
+ // we may have migrated from old signalling channel to the new instance
+ // so cannot use old signalling channel pointer
+ iSignallingChannel = &aNewChannel;
+
+ SetRemoteAddress(aNewChannel.RemoteAddress());
+
+ if (iIsListening)
+ {
+ TInternalAvdtpSignallingReadyIndication ind;
+ ind.iBuf = aNewChannel.RemoteAddress().Des();
+
+ TPckg<TInternalAvdtpSignallingReadyIndication> indPckg(ind);
+ iSAP.Indication(indPckg);
+ iIsListening = EFalse;
+ }
+ else
+ {
+ iSAP.Ready();
+ }
+ }
+
+void CSignallingSession::DestroyStream(CAVStream* aStream, TInt aError)
+ {
+ // tell all sessions of the error
+ aStream->NotifyUserPlaneTransportSessionsError(NULL, aError);
+ // and remove the stream
+ delete aStream;
+ }
+
+CCapabilityNotAllowedVisitor::CCapabilityNotAllowedVisitor(TAvdtpServiceCategories aLocallySupported)
+: iLocallySupported(aLocallySupported), iIsValid(ETrue)
+ {
+ LOG_FUNC
+ }
+
+TBool CCapabilityNotAllowedVisitor::Capability(TAvdtpServiceCategory aCat)
+ {
+ LOG_FUNC
+ // need to put aCat into correct bit position
+ TAvdtpServiceCategories cat;
+ cat.SetCapability(aCat);
+
+ if ((cat() ^ iLocallySupported()) & cat())
+ {
+ // remote has wrongly used a cap we don't support, mark it as dud
+ iWrongCategory = aCat;
+ iIsValid = EFalse;
+ }
+ return iIsValid; // will therefore stop at first broken capability
+ }
+
+TBool CCapabilityNotAllowedVisitor::IsValid() const
+ {
+ LOG_FUNC
+ return iIsValid;
+ }
+
+TAvdtpServiceCategory CCapabilityNotAllowedVisitor::WrongCategory() const
+ {
+ LOG_FUNC
+ return iWrongCategory;
+ }
+