--- /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();
+ }