bluetooth/btstack/avdtp/avdtpsap.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements the code for AVDTP SAP
       
    15 // The SAP is really only a conduit to the socket
       
    16 // The sessions implement the meaningful protocol stuff
       
    17 // 
       
    18 //
       
    19 
       
    20 /**
       
    21  @file
       
    22  @internalComponent
       
    23 */
       
    24 
       
    25 #include <bluetooth/logger.h>
       
    26 #include "avdtpsap.h"
       
    27 #include "avdtp.h"
       
    28 #include "avdtpStream.h"
       
    29 #include "avdtpMediaSession.h"
       
    30 #include "avdtpReportingSession.h"
       
    31 #include "avdtpRecoverySession.h"
       
    32 #include "avdtpSignallingSession.h"
       
    33 #include "avdtputil.h"
       
    34 
       
    35 #ifdef __FLOG_ACTIVE
       
    36 _LIT8(KLogComponent, LOG_COMPONENT_AVDTP);
       
    37 #endif
       
    38 
       
    39 CAvdtpSAP* CAvdtpSAP::NewL(CAvdtpProtocol& aProt)
       
    40 /**
       
    41 Static AVDTP SAP factory function
       
    42 
       
    43   @internalComponent
       
    44   @leave KErrNoMemory if the SAP object could not be allocated
       
    45   @param aProt protocol object
       
    46   @return A pointer to the new SAP
       
    47 */
       
    48 	{
       
    49 	LOG_STATIC_FUNC
       
    50 	// Create and return a new SAP
       
    51 	CAvdtpSAP* sap = new(ELeave) CAvdtpSAP(aProt);
       
    52 	CleanupStack::PushL(sap);
       
    53 	sap->ConstructL();
       
    54 	CleanupStack::Pop(sap);
       
    55 	return sap;
       
    56 	}
       
    57 
       
    58 void CAvdtpSAP::ConstructL()
       
    59 /**
       
    60 Second-phase construction of a SAP
       
    61 
       
    62 Set up the async. callback.
       
    63 
       
    64   @internalComponent
       
    65 */
       
    66 	{
       
    67 	LOG_FUNC
       
    68 	CBluetoothSAP::ConstructL();
       
    69 	}
       
    70 
       
    71 CAvdtpSAP::CAvdtpSAP(CAvdtpProtocol& aProtocol)
       
    72 	: CBluetoothSAP(aProtocol.SecMan(), aProtocol.CodMan()),
       
    73 	  iProtocol(aProtocol),
       
    74 	  iIndicationQueue(_FOFF(HQueuedAvdtpIndication, iLink))
       
    75 /**
       
    76 Constructor for an AVDTP SAP
       
    77 
       
    78   @internalComponent
       
    79   @param aProt The AVDTP protocol object
       
    80 */
       
    81 	{
       
    82 	LOG_FUNC
       
    83 	}
       
    84 
       
    85 
       
    86 CAvdtpSAP::~CAvdtpSAP()
       
    87 /**
       
    88 Called when ESock deletes the SAP, when user app calls RSocket::Close()
       
    89 
       
    90   @internalAll
       
    91 */
       
    92 	{
       
    93 	LOG_FUNC
       
    94 	// clear (possible) indication queue
       
    95 	TSglQueIter<HQueuedAvdtpIndication> iter(iIndicationQueue);
       
    96 	while (iter)
       
    97 		{
       
    98 		delete iter++;
       
    99 		}
       
   100 	// at this point we don't support idling sessions
       
   101 	delete iSession;
       
   102 	}
       
   103 
       
   104 /**
       
   105 SetLocalName is here used to specify the *local* session to which this SAP will become attached
       
   106 As a part of this the SAP tries to tell the session of the stream with which it'll be associated
       
   107 The stream lookup key is the *remote* SEID of the stream (streams are always searched for by this SEID)
       
   108 This gives rise to an interesting API, but the intended client is only GAVDP
       
   109 (via ESOCK).
       
   110 So: the parts of AVDTPSockAddr for passive sides are
       
   111 BTAddr - not used
       
   112 SEID - specify the *remote* SEID
       
   113 Session - specify the *local* session type
       
   114 
       
   115 This *could* change if needs be, so that a conversion from local to remote is performed here
       
   116 but would be fiddly and break the ease of always looking for a stream by its remote SEID
       
   117 */
       
   118 TInt CAvdtpSAP::SetLocalName(TSockAddr& aAddr)
       
   119 	{
       
   120 	LOG_FUNC
       
   121 	// this determines our session
       
   122 	TRAPD(err, UpdateSessionL(TAvdtpSockAddr::Cast(aAddr)));
       
   123 	return err;
       
   124 	}
       
   125 
       
   126 void CAvdtpSAP::LocalName(TSockAddr& aAddr) const
       
   127 /**
       
   128 Read the Local Name into aAddr.
       
   129 
       
   130 
       
   131   @internalAll
       
   132   @param aAddr The address to read into
       
   133 */
       
   134 	{
       
   135 	LOG_FUNC
       
   136 	if (iSession)
       
   137 		{
       
   138 		TAvdtpSockAddr avAddr = TAvdtpSockAddr::Cast(aAddr);
       
   139 		iSession->LocalName(avAddr);
       
   140 		aAddr = avAddr;
       
   141 		}
       
   142 	}
       
   143 
       
   144 void CAvdtpSAP::RemName(TSockAddr& aAddr) const
       
   145 /**
       
   146 Read the remote name into aAddr.
       
   147 
       
   148   @internalAll
       
   149   @param aAddr The address to read into
       
   150 */
       
   151 	{
       
   152 	// Return the remote name
       
   153 	LOG_FUNC
       
   154 	if (iSession)
       
   155 		{
       
   156 		TAvdtpSockAddr avAddr = TAvdtpSockAddr::Cast(aAddr);
       
   157 		iSession->RemName(avAddr);
       
   158 		aAddr = avAddr;
       
   159 		}
       
   160 	}
       
   161 
       
   162 /**
       
   163 SetRemName is here used to specify the *remote* BTAddr, SEID and session to which this SAP will become attached
       
   164 As a part of this the SAP tries to tell the session of the stream with which it'll be associated
       
   165 The stream lookup key is the *remote* SEID of the stream (streams are always searched for by this SEID)
       
   166 This gives rise to an interesting API, but the intended client is only GAVDP
       
   167 (via ESOCK).
       
   168 So: the parts of AVDTPSockAddr for active sides are
       
   169 BTAddr - that of remote
       
   170 SEID - the remote SEID
       
   171 Session - specify the local/remote session type
       
   172 */
       
   173 TInt CAvdtpSAP::SetRemName(TSockAddr& aAddr)
       
   174 	{
       
   175 	LOG_FUNC
       
   176 	TRAPD(err, UpdateSessionL(TAvdtpSockAddr::Cast(aAddr)));
       
   177 	return err;
       
   178 	}
       
   179 	
       
   180 
       
   181 void CAvdtpSAP::UpdateSessionL(const TAvdtpSockAddr& aAddr)	
       
   182 	{
       
   183 	LOG_FUNC
       
   184 	
       
   185 	// do we want to support swapping session type? for now no
       
   186 	if (!iSession)
       
   187 		{
       
   188 		// need to get one
       
   189 		// get to see our TransportSession here
       
   190 		TAvdtpTransportSessionType s = aAddr.Session();
       
   191 		CAVStream* stream = NULL; //non-owned
       
   192 		if (s!=ESignalling)
       
   193 			{
       
   194 			stream = iProtocol.FindStream(aAddr);
       
   195 			if (!stream)
       
   196 				{
       
   197 				User::Leave(KErrUnknown);
       
   198 				}
       
   199 			}
       
   200 			
       
   201 		switch (s)
       
   202 			{
       
   203 			case EMedia:
       
   204 				iSession = CMediaSession::NewL(iProtocol, *this, *stream);
       
   205 				break;
       
   206 			case EReporting:
       
   207 				iSession = CReportingSession::NewL(iProtocol, *this, *stream);
       
   208 				break;
       
   209 			case ERecovery:
       
   210 				iSession = CRecoverySession::NewL(iProtocol, *this, *stream);
       
   211 				break;
       
   212 			case ESignalling:
       
   213 				iSession = CSignallingSession::NewL(iProtocol, *this);
       
   214 				break;
       
   215 			default:
       
   216 				User::Leave(KErrArgument);
       
   217 			}
       
   218 		}
       
   219 		
       
   220 	// update the device address (the session may go from passive to active)
       
   221 	iSession->SetRemoteAddress(aAddr.BTAddr());	// session cannot change type
       
   222 	}
       
   223 
       
   224 void CAvdtpSAP::AutoBind()
       
   225 /**
       
   226 Auto bind from ESock.
       
   227 
       
   228 @internalComponent
       
   229 */
       
   230 	{
       
   231 	LOG_FUNC
       
   232 	}
       
   233 
       
   234 TInt CAvdtpSAP::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const
       
   235 /**
       
   236 Get a socket option.
       
   237 
       
   238 Currently, just for getting the results of an AVDTP operation to user-land
       
   239 
       
   240 
       
   241   @internalAll
       
   242   @param aLevel The socket option level
       
   243   @param aName The socket option name
       
   244   @param aOption The socket option data
       
   245 */
       
   246 	{
       
   247 	// Do a getopt
       
   248 	LOG_FUNC
       
   249 	return iSession ? iSession->GetOption(aLevel, aName, aOption) : KErrNotReady;
       
   250 	}
       
   251 
       
   252 	
       
   253 TInt CAvdtpSAP::SAPSetOption(TUint aLevel, TUint aName, const TDesC8& aOption)
       
   254 /**
       
   255 Set a socket option.
       
   256 
       
   257   @internalAll
       
   258   @param aLevel The socket option level
       
   259   @param aName The socket option name
       
   260   @param aOption The socket option data
       
   261 */
       
   262 	{
       
   263 	// Perform a setopt
       
   264 	LOG_FUNC
       
   265 	TInt ret = KErrNotSupported;
       
   266 	// if this is not an internal option then pass to the session
       
   267 	if (aLevel == KSolBtAVDTPInternal)
       
   268 		{
       
   269 		switch (aName)
       
   270 			{				
       
   271 			case ESetAsSecondarySAP:
       
   272 				{
       
   273 				// assert we haven't had an address set
       
   274 				__ASSERT_DEBUG(iRemoteDev == TBTDevAddr(0), Panic(ERGAVDPSequenceFailure));
       
   275 				// this SAP does not have a session, nor an addr
       
   276 				// tell protocol to look after us until a primary collects us
       
   277 				iProtocol.AddSecondarySAP(*this);
       
   278 				iIsSecondary = ETrue;
       
   279 				ret = KErrNone;		
       
   280 				}
       
   281 			break;
       
   282 			case EBindToSecondarySAP:
       
   283 				{
       
   284 				// form binding to secondary sap
       
   285 				iSecondarySAP = iProtocol.GetSecondarySAP();
       
   286 				__ASSERT_DEBUG(iSecondarySAP, Panic(ERGAVDPSequenceFailure));
       
   287 				ret = KErrNone;
       
   288 				}
       
   289 			break;
       
   290 			}
       
   291 		// default covered by ret.
       
   292 		}
       
   293 	else
       
   294 		{
       
   295 		ret = iSession ? iSession->SetOption(aLevel, aName, aOption) : KErrNotReady;
       
   296 		}
       
   297 	return ret;
       
   298 	}
       
   299 
       
   300 
       
   301 // Startup/Shutdown
       
   302 
       
   303 void CAvdtpSAP::ActiveOpen()
       
   304 /**
       
   305 Active open an AVDTP socket...
       
   306 
       
   307   @internalAll
       
   308 */
       
   309 	{
       
   310 	LOG_FUNC
       
   311 	TInt err = KErrNotReady;
       
   312 	
       
   313 	if (iSession)
       
   314 		{
       
   315 		err = iSession->ActiveOpen();
       
   316 		}
       
   317 		
       
   318 	if (err!=KErrNone)
       
   319 		{
       
   320 		iSocket->Error(err, MSocketNotify::EErrorConnect);
       
   321 		}
       
   322 	}
       
   323 
       
   324 void CAvdtpSAP::ActiveOpen(const TDesC8& /*aConnectionData*/)
       
   325 /**
       
   326 Active open an AVDTP socket (data overload)...
       
   327 
       
   328   @internalAll
       
   329   @param aConnectionData Data to send on connection
       
   330 */
       
   331 	{
       
   332 	LOG_FUNC
       
   333 	Error(KErrNotSupported);
       
   334 	}
       
   335 
       
   336 TInt CAvdtpSAP::PassiveOpen(TUint /*aQueSize*/)
       
   337 /**
       
   338 Passive open an AVDTP socket...
       
   339 NOT SUPPORTED.
       
   340 @see CLogicalChannelFactory which acquires inbound logical channels and is aware of their sequence
       
   341 @see Transport sessions which are ActiveOpened to "find" passive bearers
       
   342 @internalAll
       
   343 */
       
   344 	{
       
   345 	LOG_FUNC
       
   346 	return KErrNotSupported;
       
   347 	}
       
   348 
       
   349 TInt CAvdtpSAP::PassiveOpen(TUint /*aQueSize*/, const TDesC8& /*aConnectionData*/)
       
   350 /**
       
   351 Passive open an AVDTP socket...
       
   352 NOT SUPPORTED.
       
   353 @see CLogicalChannelFactory which acquires inbound logical channels and is aware of their sequence
       
   354 @see Transport sessions which are ActiveOpened to "find" passive bearers
       
   355 @internalAll
       
   356 */
       
   357 	{
       
   358 	LOG_FUNC
       
   359 	return KErrNotSupported;
       
   360 	}
       
   361 
       
   362 void CAvdtpSAP::Start()
       
   363 /**
       
   364 @internalAll
       
   365 */
       
   366 	{
       
   367 	LOG_FUNC
       
   368 	// sessions do not need to be forwarded this at present
       
   369 	// (primarily as no "usual" passive connections)
       
   370 	}
       
   371 
       
   372 void CAvdtpSAP::Shutdown(TCloseType aCloseType)
       
   373 /**
       
   374 Close the SAP down.  We don't declare support for Normal shutdown, but for future use
       
   375 we pass onto transport session.
       
   376 
       
   377 @internalAll
       
   378 @param aCloseType How fast we're going down
       
   379 */
       
   380 	{
       
   381 	LOG_FUNC
       
   382 	if (iSession)
       
   383 		{
       
   384 		aCloseType==ENormal ? iSession->Shutdown() : iSession->FastShutdown();
       
   385 		}
       
   386 		
       
   387 	// fast shutdown will delete us after this unwinds
       
   388 	}
       
   389 
       
   390 void CAvdtpSAP::Shutdown(TCloseType aCloseType, const TDesC8& /*aDisconnectionData*/)
       
   391 /**
       
   392 Close the SAP down (data overload).
       
   393 
       
   394 We don't declare support for Normal or data shutdowns, but for future use
       
   395 we pass onto transport session.
       
   396 
       
   397 @internalAll
       
   398 @param aCloseType How fast we're going down
       
   399 @param aDisconnectionData Data to send on disconnect
       
   400 */
       
   401 	{
       
   402 	// this one's an error
       
   403 	LOG_FUNC
       
   404 	Shutdown(aCloseType);
       
   405 	}
       
   406 
       
   407 // Data flow & ioctl
       
   408 
       
   409 TInt CAvdtpSAP::Write(RMBufChain& aData, TUint aOptions, TSockAddr* aAddr)
       
   410 	{
       
   411 	LOG_FUNC
       
   412 
       
   413 	if (iSession)
       
   414 		{
       
   415 		return iSession->Send(aData, aOptions, aAddr);
       
   416 		}
       
   417 	else
       
   418 		{
       
   419 		iSocket->Error(KErrNotReady, MSocketNotify::EErrorSend);
       
   420 		return 0;
       
   421 		}
       
   422 	}
       
   423 
       
   424 TInt CAvdtpSAP::GetData(RMBufChain& aData, TUint /*aLength*/, TUint /*aOptions*/, TSockAddr* /*aAddr*/)
       
   425 	{
       
   426 	LOG_FUNC
       
   427 	return iSession ? iSession->GetData(aData) : KErrNotSupported;
       
   428 	}
       
   429 
       
   430 
       
   431 void CAvdtpSAP::Ioctl(TUint aLevel, TUint aName, TDes8* aOption)
       
   432 /**
       
   433 Perform an Ioctl.
       
   434 Primary SAPs ask the session to actually perform the ioctl.
       
   435 Secondary SAPs do the ioctl themselves.
       
   436 
       
   437 Perform ioctl-guarding (one at a time stuff) then forward to session
       
   438 @internalAll
       
   439 @param aLevel The Ioctl level
       
   440 @param aName The Ioctl name
       
   441 @param aOption The Ioctl data
       
   442 */
       
   443 	{
       
   444 	LOG_FUNC
       
   445 	if (!iIsSecondary)
       
   446 		{
       
   447 		// we are a *primary* SAP, and should forward to our session
       
   448 		if (!iSession)
       
   449 			{
       
   450 			iSocket->Error(KErrDisconnected, MSocketNotify::EErrorIoctl);
       
   451 			}
       
   452 		else
       
   453 			{
       
   454 			iIoctlLevel = aLevel;
       
   455 			iIoctlName = aName;
       
   456 			iSession->Ioctl(aLevel, aName, aOption);
       
   457 			}
       
   458 		}
       
   459 	else
       
   460 		{
       
   461 		if (aLevel == KSolBtAVDTPSignalling)
       
   462 			{
       
   463 			// we are a secondary sap, so just deal with ioctls ourselves
       
   464 			iIoctlLevel = aLevel;
       
   465 			iIoctlName = aName;
       
   466 
       
   467 			switch (aName)
       
   468 				{
       
   469 				case EAwaitIndication:
       
   470 					{
       
   471 					// if there is one on the queue then deliver
       
   472 					if (!iIndicationQueue.IsEmpty())
       
   473 						{
       
   474 						HQueuedAvdtpIndication* ind = iIndicationQueue.First();
       
   475 						iIndicationQueue.Remove(*ind);
       
   476 						ServiceComplete(ind->Indication());
       
   477 						delete ind;
       
   478 						}
       
   479 					}
       
   480 				break;
       
   481 				default:
       
   482 					Error(KErrNotSupported);				
       
   483 				}
       
   484 			}
       
   485 		}
       
   486 	}
       
   487 	
       
   488 	
       
   489 
       
   490 void CAvdtpSAP::CancelIoctl(TUint aLevel, TUint aName)
       
   491 /**
       
   492 Cancel an Ioctl.
       
   493 
       
   494 @internalAll
       
   495 @param aLevel The Ioctl level
       
   496 @param aName The Ioctl name
       
   497 */
       
   498 	{
       
   499 	LOG_FUNC
       
   500 	__ASSERT_DEBUG(aLevel == iIoctlLevel && aName == iIoctlName, Panic(EAvdtpBadIoctl));
       
   501 	if (iSession)
       
   502 		{
       
   503 		iSession->CancelIoctl(aLevel, aName);
       
   504 		}
       
   505 	
       
   506 	ClearIoctl();
       
   507 	}
       
   508 
       
   509 void CAvdtpSAP::Error(TInt aError)
       
   510 /**
       
   511 Error has occurred - tell the socket.
       
   512 
       
   513 @internalAll
       
   514 @param aErr The error code
       
   515 @param aType The type of error
       
   516 */
       
   517 	{
       
   518 	LOG_FUNC
       
   519 	iSocket->Error(aError, iIoctlLevel ? MSocketNotify::EErrorIoctl
       
   520 									   : MSocketNotify::EErrorAllOperations);
       
   521 #ifdef _DEBUG									   
       
   522 	iCanSignalDisconnect = EFalse; // esock doesn't allow error then disconnect
       
   523 #endif
       
   524 	ClearIoctl();
       
   525 	}
       
   526 	
       
   527 void CAvdtpSAP::SendError(TInt aError)
       
   528 	{
       
   529 	iSocket->Error(aError, MSocketNotify::EErrorSend);
       
   530 	}
       
   531 	
       
   532 void CAvdtpSAP::SessionDisconnect()
       
   533 	{
       
   534 #ifdef _DEBUG
       
   535 	if (iCanSignalDisconnect)
       
   536 #endif
       
   537 		{
       
   538 		iSocket->Disconnect();
       
   539 #ifdef _DEBUG
       
   540 		iCanSignalDisconnect = EFalse;
       
   541 #endif
       
   542 		}
       
   543 	}
       
   544 
       
   545 
       
   546 /************************************************************************
       
   547 
       
   548   Events interface (from TransportSession)
       
   549 
       
   550  ************************************************************************/
       
   551 
       
   552 void CAvdtpSAP::NewData(TUint aCount)
       
   553 /**
       
   554 There is new data from the session for us.
       
   555 
       
   556 @internalComponent
       
   557 @param aPacket The new data from the muxer
       
   558 */
       
   559 	{
       
   560 	// Write the data out to the socket, if possible.
       
   561 	LOG_FUNC
       
   562 	if (iSocket)
       
   563 		{
       
   564 		iSocket->NewData(aCount);
       
   565 		}
       
   566 	}
       
   567 
       
   568 void CAvdtpSAP::CanSend()
       
   569 /**
       
   570 Notification from the session that we can send again.
       
   571 
       
   572 Pass this through to our state machine.
       
   573 
       
   574   @internalComponent
       
   575 */
       
   576 	{
       
   577 	LOG_FUNC
       
   578 	iSocketBlocked = EFalse;
       
   579 	iSocket->CanSend();
       
   580 	}
       
   581 
       
   582 void CAvdtpSAP::ServiceComplete(const TDesC8* aBuf)
       
   583 /**
       
   584 Notification that an AVDTP command has completed.
       
   585 May be called when no Ioctl called (ag stack-initiated Aborts) - in which case NOP
       
   586 @param aBuf The Ioctl data
       
   587 */
       
   588 	{
       
   589 	LOG_FUNC
       
   590 	if (iIoctlLevel)
       
   591 		{
       
   592 		// need to cast away constness!
       
   593 		iSocket->IoctlComplete(const_cast<TDesC8*>(aBuf));
       
   594 		ClearIoctl();
       
   595 		}
       
   596 	}
       
   597 
       
   598 // Bearer (=signalling channel in this case) interface
       
   599 
       
   600 void CAvdtpSAP::Ready()
       
   601 	{
       
   602 	LOG_FUNC
       
   603 	// tell socket that session is ready 
       
   604 		{
       
   605 #ifdef _DEBUG
       
   606 		iCanSignalDisconnect = ETrue;
       
   607 #endif
       
   608 		iSocket->ConnectComplete();
       
   609 		}
       
   610 	}
       
   611 
       
   612 
       
   613 /*inline*/ void CAvdtpSAP::ClearIoctl()
       
   614 	{
       
   615 	LOG_FUNC
       
   616 	iIoctlLevel = 0;
       
   617 	iIoctlName = 0;
       
   618 	}
       
   619 
       
   620 /* for the case of normal shutdowns from socket this is called when session
       
   621 is ready to go
       
   622 */
       
   623 void CAvdtpSAP::CanClose()
       
   624 	{
       
   625 	LOG_FUNC
       
   626 	iSocket->CanClose(MSocketNotify::EDelete);
       
   627 	}
       
   628 	
       
   629 /**
       
   630 Raise an indication to the client
       
   631 Only secondary saps can propagate indications
       
   632 */
       
   633 void CAvdtpSAP::Indication(const TDesC8& aIndicationData)
       
   634 	{
       
   635 	LOG_FUNC
       
   636 	__ASSERT_DEBUG(iSecondarySAP, Panic(EAvdtpSAPIndicationEngineFailure));
       
   637 	iSecondarySAP->DoIndication(aIndicationData);
       
   638 	}
       
   639 
       
   640 /**
       
   641 Actually do the raising of the indication
       
   642 */	
       
   643 void CAvdtpSAP::DoIndication(const TDesC8& aIndicationData)
       
   644 	{
       
   645 	LOG_FUNC
       
   646 	__ASSERT_DEBUG(iSocket, Panic(EAvdtpSAPIndicationEngineFailure));
       
   647 
       
   648 	// since the protocol allows multiple outstanding commands it can be that we
       
   649 	// have to raise subsequent indications before the client has responded to the first
       
   650 	// therefore we queue the indication data
       
   651 
       
   652 	if (iIoctlName == 0)
       
   653 		// means there is no pending ioctl.
       
   654 		// the queue can or cannot be empty. However, since there is no
       
   655 		// pending ioctl, we queue the indication
       
   656 		{
       
   657 	    HQueuedAvdtpIndication* ind = HQueuedAvdtpIndication::New(aIndicationData);
       
   658 		if (ind)
       
   659 			{
       
   660 			LOG(_L("Adding Indication to queue"));
       
   661 			iIndicationQueue.AddLast(*ind);
       
   662 			}
       
   663 		else
       
   664 			{
       
   665 			// OOM'd - better tell client...they've lost an indication
       
   666 			Error(KErrNoMemory);
       
   667 			}
       
   668 		}
       
   669 	else
       
   670 		// if we have an outstanding Ioctl means the queue is empty.
       
   671 		// infact when an Ioctl (on sec sap) is performed and there are items
       
   672 		// in the queue, it completes the Ioctl immediately with a queued
       
   673 		// indication and then it clears the iIoctlName.
       
   674 		// Otherwise, if it cannot find queued indications then sets the iIoctlName
       
   675 		// and iIoctlLevel that means having a pending Ioctl 
       
   676 		{
       
   677 		__ASSERT_DEBUG(iIndicationQueue.IsEmpty(), Panic(EAvdtpUnexpectedIndicationsInQueue));
       
   678 		// tell client straight away
       
   679 		if (iSocket)
       
   680 			{
       
   681 			ServiceComplete(&aIndicationData);
       
   682 			}
       
   683 		}
       
   684 	}
       
   685 	
       
   686 
       
   687 HQueuedAvdtpIndication* HQueuedAvdtpIndication::New(const TDesC8& aIndicationData)
       
   688     {
       
   689 	LOG_STATIC_FUNC
       
   690     HQueuedAvdtpIndication* ind = new HQueuedAvdtpIndication;
       
   691     TInt err = KErrNone;
       
   692     if (ind)
       
   693     	{
       
   694     	TRAPD(err, ind->ConstructL(aIndicationData));
       
   695     	if (err)
       
   696     	    {
       
   697     	    delete ind;
       
   698     	    ind=NULL;
       
   699     	    }
       
   700     	}
       
   701     return (err==KErrNone) ? ind : NULL;
       
   702     }
       
   703 	
       
   704 void HQueuedAvdtpIndication::ConstructL(const TDesC8& aIndicationData)
       
   705     {
       
   706 	LOG_FUNC
       
   707 	iBuf = NULL;
       
   708     iBuf = aIndicationData.AllocL();
       
   709     }
       
   710     
       
   711 HQueuedAvdtpIndication::~HQueuedAvdtpIndication()
       
   712     {
       
   713 	LOG_FUNC
       
   714     delete iBuf;
       
   715     }
       
   716