os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/GavdpStateMachine.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-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 //
    15 
    16 #include "A2dpCodecUtilities.h"
    17 #include "GavdpStateMachine.h"
    18 
    19 
    20 /**
    21 GAVDP State Machine Panics
    22 **/
    23 enum TGavdpStateMachinePanic
    24 	{
    25 	EGavdpStateMachineBadState,//0
    26 	EGavdpStateMachineBadConfigByRemoteHeadsetState,//1
    27 	EGavdpStateMachineBadBTAddr,//2
    28 	EGavdpStateMachineUnexpectedCallback,//3
    29 	EGavdpStateMachineDataTypeMismatch//4
    30 	};
    31 
    32 
    33 static void Panic(TGavdpStateMachinePanic aPanic)
    34 // Panic client
    35 	{
    36 	_LIT(KGavdpStateMachinePanicName, "GAVDP State Mchn");
    37 	User::Panic(KGavdpStateMachinePanicName, aPanic);
    38 	}
    39 
    40 
    41 /**
    42 Utility function to map a bluetooth code to a standard SymbianOS code
    43 Where a standard Symbian error code exists the error is mapped
    44 to the standard code.  Ideally all HCI, L2CAP, AVDTP, GAVDP errors
    45 should be mapped to standard SymbianOS codes since bluetooth specific
    46 error codes aren't meaningful in the multimedia domain
    47 */
    48 static TInt ConvertToStandardSymbianOSError(TInt aError)
    49 	{
    50 	TInt error;
    51 	
    52 	switch (aError)
    53 		{
    54 		case KHCIErrorBase-EPageTimedOut://-6004
    55 			error = KErrCouldNotConnect;
    56 			break;
    57 		case KHCIErrorBase-EAuthenticationFailure://-6005
    58 			error = KErrCouldNotConnect;
    59 			break;
    60 		case KHCIErrorBase-EPairingNotAllowed: //-6024
    61 			error = KErrCouldNotConnect;
    62 			break;
    63 		case KHCIErrorBase-ELMPResponseTimeout: //-6034
    64 			error = KErrTimedOut;
    65 			break;
    66 		case KErrHCIConnectFailed: //-6304
    67 			error = KErrCouldNotConnect;
    68 			break;
    69 		case KErrHCILinkDisconnection: //-6305
    70 			error = KErrDisconnected;
    71 			break;
    72 		default:
    73 			error = aError;
    74 			break;
    75 		}
    76 	return error;
    77 	}
    78 
    79 
    80 /**
    81 Creates CGAVDPStateMachine
    82 
    83 @internalComponent
    84 @return CGAVDPStateMachine*
    85 */
    86 CGAVDPStateMachine* CGAVDPStateMachine::NewL(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer)
    87 	{
    88 	CGAVDPStateMachine* self = new(ELeave) CGAVDPStateMachine(aGAVDPStateChangeObserver, aA2dpCodecSettings, aSocketServer);
    89 	CleanupStack::PushL(self);
    90 	self->ConstructL();
    91 	CleanupStack::Pop(self);
    92 	return self;
    93 	}
    94 
    95 
    96 /**
    97 Constructor
    98 [TODO] change default stereo mode to EMMFJoint when hardware has sufficient bandwidth
    99 Note we make the AO priority one less than normal to give the AOs in GAVDP
   100 preference
   101 */
   102 CGAVDPStateMachine::CGAVDPStateMachine(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer) : CActive(EPriorityNormal-1), 
   103 iGAVDPStateChangeObserver(aGAVDPStateChangeObserver) ,iA2dpCodecSettings(aA2dpCodecSettings), iSocketServer(aSocketServer)
   104 	{
   105 	CActiveScheduler::Add(this);
   106 	}
   107 
   108 
   109 void CGAVDPStateMachine::ConstructL()
   110 	{
   111 	User::LeaveIfError(iGavdp.Open(*this, iSocketServer));
   112 	User::LeaveIfError(RegisterLocalSEP());
   113 	iSignallingTransactionTimeout = CGavdpTimeout::NewL(*this);
   114 	}
   115 	
   116 
   117 /**
   118 Internal function to register local SEPs with GAVDP
   119 The function sets the iSymbianDeviceSEID to the TSEID 
   120 of the Symbian device
   121 */	
   122 TInt CGAVDPStateMachine::RegisterLocalSEP()
   123 	{
   124 	//register SEPs - currently SBC & mp3 SEPs are supported
   125 	TAvdtpSEPInfo avdtpSEPInfo;	
   126 	avdtpSEPInfo.SetInUse(EFalse);
   127 	avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio);
   128 	avdtpSEPInfo.SetIsSink(EFalse);
   129 	TInt err = iGavdp.RegisterSEP(avdtpSEPInfo);	
   130 	TUsableSEP sep;
   131 	sep.iSEID = avdtpSEPInfo.SEID();
   132 	sep.iDataType = KMMFFourCCCodeSBC;
   133 	err = iSymbianDeviceSEPs.Append(sep);
   134 	
   135 	if (!err)
   136 		{
   137 		avdtpSEPInfo.SetInUse(EFalse);
   138 		avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio);
   139 		avdtpSEPInfo.SetIsSink(EFalse);
   140 		err = iGavdp.RegisterSEP(avdtpSEPInfo);
   141 		if (!err)
   142 			{
   143 			sep.iSEID = avdtpSEPInfo.SEID();
   144 			sep.iDataType = KMMFFourCCCodeMP3;
   145 			err = iSymbianDeviceSEPs.Append(sep);
   146 			}
   147 		}			
   148 	if (!err)
   149 		{
   150 		TBool SEPDataTypeFound(EFalse);
   151 		for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
   152 			{
   153 			if (iSymbianDeviceSEPs[i].iDataType == iA2dpCodecSettings.HeadsetCodecDataType()) 
   154 				{
   155 				iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID;
   156 				SEPDataTypeFound = ETrue;
   157 				break;
   158 				}
   159 			}
   160 		if (!SEPDataTypeFound)
   161 			{
   162 			err = KErrNotFound;
   163 			}
   164 		}
   165 	return err;
   166 	}
   167 
   168 
   169 /**
   170 Standard destructor.
   171 */
   172 CGAVDPStateMachine::~CGAVDPStateMachine()
   173 	{
   174 	Cancel();
   175 	iBearerSocket.Close();
   176 	iGavdp.Close();
   177 	iPotentialSEPs.Close();
   178 	iUsableSEPs.Close();
   179 	iSymbianDeviceSEPs.Close();
   180 	iSEPCapabilities.ResetAndDestroy();
   181 	iSEPCapabilities.Close();
   182 	delete iSignallingTransactionTimeout;
   183 	}
   184 
   185 
   186 /**
   187 Function to set the Bluetooth address of the headset.
   188 
   189 @param aRemoteAddress Bluetooth address of the headset
   190 */
   191 void CGAVDPStateMachine::SetBTAddress(const TBTDevAddr& aRemoteAddress)
   192 	{
   193 	if (iBTDevAddr != aRemoteAddress)
   194 		{//must be using a new headet so reset state machine
   195 		Reset();
   196 		iBTDevAddr = aRemoteAddress;
   197 		}
   198 	}
   199 	
   200 	
   201 /**
   202 Function to returns the current state of the GAVDP state machine.
   203 
   204 @return the current state of the GAVDP state machine
   205 */
   206 TGAVDPState CGAVDPStateMachine::State() const
   207 	{
   208 	return iCurrentState ;
   209 	}
   210 
   211 
   212 /**
   213 Internal function to resets the GAVDP state machine to the EGAVDPIdle state
   214 Note that if the headset is already connected Reseting
   215 will cause a subsequent call to RGavdp.Connect, however
   216 if we are already connected this should complete straight away
   217 
   218 Note we don't close the bearer socket here as we need to ensure
   219 this is closed after the RTP streamer is deleted so this is handled by the CA2dpBTHeadsetAudioInterface
   220 */
   221 void CGAVDPStateMachine::Reset()
   222 	{
   223 	iPotentialSEPs.Reset();
   224 	iUsableSEPs.Reset();
   225 	iSEPCapabilities.ResetAndDestroy();
   226 	iSEPIterator = 0;
   227 	iSEPCapabilityEntry = 0;
   228 	iA2dpCodecSettings.Reset();
   229 	iInitialState = TGAVDPState::EGAVDPIdle;
   230 	iCurrentState = TGAVDPState::EGAVDPIdle;
   231 	iNextState = TGAVDPState::EGAVDPIdle;
   232 	iTargetState = TGAVDPState::EGAVDPIdle;
   233 	iConfigurationByRemoteHeadsetState.Reset();
   234 	iHeadsetSEID.Reset();
   235 	iLocalSEPConfigured = EFalse;
   236 	iChangeOfSelectedHeadsetSEP = EFalse;
   237 	iGavdp.Cancel();
   238 	iSignallingTransactionTimeout->Cancel();
   239 	}
   240 
   241 
   242 /**
   243 Function to move the GAVDP state machine to the state specified in aNewState
   244 Not all state changes are allowed, however. 
   245 Permitted state changes are anystate to ->EGAVDPIdle,EConnectedToGavdp,ESEPsDiscovered
   246 which causes a reset.  
   247 Anything prior to EGAVDPOpen->EGAVDPOpen
   248 EGAVDPOpen->EGAVDPStreaming
   249 EGAVDPStreaming->EGAVDPOpen
   250 
   251 When the state change is completed a GAVDPStateChangeComplete callback is 
   252 made on the MGAVDPStateChangeObserver, which is the CA2dpBTHeadsetAudioInterface
   253 
   254 @param aNewState The state we wish to go to
   255 @return standard SymbianOS error code
   256 */
   257 TInt CGAVDPStateMachine::ChangeState(const TGAVDPState& aNewState)
   258 	{
   259 	if (iStateChangeInProgress)
   260 		{//can't change state if a state change is already in progress
   261 		return KErrNotReady; 
   262 		}
   263 	if (aNewState.State()<= TGAVDPState::ESEPSelected)
   264 		{
   265 		//if the state is ESEPSelected or less then
   266 		//the assumption is we need to reselect the SEP and in
   267 		//effect redo the entire initialization prior to selecting the SEP
   268 		//therefore roll back to EGAVDPIdle and reset.
   269 		Reset();
   270 		}
   271 	else if (aNewState == TGAVDPState::EGAVDPStreaming)
   272 		{
   273 		//must be in the EGAVDPOpen state in order to go to EGAVDPStreaming
   274 		if (iCurrentState != TGAVDPState::EGAVDPOpen)
   275 			{
   276 			return KErrNotReady;
   277 			}
   278 		}
   279 		
   280 	if (aNewState == iCurrentState)
   281 		{
   282 		//then we are already in the requested state so don't move to
   283 		//next state- so just call the RunL and complete
   284 		iStateChangeInProgress = EFalse;//we're not going to change the state
   285 		TRequestStatus* stat = &iStatus;
   286 		if (!IsActive())
   287 			{
   288 			User::RequestComplete(stat, KErrNone);
   289 			SetActive();
   290 			}
   291 		}
   292 	else
   293 		{//need to move to the next state
   294 		iInitialState = iCurrentState; //incase we need to wind back if state change fails
   295 		iTargetState = aNewState;
   296 		NextState();
   297 		}
   298 	return KErrNone;
   299 	}
   300 
   301 
   302 /**
   303 Function to cause a reconfiguration of the SEP.  The function determines 
   304 whether a reconfiguration is required ie becuase the settings have changed.
   305 And if so the SEP is reconfigured or a new SEP is selected if the reconfiguration
   306 results in a change of SEP ie because the datatype has changed
   307 This function makes a GAVDPStateChangeComplete callback on the CA2dpBTHeadsetAudioInterface
   308 If the SEP changes because of a change in data type then the 	iChangeOfSelectedHeadsetSEP
   309 flag is set which is used by the state machine to cause the media transport
   310 caps to be added to the SEP
   311 
   312 @param aSettingsHaveChanged set to ETrue if the settings have changed
   313 
   314 @return SymbianOS error code
   315 */	
   316 TInt CGAVDPStateMachine::Reconfigure(TBool aSettingsHaveChanged)
   317 	{
   318 	//not allowed to reconfigure in the middle of a state change	
   319 	if ((iStateChangeInProgress)||(IsActive()))
   320 		{
   321 		return KErrNotReady;
   322 		}	
   323 		
   324 	//in order to perform a reconfigure the current state must
   325 	//be either EConfigured or EGAVDPOpen
   326 	//reconfiguration by the SymbianOs device in the streaming state is not supported
   327 	//in this implementation even though it is allowed by the GAVDP profile
   328 	if ((iCurrentState != TGAVDPState::EConfigured) &&
   329 		(iCurrentState != TGAVDPState::EGAVDPOpen))
   330 		{
   331 		return KErrNotReady;
   332 		}
   333 		
   334 	__ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));//this should always be true if no state change is in progress
   335 	
   336 	iChangeOfSelectedHeadsetSEP = EFalse;
   337 	if (aSettingsHaveChanged)
   338 		{//then see if we need to change SEP
   339 		//data type has changed so we need to choose a different SEP
   340 		//and configure it
   341 		//note if no match is found then we go with the exiting
   342 		//selected SEP
   343 		for (TUint i=0;  i<iUsableSEPs.Count() ; i++)
   344 			{
   345 			TUsableSEP sep = iUsableSEPs[i];
   346 			if (sep.iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
   347 				{//then we have a match so use this SEP
   348 				if (sep.iSEID != iHeadsetSEID)
   349 					{//then this is a different SEP to the one we were already using
   350 					iHeadsetSEID = sep.iSEID;
   351 					iLocalSEPConfigured = EFalse;
   352 					iChangeOfSelectedHeadsetSEP = ETrue;//need to config transport capabilites again if change of SEP
   353 					//need to change the symbian device SEP as well
   354 					TBool symbianDeviceSupportsNewSEPDataType(EFalse);
   355 					for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
   356 						{
   357 						if (iSymbianDeviceSEPs[i].iDataType == sep.iDataType) 
   358 							{
   359 							iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID;
   360 							symbianDeviceSupportsNewSEPDataType = ETrue;
   361 							break;
   362 							}
   363 						}
   364 					__ASSERT_DEBUG(symbianDeviceSupportsNewSEPDataType, Panic(EGavdpStateMachineDataTypeMismatch));
   365 					
   366 					//the if condition below is totaly unnecesaary since we have already
   367 					//ASSERTed symbianDeviceSupportsNewSEPDataType, however the ARM 5 compiler
   368 					//does not seem to recognize code in ASSERT statements so the if statement
   369 					//supresses an ARM v5 compiler warning
   370 					if (symbianDeviceSupportsNewSEPDataType)
   371 						{
   372 						iBearerSocket.Close(); //if we change headset SEP then the old bearer is no longer valid 
   373 						}
   374 					}
   375 				}
   376 			}
   377 		}
   378 		
   379 	
   380 		
   381 	//if a reconfigure is required then we need to reset the current state
   382 	//to ESEPSelected and reconfigure 
   383 	iInitialState = iCurrentState; //incase we need to wind back if state change fails
   384 	
   385 	if ((aSettingsHaveChanged)||(iChangeOfSelectedHeadsetSEP))
   386 		{
   387 		iTargetState = iCurrentState;  //need to end up in the same state we started at
   388 		iCurrentState = TGAVDPState::ESEPSelected; //roll back the state machine to ESEPSelected
   389 		iNextState = iCurrentState;
   390 		NextState(); //make sure the NextState is EConfigured
   391 		}
   392 	else
   393 		{//go to RunL to make GAVDPStateChangeComplete callback
   394 		if (!IsActive())
   395 			{
   396 			TRequestStatus* stat = &iStatus;
   397 			User::RequestComplete(stat, KErrNone);
   398 			SetActive();
   399 			}
   400 		}
   401 	return KErrNone;
   402 	}
   403 
   404 
   405 /**
   406 Advance to Next state
   407 */	
   408 void CGAVDPStateMachine::NextState()
   409 	{
   410 	iStateChangeInProgress = ETrue;
   411 	TRequestStatus* stat = &iStatus;
   412 	++iNextState;
   413 	if (!IsActive())
   414 		{
   415 		User::RequestComplete(stat, KErrNone);
   416 		SetActive();
   417 		}
   418 	}
   419 	
   420 
   421 /**
   422 Internal function to complete the state change
   423 */	
   424 void CGAVDPStateMachine::StateChangeComplete()
   425 	{
   426 	iCurrentState = iNextState;
   427 	if (iCurrentState == iTargetState)
   428 		{
   429 		iStateChangeInProgress = EFalse;
   430 		iGAVDPStateChangeObserver.GAVDPStateChangeComplete(iInitialState, KErrNone);
   431 		}
   432 	else
   433 		{//we've completed the internal state change but have not reached the target state
   434 		NextState();
   435 		}
   436 	}
   437 
   438 
   439 /**
   440 Function to cancel a state change initialited by the ChangeState function
   441 This function is called when the change state is explicitly cancelled by the client
   442 */
   443 void CGAVDPStateMachine::CancelChangeState()
   444 	{
   445 	//if we call this externally then the reason is KErrCancel
   446 	//as the state change has been explicitely cancelled
   447 	CancelChangeState(KErrCancel);
   448 	}
   449 
   450 	
   451 /**
   452 Internal function to cancel a state change initiated by the ChangeState function
   453 Usually called when an error occurs that would prevent the state change
   454 from completing
   455 */	
   456 void CGAVDPStateMachine::CancelChangeState(TInt aReason)
   457 	{
   458 	if (iStateChangeInProgress)
   459 		{//unwind the request as far as possible
   460 		switch (iInitialState.State())
   461 			{
   462 			case TGAVDPState::EGAVDPIdle:
   463 				Reset();
   464 				break;
   465 			case TGAVDPState::EGAVDPOpen:
   466 				iGavdp.Cancel();
   467 				iCurrentState = TGAVDPState::EGAVDPOpen;
   468 				iNextState = TGAVDPState::EGAVDPOpen;
   469 				iTargetState = TGAVDPState::EGAVDPOpen;
   470 				break;
   471 			case TGAVDPState::EGAVDPStreaming:
   472 				iGavdp.Cancel();
   473 				iNextState = TGAVDPState::EGAVDPStreaming;
   474 				iTargetState = TGAVDPState::EGAVDPStreaming;
   475 				break;
   476 			default:
   477 				Panic(EGavdpStateMachineBadState);
   478 				break;		
   479 			}	
   480 		}
   481 	if (IsActive())
   482 		{
   483 		Cancel();
   484 		}
   485 	iStateChangeInProgress = EFalse;
   486 	iGAVDPStateChangeObserver.GAVDPStateChangeComplete(iInitialState, aReason);
   487 	}
   488 	
   489 
   490 /**
   491 Internal function to initiate the connection to the headset
   492 */
   493 void CGAVDPStateMachine::ConnectToGAVDP()
   494 	{
   495 	iGavdp.Connect(iBTDevAddr);
   496 	}
   497 	
   498 
   499 /**
   500 MGavdpUser callback to indicate the headset is connected
   501 
   502 @see MGavdpUser
   503 */	
   504 void CGAVDPStateMachine::GAVDP_ConnectConfirm(const TBTDevAddr& aDevice)
   505 	{
   506 	if (!iStateChangeInProgress)
   507 		{//connect initiated by remote headset so we'll accept the address
   508 		iBTDevAddr = aDevice;
   509 		iCurrentState == TGAVDPState::EConnectedToGavdp;
   510 		}
   511 	else if (iBTDevAddr == aDevice)
   512 		{//if a state change is in progress then we have already set the bt
   513 		//address so the above should be true
   514 		//if its not we'll treat the connect as a spurious connect and ignore
   515 		if (iCurrentState.State() == TGAVDPState::EGAVDPIdle)
   516 			{//if the above isn't true then must be a spurious connect from the headset
   517 			//now connected to the device in question
   518 			StateChangeComplete();
   519 			}	
   520 		}
   521 	}
   522 
   523 
   524 /**
   525 MGavdpUser callback to indicate the headset has suspended streaming
   526 Makes a GAVDPStateMachineStreamSuspendedByRemoteHeadset MGAVDPStateChangeObserver
   527 callback on the CA2dpBTHeadsetAudioInterface
   528 
   529 @see MGavdpUser
   530 */
   531 TInt CGAVDPStateMachine::GAVDP_SuspendIndication(TSEID aSEID)
   532 	{
   533 	TInt err = KErrNone;
   534 	//first check the callback is for the symbian device SEP we are using to 
   535 	//send data to the a2dp headset - incase the Symbian device has more than one SEP
   536 	if (aSEID == iSymbianDeviceSEID)
   537 		{
   538 		__ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   539 	
   540 		//need to stop the RTP streamer from sending more packets to the headset
   541 		iGAVDPStateChangeObserver.GAVDPStateMachineStreamSuspendedByRemoteHeadset();
   542 	
   543 		iCurrentState = TGAVDPState::EGAVDPSuspended;
   544 		}
   545 	else
   546 		{
   547 		err = ConvertToSymbianError::AvdtpError(EAvdtpBadACPSEID);
   548 		}
   549 	return err;
   550 	}
   551 
   552 
   553 /**
   554 MGavdpUser callback to indicate the headset wished to configure the SymbianDevice
   555 
   556 @see MGavdpUser
   557 */
   558 void CGAVDPStateMachine::GAVDP_ConfigurationStartIndication(TSEID aLocalSEID, TSEID aRemoteSEID)
   559 	{
   560 	//first check the callback is for the symbian device SEP we are using to 
   561 	//send data to the a2dp headset - incase the Symbian device has more than one SEP
   562 	if (aLocalSEID == iSymbianDeviceSEID)
   563 		{
   564 		__ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   565 		__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ENotBeingConfiguredByRemoteHeadset, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   566 	
   567 		//cancel any current state changes - config is being driven by headset
   568 		Cancel();
   569 		iGavdp.Cancel();
   570 		//no timeouts are required as if the headset goes down ie does not 
   571 		//result in the expected GAVDP_ConfigurationIndication callbacks a GAVDP_Error
   572 		//callback occurs.
   573 		
   574 		iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart;
   575 		
   576 		//we just store the remote SEP for now
   577 		iConfigurationByRemoteHeadsetState.SetSEPRequestedByRemoteHeadset(aRemoteSEID);
   578 		}
   579 	//	else we can't return an error if the aLocalSEID is not for the SymbianOS device
   580 	}
   581 	
   582 
   583 /**
   584 MGavdpUser callback to request the SymbianOS device to take the configuration passed in aCapability
   585 Only SBC reconfigurations by the remote headset are supported, sample rate changes
   586 are not supported, changes in the number of channels are not suported
   587 if the capability is TSBCCodecCapabilities then the function checks that the values
   588 requested can be accepted.
   589 
   590 @see MGavdpUser
   591 */
   592 TInt CGAVDPStateMachine::GAVDP_ConfigurationIndication(TAvdtpServiceCapability* aCapability)
   593 	{
   594 	//the underlying GAVDP/AVDTP code should ensure that this 
   595 	//callback from GAVDP never occurs once the headset has been configured	
   596 	__ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   597 	__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   598 		
   599 	TInt err = KErrNone;
   600 
   601 	switch(aCapability->Category())
   602 		{
   603 		case EServiceCategoryMediaTransport:
   604 			{
   605 			TAvdtpMediaTransportCapabilities* mediaTransportCaps = static_cast<TAvdtpMediaTransportCapabilities*>(aCapability);
   606 			iConfigurationByRemoteHeadsetState.SetTransportCapsRequestedByRemoteHeadset(mediaTransportCaps);
   607 			}
   608 			break;
   609 		case EServiceCategoryMediaCodec:
   610 			{
   611 			TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(aCapability);
   612 			if (codecCaps->MediaType() != EAvdtpMediaTypeAudio)
   613 				{
   614 				err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec);
   615 				}
   616 			//we're only going to allow a reconfiguration for SBC
   617 			if ((codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCCodeSBC))
   618 				{
   619 				TSBCCodecCapabilities* sbcCodecCapabilities = static_cast<TSBCCodecCapabilities*>(codecCaps);
   620 				TSBCSamplingFrequencyBitmask samplingFreqBitMask = sbcCodecCapabilities->SamplingFrequencies();
   621 				
   622 				//if the headset has already been configured then we don't allow a change 
   623 				//of sampling frequency.  This is because once the DevSound has been configured
   624 				//with a sampling frequency after the DevSound is initialized and hence
   625 				//the a2dpheadsetif is initialized, it is no longer possible to change the sample frequency
   626 				TBool headsetAlreadyConfigured(EFalse);
   627 				if ((iCurrentState.State() == TGAVDPState::EGAVDPOpen) ||
   628 				(iCurrentState.State() == TGAVDPState::EGAVDPSuspended))
   629 					{
   630 					headsetAlreadyConfigured = ETrue;
   631 					}
   632 				//only one bit of the sampling frequency mask should be set
   633 				//note we're using switch statements rather than if then else
   634 				//it makes it easier to pick up the case where we have an invalid
   635 				//value or more than one value has been set in the bit mask
   636 				switch (samplingFreqBitMask)
   637 					{
   638 					case E16kHz:
   639 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 16000))
   640 							{
   641 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   642 							}
   643 						break;
   644 					case E32kHz:
   645 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 32000))
   646 							{
   647 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   648 							}
   649 						break;
   650 					case E44100Hz:
   651 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 44100))
   652 							{
   653 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   654 							}
   655 						break;
   656 					case E48kHz:
   657 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 48000))
   658 							{
   659 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   660 							}
   661 						break;
   662 					default:
   663 						err = ConvertToSymbianError::A2dpError(EA2dpInvalidSamplingFrequency);
   664 						break;
   665 					}
   666 				TSBCChannelModeBitmask channelModeBitMask =  sbcCodecCapabilities->ChannelModes();
   667 				
   668 				//if the headset has already been configured then we don't allow a change 
   669 				//of channels.  This is because once the DevSound has been configured
   670 				//with a sampling frequency after the DevSound is initialized and hence
   671 				//the a2dpheadsetif is initialized, it is no longer possible to change the number of channels
   672 				switch (channelModeBitMask)
   673 					{
   674 					case EMono:
   675 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFMono))
   676 							{
   677 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   678 							}
   679 						break;
   680 					case EDualChannel: //we don't support dual channel
   681 						err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   682 						break;
   683 					case EStereo:
   684 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo))
   685 							{
   686 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   687 							}
   688 						break;
   689 					case EJointStereo:
   690 						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo))
   691 							{
   692 							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   693 							}
   694 						break;
   695 					default:
   696 						err = ConvertToSymbianError::A2dpError(EA2dpInvalidChannelMode);
   697 						break;
   698 					}
   699 					
   700 				TSBCBlockLengthBitmask blockLengthBitMask = sbcCodecCapabilities->BlockLengths();
   701 				
   702 				switch (blockLengthBitMask)
   703 					{
   704 					case EBlockLenFour:
   705 						break;
   706 					case EBlockLenEight:
   707 						break;
   708 					case EBlockLenTwelve:
   709 						break;
   710 					case EBlockLenSixteen:
   711 						break;
   712 					default:
   713 						err = ConvertToSymbianError::A2dpError(EA2dpInvalidBlockLength);
   714 						break;
   715 					}
   716 					
   717 				TSBCSubbandsBitmask subbandsBitMask = sbcCodecCapabilities->Subbands();
   718 				
   719 				TUint subbands = 0;
   720 				switch (subbandsBitMask) 
   721 					{
   722 					case EFourSubbands:
   723 						subbands = 4;
   724 						break;
   725 					case EEightSubbands:
   726 						subbands = 8;
   727 						break;
   728 					default:
   729 						err = ConvertToSymbianError::A2dpError(EA2dpInvalidSubbands);
   730 						break;
   731 					}
   732 					
   733 				TSBCAllocationMethodBitmask allocationMethodBitMask = sbcCodecCapabilities->AllocationMethods();
   734 				
   735 				switch (allocationMethodBitMask)
   736 					{
   737 					case ELoudness:
   738 						break;
   739 					case ESNR:
   740 						break;
   741 					default:
   742 						err = ConvertToSymbianError::A2dpError(EA2dpInvalidAllocationMethod);
   743 						break;
   744 					}
   745 					
   746 				TInt bitPoolValue = sbcCodecCapabilities->MinBitpoolValue();
   747 				
   748 				if (bitPoolValue < KMinBitPoolValue)
   749 					{
   750 					err = ConvertToSymbianError::A2dpError(EA2dpInvalidMinimumBitPoolValue);
   751 					}
   752 					
   753 				bitPoolValue = sbcCodecCapabilities->MaxBitpoolValue();
   754 				
   755 				//The bitpool value must be in the range of 2-250 and must not exceed
   756 				// 16*numberOfSubbands*channels
   757 				if ((bitPoolValue > KMaxBitPoolValue)||(bitPoolValue > (16*subbands*iA2dpCodecSettings.Channels())))
   758 					{		
   759 					err = ConvertToSymbianError::A2dpError(EA2dpInvalidMaximumBitPoolValue);
   760 					}
   761 				if (!err)
   762 					{//note ownership of codecCaps is transferred
   763 					iConfigurationByRemoteHeadsetState.SetCodecConfigRequestedByRemoteHeadset(codecCaps);
   764 					}
   765 				}//if (codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCodeSBC))
   766 			else
   767 				{//only support SBC for now
   768 				err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec);
   769 				}
   770 			}
   771 			break; //case EServiceCategoryMediaCodec:
   772 		default: //	switch(aCapability->Category())
   773 			err = KErrNotSupported;
   774 			break;
   775 		}
   776 	
   777 	if (err)
   778 		{
   779 		iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed;
   780 		if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle))
   781 			{//we only abort if the remote headset has not been configured
   782 			//need to abort using SEID of remote headset - this resets config at remote headset
   783 			Cancel(); //probably not necessary - but just in case
   784 			iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset());
   785 			}
   786 		//else
   787 		//config is a reconfig in suspend streams 
   788 		//wait on a Start_Indication if the headset is ok with the existing config
   789 		//or an Abort_Indication if the headset is not
   790 		}
   791 	
   792 	return err;
   793 	}
   794 
   795 
   796 /*
   797 MGavdpUser callback to indicate to the SymbianOS device that all the GAVDP_ConfigurationIndications
   798 have been sent.
   799 This callback should only occur if there have been no errored GAVDP_ConfigurationIndications
   800 
   801 @see MGavdpUser
   802 */
   803 TInt CGAVDPStateMachine::GAVDP_ConfigurationEndIndication()
   804 	{	
   805 	//the underlying GAVDP/AVDTP code should ensure that this 
   806 	//callback from GAVDP never occurs once the headset has been configured
   807 	__ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   808 	__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   809 	
   810 	TInt err = KErrNone;
   811 	
   812 	TAvdtpMediaCodecCapabilities* configRequestedByRemoteHeadset = iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset();
   813 	if (configRequestedByRemoteHeadset)
   814 		{
   815 		__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset().IsValid(), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   816 		
   817 		//the headset settings have been accepted so use the headset settings
   818 		//the only usable SEP shall be the once specified by the headset
   819 		//for now this will always be SBC
   820 		TUsableSEP SEP;
   821 		SEP.iSEID = iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset();
   822 		TFourCC dataTypeSupport;
   823 		switch (configRequestedByRemoteHeadset->MediaCodecType())
   824 			{
   825 			case EAudioCodecSBC:
   826 				dataTypeSupport.Set(KMMFFourCCCodeSBC);
   827 				break;
   828 			case EAudioCodecMPEG12Audio:
   829 				dataTypeSupport.Set(KMMFFourCCCodeMP3);
   830 				break;
   831 			case EAudioCodecMPEG24AAC:
   832 				dataTypeSupport.Set(KMMFFourCCCodeAAC);
   833 				break;
   834 			case EAudioCodecATRAC:
   835 				dataTypeSupport.Set(KMMFFourCCCodeATRAC3);
   836 				break;
   837 			default://should never get here
   838 				Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState);
   839 				break;
   840 			}
   841 		SEP.iDataType.Set(dataTypeSupport);
   842 		iUsableSEPs.Reset();
   843 		err = iUsableSEPs.Append(SEP);
   844 		
   845 		//the only service capabilities are codec caps provided by the headset and transport
   846 		if (!(iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*configRequestedByRemoteHeadset)))
   847 			{
   848 			err = KErrNoMemory;
   849 			}
   850 		if (!err)
   851 			{
   852 			iSEPCapabilities.ResetAndDestroy();
   853 			err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.TransportCapsRequestedByRemoteHeadset());
   854 			if (!err)
   855 				{
   856 				err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset());
   857 				}
   858 			}	
   859 		}//	if (codecCaps)
   860 
   861 	if (!err)
   862 		{
   863 		if ((iStateChangeInProgress) && (iInitialState.State() == TGAVDPState::EGAVDPIdle))
   864 			{//the headset configured us during an a2dpheadsetif Initialize()
   865 			//we're now configured so now wait for GAVDP_Bearer ready
   866 			iCurrentState == TGAVDPState::EConfigured;
   867 			}
   868 		else if (iCurrentState == TGAVDPState::EGAVDPSuspended)
   869 			{
   870 			//we have reconfigured so the SBC codec needs reconfiguring
   871 			err = iGAVDPStateChangeObserver.GAVDPStateMachineReconfigureByRemoteHeadset();
   872 			}
   873 		}
   874 	if (err)
   875 		{
   876 		if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle))
   877 			{//we only abort if the remote headset has not been configured
   878 			//need to abort using SEID of remote headset - this resets config at remote headset
   879 			Cancel(); //probably not necessary - but just in case
   880 			iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset());
   881 			}
   882 		}
   883 		//else
   884 		//config is a reconfig in suspend streams 
   885 		//wait on a Start_Indication if the headset is ok with the existing config
   886 		//or an Abort_Indication if the headset is not
   887 	iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationEnd;
   888 	return err;
   889 	}
   890 
   891 
   892 /**
   893 MGavdpUser callback to indicate to the SymbianOS device that it has started streaming
   894 There are two circumstances we can get a start indication
   895 1) The headset can request to start the streams itself once we are in the open state
   896 2) The headset can request a restart after suspending the streams eg to perform a reconfiguration
   897 
   898 @see MGavdpUser
   899 */
   900 TInt CGAVDPStateMachine::GAVDP_StartIndication(TSEID aSEID)
   901 	{
   902 	__ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPOpen) ||
   903 	(iCurrentState.State() == TGAVDPState::EGAVDPSuspended), Panic(EGavdpStateMachineUnexpectedCallback));
   904 	__ASSERT_DEBUG((iConfigurationByRemoteHeadsetState.State() != TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart),Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   905 	//first check the callback is for the symbian device SEP we are using to 
   906 	//send data to the a2dp headset - incase the Symbian device has more than one SEP
   907 	if (aSEID == iSymbianDeviceSEID)
   908 		{
   909 		if (iCurrentState.State() ==  TGAVDPState::EGAVDPOpen)
   910 			{
   911 			if (iStateChangeInProgress)
   912 				{
   913 				if (iTargetState.State() == TGAVDPState::EGAVDPStreaming)
   914 					{
   915 					//a EGAVDPOpen->Streaming transistion
   916 					//which has been completed for us by the headset
   917 					Cancel();
   918 					iGavdp.Cancel();
   919 					iCurrentState = TGAVDPState::EGAVDPStreaming;
   920 					StateChangeComplete();
   921 					}
   922 				//else only other state change would be open->idle
   923 				//this is unlikely/impossible if we get a GAVDP_StartIndication
   924 				//do nothing
   925 				}
   926 			else
   927 				{
   928 				//note if no state change is in progress then the headset itself
   929 				//has put itself in the streaming state 
   930 				//normally we put the headset in the streaming state
   931 				//when we call OpenDevice() on the a2dpaudioif
   932 				//but if the headset does this then it is no longer possible
   933 				//for the client to change the audio settings 
   934 				iCurrentState = TGAVDPState::EGAVDPStreaming;
   935 				}
   936 			}//(iCurrentState.State() ==  TGAVDPState::EGAVDPOpen)
   937 		else if (iCurrentState.State() ==  TGAVDPState::EGAVDPSuspended)
   938 			{//most probably restarting after a reconfigure
   939 			iCurrentState = TGAVDPState::EGAVDPStreaming;
   940 			iGAVDPStateChangeObserver.GAVDPStateMachineStreamResumedByRemoteHeadset();
   941 			}
   942 		}//if (aSEID == iSymbianDeviceSEID)
   943 	return KErrNone;	
   944 	}
   945 	
   946 	
   947 /**
   948 MGavdpUser callback to indicate to the SymbianOS device that the request to abort the headset
   949 which means it is not configured has completed
   950 Can request an abort stream if headset configuration fails
   951 
   952 @see MGavdpUser
   953 */
   954 void CGAVDPStateMachine::GAVDP_AbortStreamConfirm()
   955 	{
   956 	//if abort stream was caused by aborting the headset in response
   957 	//to a headset configuration in GAVDP_ConfigurationIndication
   958 	//then restart state machine from EConnectedToGavdp
   959 	if (iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed)
   960 		{//then the abort was caused an aborted configuration from the headset
   961 		__ASSERT_DEBUG((iCurrentState.State() < TGAVDPState::EConfigured), Panic(EGavdpStateMachineUnexpectedCallback));
   962 		
   963 		//since we only aborted if the headset was not yet configured
   964 		//there must be a state change in progress and since we cancelled
   965 		//the GAVDPStateMachine should not be active
   966 		__ASSERT_DEBUG((iStateChangeInProgress) && (!IsActive()), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   967 		
   968 		iConfigurationByRemoteHeadsetState.Reset();	
   969 		//just to make extra sure we'll rediscover the SEPs
   970 		iPotentialSEPs.Reset();
   971 		iUsableSEPs.Reset();
   972 		iSEPCapabilities.ResetAndDestroy();
   973 		iCurrentState = TGAVDPState::EConnectedToGavdp;
   974 		iNextState = TGAVDPState::EConnectedToGavdp;
   975 		iConfigurationByRemoteHeadsetState.Reset();
   976 		iA2dpCodecSettings.Reset();
   977 		iHeadsetSEID.Reset();
   978 		iBearerSocket.Close();
   979 		iLocalSEPConfigured = EFalse;
   980 		iChangeOfSelectedHeadsetSEP = EFalse;
   981 		iSignallingTransactionTimeout->Cancel();	
   982 		NextState();
   983 		}
   984 	iConfigurationByRemoteHeadsetState.Reset();	
   985 	}
   986 
   987 
   988 /**
   989 MGavdpUser callback to indicate to the SymbianOS device that the headset has aborted
   990 ie it can no longer be regarded as configured
   991 This makes a GAVDPStateMachineEvent MGAVDPStateChangeObserver callback on the CA2dpBTHeadsetAudioInterface
   992 (which inturn will cause a Reset on the GAVDP state machine)
   993 
   994 @see MGavdpUser
   995 */	
   996 void CGAVDPStateMachine::GAVDP_AbortIndication(TSEID aSEID)
   997 	{
   998 	//first check the callback is for the symbian device SEP we are using to 
   999 	//send data to the a2dp headset - incase the Symbian device has more than one SEP
  1000 	if (aSEID == iSymbianDeviceSEID)
  1001 		{
  1002 		if (iStateChangeInProgress)
  1003 			{
  1004 			CancelChangeState(KErrAbort);		
  1005 			}
  1006 		else 
  1007 			{
  1008 			iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrAbort);
  1009 			}
  1010 		}
  1011 	//else not much we can do it aSEID isn't the Symbian device ID
  1012 	iConfigurationByRemoteHeadsetState.Reset();
  1013 	}
  1014 
  1015 
  1016 /**
  1017 Internal function to initiate the discovery of the headset SEPs
  1018 Note that the SEP discovery does not have a built in timeout
  1019 so the GAVDP_SEPDiscovered callback must occur withing the GAVDP callback timeout 30s
  1020 or the state change will be cancelled with KErrTimedOut
  1021 */
  1022 void CGAVDPStateMachine::DiscoverRemoteSEPs()
  1023 	{
  1024 	iPotentialSEPs.Reset();
  1025 	iGavdp.DiscoverRemoteSEPs();
  1026 	iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout));
  1027 	}
  1028 
  1029 
  1030 /**
  1031 MGavdpUser callback in response to DiscoverRemoteSEPs
  1032 
  1033 @see MGavdpUser
  1034 */	
  1035 void CGAVDPStateMachine::GAVDP_SEPDiscovered(const TAvdtpSEPInfo& aSEP)
  1036 	{
  1037 	//check whether the SEP is suitable for connection
  1038 	if ((!aSEP.InUse()) && (aSEP.MediaType() == EAvdtpMediaTypeAudio) && (aSEP.IsSink()))
  1039 		{//the SEP is a potentialy suitable for connection
  1040 		//so add to list of potential SEPs
  1041 		TInt err = iPotentialSEPs.Append(aSEP.SEID());
  1042 		if (err)
  1043 			{
  1044 			CancelChangeState(err);
  1045 			}
  1046 		}
  1047 	//else SEP is not suitable so ignore it
  1048 	}
  1049 
  1050 
  1051 /**
  1052 MGavdpUser callback
  1053 
  1054 @see MGavdpUser
  1055 */	
  1056 void CGAVDPStateMachine::GAVDP_SEPDiscoveryComplete()
  1057 	{
  1058 	iSignallingTransactionTimeout->Cancel();
  1059 	if (iPotentialSEPs.Count())
  1060 		{//we have at least one potential SEP
  1061 		StateChangeComplete();
  1062 		}
  1063 	else
  1064 		{//no potential SEPs were found so cannot proceed any further
  1065 		CancelChangeState(KErrCouldNotConnect);
  1066 		}
  1067 	}
  1068 
  1069 
  1070 /**
  1071 Internal function to get the capability of an individual SEP
  1072 */
  1073 void CGAVDPStateMachine::GetRemoteSEPCapability()
  1074 	{
  1075 	TAvdtpServiceCategories serviceCategories;
  1076 	serviceCategories.SetCapability(EServiceCategoryMediaTransport);
  1077 	serviceCategories.SetCapability(EServiceCategoryMediaCodec);
  1078 	TSEID SEPtoGetCapabilityOf = iPotentialSEPs[iSEPIterator];
  1079 	iGavdp.GetRemoteSEPCapabilities(SEPtoGetCapabilityOf, serviceCategories);
  1080 	iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout));
  1081 	}
  1082 
  1083 
  1084 /**
  1085 Internal function to iterate through the list of potential SEPs and asking
  1086 for the capabilites of each one.
  1087 */	
  1088 void CGAVDPStateMachine::GetRemoteSEPCapabilities()
  1089 	{
  1090 	iSEPCapabilities.ResetAndDestroy(); //clear what's already there
  1091 	iUsableSEPs.Reset();
  1092 	iSEPIterator = 0;
  1093 	iSEPCapabilityEntry = 0;
  1094 	//go and get the capability of the first SEP in the list of potential SEPs
  1095 	//the GAVDP_SEPCapabilityComplete() callback will cause the next potential
  1096 	//SEP capability to be obtained.
  1097 	GetRemoteSEPCapability(); 
  1098 	}
  1099 
  1100 
  1101 /**
  1102 MGavdpUser callback in response to GetRemoteSEPCapabilities
  1103 
  1104 @see MGavdpUser
  1105 */	
  1106 void CGAVDPStateMachine::GAVDP_SEPCapability(TAvdtpServiceCapability* aCapability)
  1107 	{
  1108 	// we own cap, stash it in the iSEPCapabilities array for owning and later use
  1109 	TInt err = iSEPCapabilities.Append(aCapability);
  1110 	if (err)
  1111 		{
  1112 		CancelChangeState(err);
  1113 		}
  1114 	}
  1115 
  1116 
  1117 /**
  1118 MGavdpUser callback in response to GetRemoteSEPCapabilities when all the 
  1119 GAVDP_SEPCapability callbacks have been made for an individual SEP
  1120 
  1121 The function iterates through the SEP capabilites looking for transport and media codec support
  1122 and if so the SEP is added to the list of usableSEPs.
  1123 
  1124 @see MGavdpUser
  1125 */	
  1126 void CGAVDPStateMachine::GAVDP_SEPCapabilityComplete()
  1127 	{
  1128 	TInt err = KErrNone;
  1129 	iSignallingTransactionTimeout->Cancel();
  1130 	//iterate through the capabilities
  1131 	TAvdtpServiceCapability* avdtpServiceCapability;
  1132 	TBool mediaTransport(EFalse);
  1133 	TBool audioSupport(EFalse);
  1134 	TFourCC dataTypeSupport; //note we are assuming here that each SEP only has one codec capability
  1135 	TUint i = 0;
  1136 	//iterate through the capabilities
  1137 	//looking for media transport and codec support
  1138 	for	(;iSEPCapabilityEntry < iSEPCapabilities.Count() ; iSEPCapabilityEntry++)
  1139 		{
  1140 		avdtpServiceCapability = iSEPCapabilities[iSEPCapabilityEntry];
  1141 		switch (avdtpServiceCapability->Category())
  1142 			{
  1143 			case EServiceCategoryMediaTransport:
  1144 				mediaTransport = ETrue;
  1145 				break;
  1146 			case EServiceCategoryMediaCodec:
  1147 				{
  1148 				TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(avdtpServiceCapability);
  1149 				if (codecCaps->MediaType() == EAvdtpMediaTypeAudio)
  1150 					{
  1151 					audioSupport = ETrue;
  1152 					}
  1153 				switch (codecCaps->MediaCodecType())
  1154 					{
  1155 					case EAudioCodecSBC:
  1156 						dataTypeSupport.Set(KMMFFourCCCodeSBC);
  1157 						break;
  1158 					case EAudioCodecMPEG12Audio:
  1159 						dataTypeSupport.Set(KMMFFourCCCodeMP3);
  1160 						break;
  1161 					case EAudioCodecMPEG24AAC:
  1162 						dataTypeSupport.Set(KMMFFourCCCodeAAC);
  1163 						break;
  1164 					case EAudioCodecATRAC:
  1165 						dataTypeSupport.Set(KMMFFourCCCodeATRAC3);
  1166 						break;
  1167 					default:
  1168 						//the datatype is an unsupported datatype
  1169 						//so set to NULL to show we can't use it
  1170 						dataTypeSupport.Set(KMMFFourCCCodeNULL);
  1171 						break;
  1172 					}
  1173 				}
  1174 			}//switch (avdtpServiceCapability->Category())
  1175 		}//	for (TUint i=0; i++; i<iSEPCapabilities.Count())
  1176 	//check if the capabilities indicate that the SEP is usable
  1177 	//for audio transport
  1178 	if ((mediaTransport) && (audioSupport) && 
  1179 		(dataTypeSupport != KMMFFourCCCodeNULL))
  1180 		{//then we can use this SEP to stream audio to the headset
  1181 		// however we ie the Symbian device must
  1182 		//also be able to support the data type
  1183 		//before we can add it to the list of usable SEPs
  1184 		TBool symbianDeviceSupportsDataType(EFalse);
  1185 		for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
  1186 			{
  1187 			if (iSymbianDeviceSEPs[i].iDataType == dataTypeSupport) 
  1188 				{
  1189 				symbianDeviceSupportsDataType = ETrue;
  1190 				break;
  1191 				}
  1192 			}
  1193 		if (symbianDeviceSupportsDataType)
  1194 			{
  1195 			TUsableSEP usableSEP;
  1196 			usableSEP.iSEID = iPotentialSEPs[iSEPIterator];
  1197 			usableSEP.iDataType.Set(dataTypeSupport);
  1198 			err = iUsableSEPs.Append(usableSEP);
  1199 			if (err)
  1200 				{
  1201 				CancelChangeState(err);
  1202 				}
  1203 			}
  1204 		}
  1205 	if (!err)
  1206 		{
  1207 		//check if we have finished going through our list of potential SEPs
  1208 		//that we need to find the capabilities of
  1209 		iSEPIterator++;
  1210 		if (iSEPIterator >= iPotentialSEPs.Count())
  1211 			{//then we have finished getting all the capabilities
  1212 			//so lets choose a SEP by iterating through the
  1213 			//usable SEPs and stopping at the first one that supports the
  1214 			//required data type 
  1215 			TUsableSEP SEP;
  1216 			TBool SEPFound(EFalse);
  1217 			for (i=0; i<iUsableSEPs.Count(); i++)
  1218 				{
  1219 				SEP = iUsableSEPs[i];
  1220 				if (SEP.iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
  1221 					{//one of the usable SEPs supports the requested data type
  1222 					SEPFound = ETrue;
  1223 					iHeadsetSEID = SEP.iSEID; //we'll use this SEID for now			
  1224 					break;
  1225 					}
  1226 				}
  1227 			iSEPIterator = 0;
  1228 			iSEPCapabilityEntry = 0;
  1229 			if (SEPFound)
  1230 				{
  1231 				//we've selected a SEP
  1232 				StateChangeComplete(); //so move on to the next state
  1233 				}
  1234 			else
  1235 				{
  1236 				//then non  of the SEPs have SBC codec capabilites
  1237 				//or no usable SEPs have been found or SEP may be in use
  1238 				//since SBC support is mandatory we do not have a suitable SEP
  1239 				CancelChangeState(KErrCouldNotConnect);
  1240 				}
  1241 			}//	if (iPotentialSEPs.Count() >= iSEPIterator)
  1242 		else
  1243 			{//get the capability of the next SEP
  1244 			GetRemoteSEPCapability();
  1245 			}
  1246 		}
  1247 	}
  1248 
  1249 
  1250 /**
  1251 Function used to return a TAvdtpMediaCodecCapabilities structure
  1252 that can be used to configure the SEP at the remote end ie on the headset
  1253 The capabilities are used to determine the configuration
  1254 need to return by pointer rather than by ref as TAvdtpMediaCodecCapabilities is abstract 
  1255 */
  1256 TAvdtpMediaCodecCapabilities* CGAVDPStateMachine::RemoteCodecConfiguration()
  1257 	{
  1258 	TAvdtpMediaCodecCapabilities* codecCaps = NULL;
  1259 	TAvdtpMediaCodecCapabilities* codecConfiguration = NULL;
  1260 	
  1261 	//first get the capabilities of the codec
  1262 	TInt error = CodecCaps(codecCaps);
  1263 	if (!error)
  1264 		{//and use the capabilities to get a valid remote codec configuration
  1265 		codecConfiguration = iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*codecCaps);
  1266 		}
  1267 
  1268 	return codecConfiguration;
  1269 	}
  1270 
  1271 
  1272 /**
  1273 Internal function to configure the local SEP
  1274 */	
  1275 TInt CGAVDPStateMachine::ConfigureLocalSEP()
  1276 	{
  1277 	TInt err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID);
  1278 	if (err == KErrNotFound)
  1279 		{
  1280 		//could be a problem with the local SEP no longer being registered
  1281 		//so register and try again
  1282 		err = RegisterLocalSEP();
  1283 		if (!err)
  1284 			{
  1285 			err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID);
  1286 			}
  1287 		}
  1288 	if (!err)
  1289 		{//configure local SEP - we only advertise one local SEP with SBC support
  1290 		//in future when capability structures are defined for mp3,AAC,ATRAC3
  1291 		//then these can also be advertised as local SEPs
  1292 		TAvdtpMediaTransportCapabilities media;
  1293 		err = iGavdp.AddSEPCapability(media);
  1294 		
  1295 		if (!err)
  1296 			{
  1297 			CA2dpLocalCodecCapabilities* localCodecCapabilities = NULL;
  1298 			TRAP(err, localCodecCapabilities = CA2dpLocalCodecCapabilities::NewL())
  1299 			if (!err)
  1300 				{
  1301 				TAvdtpMediaCodecCapabilities* localSEPCapability = localCodecCapabilities->LocalCodecCapabilities(iA2dpCodecSettings.HeadsetCodecDataType());
  1302 				if (localSEPCapability)
  1303 					{
  1304 					err = iGavdp.AddSEPCapability(*localSEPCapability);
  1305 					}
  1306 				else
  1307 					{
  1308 					err = KErrNoMemory;
  1309 					}
  1310 				delete localCodecCapabilities;
  1311 				localCodecCapabilities = NULL;
  1312 				}
  1313 			}	
  1314 		}
  1315 	return err;
  1316 	}
  1317 
  1318 
  1319 /**
  1320 Internal function to configure the remote SEP ie the headset
  1321 
  1322 If the SEP has never been configured before then the transport caps are added
  1323 If we are doing a reconfigure of the remote SEP then just the codec caps are added
  1324 */
  1325 TInt CGAVDPStateMachine::ConfigureRemoteSEP()
  1326 	{
  1327 	TInt err = iGavdp.BeginConfiguringRemoteSEP(iHeadsetSEID, iSymbianDeviceSEID);
  1328 	if (!err)
  1329 		{
  1330 		if ((iInitialState.State() < TGAVDPState::EConfigured)||(iChangeOfSelectedHeadsetSEP))
  1331 			{//then this SEP has never been configured before
  1332 			//in which case we need to configure it with transport capabilities
  1333 			//note that if the SEP has been configured before ie the above condition
  1334 			//is false then we are performing a reconfiguration and are not allowed
  1335 			//to reconfigure the media transport capabilities
  1336 			TAvdtpMediaTransportCapabilities avdtpMediaTransportCapabilities;
  1337 			err = iGavdp.AddSEPCapability(avdtpMediaTransportCapabilities);
  1338 			iChangeOfSelectedHeadsetSEP = EFalse;//reset
  1339 			}
  1340 		if (!err)
  1341 			{
  1342 			TAvdtpMediaCodecCapabilities* codecConfiguration = RemoteCodecConfiguration();
  1343 			//note we are setting a configuration here not a capability
  1344 			if (codecConfiguration)
  1345 				{
  1346 				err = iGavdp.AddSEPCapability(*codecConfiguration);
  1347 				}
  1348 			else
  1349 				{//we were not able to get a valid configuration
  1350 				//so abort configuration
  1351 				err = KErrAbort;
  1352 				}
  1353 			}//	if (!err)
  1354 		}
  1355 	return err;
  1356 	}
  1357 
  1358 
  1359 /**
  1360 Internal function to initiate SEP configuration of both the local and remote SEPs
  1361 */			
  1362 void CGAVDPStateMachine::ConfigureSEP()
  1363 	{
  1364 	if (iHeadsetSEID.IsValid())
  1365 		{
  1366 		TInt err;
  1367 		if (!iLocalSEPConfigured)
  1368 			{//the local SEP must be configured first before configuring the remote SEP
  1369 			err = ConfigureLocalSEP();	
  1370 			}
  1371 		else
  1372 			{//local SEP is already configured so configure remote SEP
  1373 			err = ConfigureRemoteSEP();
  1374 			}
  1375 		if (err)
  1376 			{
  1377 			CancelChangeState(err);
  1378 			}
  1379 		else
  1380 			{
  1381 			iGavdp.CommitSEPConfiguration();
  1382 			}
  1383 		}
  1384 	else
  1385 		{//we've requested to configure a SEP before we have
  1386 		//a valid SEP to configure
  1387 		CancelChangeState(KErrNotReady);
  1388 		}
  1389 	}
  1390 	
  1391 
  1392 /**
  1393 MGavdpUser callback to confirm that the SEP configuration has been acepted
  1394 This callback should occur for both the local SEP and the remote SEP 
  1395 */
  1396 void CGAVDPStateMachine::GAVDP_ConfigurationConfirm()
  1397 	{
  1398 	TInt err = KErrNone;
  1399 	if (!iLocalSEPConfigured)
  1400 		{//the local SEP is configured first so this call back must be from
  1401 		 //a local SEP configuration
  1402 		iLocalSEPConfigured = ETrue;
  1403 		//now configure the remote SEP
  1404 		err = ConfigureRemoteSEP();
  1405 		if (!err)
  1406 			{
  1407 			iGavdp.CommitSEPConfiguration();
  1408 			}
  1409 		else
  1410 			{
  1411 			CancelChangeState(err);
  1412 			}
  1413 		}
  1414 	else
  1415 		{
  1416 		//local and remote SEPs now configured
  1417 		TInt err = iGavdp.Listen();	
  1418 		//note that if there is an error above
  1419 		// there is not much we can do so ignore it
  1420 		StateChangeComplete();
  1421 		}
  1422 	}
  1423 	
  1424 
  1425 /**
  1426 Internal function to request a bearer RSocket in order to stream audio to the headset
  1427 */
  1428 void CGAVDPStateMachine::CreateBearerSocket()
  1429 	{
  1430 	//then we need to request for one from the remote SEP
  1431 	//this reference code does not support reporting and recovery channels
  1432 
  1433 	if (!iBearerSocket.SubSessionHandle())
  1434 		{//we don't already have a bearer socket, create one - note no reporting and recovery implementation
  1435 		TInt err = iGavdp.CreateBearerSockets(iHeadsetSEID, EFalse, EFalse);
  1436 		if (err)
  1437 			{
  1438 			CancelChangeState(err);
  1439 			}
  1440 		}
  1441 	else
  1442 		{
  1443 		//we already have a bearer socket so no need to create a new one
  1444 		//just complete the state change
  1445 		StateChangeComplete();
  1446 		}
  1447 	}
  1448 	
  1449 
  1450 /**
  1451 MGavdpUser callback to supply the RSocket used to stream audio to the headset
  1452 
  1453 This callback can occur either via a direct request from the headset or in response
  1454 to a CreateBearerSocket
  1455 
  1456 @see MGavdpUser
  1457 */
  1458 void CGAVDPStateMachine::GAVDP_BearerReady(RSocket aSocket, const TAvdtpSockAddr& /*aAddress*/)
  1459 	{
  1460 	//This call back can occur without a prior call to CreateBearerSocket
  1461 	iBearerSocket = aSocket;
  1462 	if ((iCurrentState == TGAVDPState::EConfigured)&&(iStateChangeInProgress))
  1463 		{//we've completed the state	
  1464 		StateChangeComplete();
  1465 		}
  1466 	// else this came from the headset without a call to RGavdp::CreateBearerSockets
  1467 	}
  1468 
  1469 
  1470 /**
  1471 Function to return an array of usable SEPs on the headset.
  1472 By 'usable' we mean the SEP supports audio, has media transport caps, is not in use,
  1473 has a supported audio codec and the audio codec is supported by the symbianOS device
  1474 @return array of usable SEPs
  1475 */	
  1476 RArray<TUsableSEP>& CGAVDPStateMachine::UsableSEPs() const
  1477 	{
  1478 	return const_cast<RArray<TUsableSEP>&>(iUsableSEPs);
  1479 	}
  1480 
  1481 
  1482 /**
  1483 Function to return the bearer socket used to stream audio to the headset
  1484 @return socket
  1485 */	
  1486 RSocket& CGAVDPStateMachine::BearerSocket() const
  1487 	{
  1488 	return const_cast<RSocket&>(iBearerSocket);
  1489 	}
  1490 
  1491 
  1492 /**
  1493 Function to return the headset BT address
  1494 @return headset BT address
  1495 */	
  1496 TBTDevAddr& CGAVDPStateMachine::BTAddress() const
  1497 	{
  1498 	return const_cast<TBTDevAddr&>(iBTDevAddr);
  1499 	}
  1500 
  1501 
  1502 /** 
  1503 Function to return the SEPCapability for the codec settings
  1504 used by CA2dpBTHeadsetAudioInterface to determine the audio settings
  1505 ie sample rate / stereo support.
  1506 aCodecCaps is set with the TAvdtpMediaCodecCapabilities of the codec in use
  1507 if no codec has been specified via the Reconfigure()	function then
  1508 the codec defaults to SBC
  1509 returns KErrNotReady if no SEP capablities have been obtained from the SEP
  1510 return KErrNotSupported if the codec type is not known
  1511 aCodecCaps Note that ownership is not transferred to the calling class.
  1512 
  1513 @param aCodecCaps  The pointer points to a codec capabilities structure
  1514 
  1515 @return SymbianOS error code
  1516 */
  1517 TInt CGAVDPStateMachine::CodecCaps(TAvdtpMediaCodecCapabilities*& aCodecCaps) const
  1518 	{
  1519 	TInt err = KErrNotReady;
  1520 	TAvdtpServiceCapability* avdtpServiceCapability;
  1521 	TFourCC dataType;
  1522 	for (TUint i=0;  i<iSEPCapabilities.Count(); i++)
  1523 		{
  1524 		avdtpServiceCapability = iSEPCapabilities[i];
  1525 		if (avdtpServiceCapability->Category() == EServiceCategoryMediaCodec)
  1526 			{
  1527 			TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(avdtpServiceCapability);
  1528 			switch (codecCaps->MediaCodecType())
  1529 				{
  1530 				case EAudioCodecSBC:
  1531 					dataType.Set(KMMFFourCCCodeSBC);
  1532 					break;
  1533 				case EAudioCodecMPEG12Audio:
  1534 					dataType.Set(KMMFFourCCCodeMP3);
  1535 					break;
  1536 				case EAudioCodecMPEG24AAC:
  1537 					dataType.Set(KMMFFourCCCodeAAC);
  1538 					break;
  1539 				case EAudioCodecATRAC:
  1540 					dataType.Set(KMMFFourCCCodeATRAC3);
  1541 					break;
  1542 				default:
  1543 					err = KErrNotSupported;
  1544 					break;
  1545 				}
  1546 			if (dataType == iA2dpCodecSettings.HeadsetCodecDataType())
  1547 				{//then we have the capabilities for the selected datatype
  1548 				aCodecCaps = codecCaps;
  1549 				err = KErrNone;
  1550 				break;
  1551 				}	
  1552 			}	
  1553 		}	//for (TUint i=0;  i<iSEPCapabilities.Count(); i++)
  1554 	return err;
  1555 	}
  1556 	
  1557 
  1558 /**
  1559 MGavdpUser callback when headset releases stream
  1560 
  1561 @see MGavdpUser
  1562 */
  1563 void CGAVDPStateMachine::GAVDP_ReleaseIndication(TSEID aSEID)
  1564 	{
  1565 	if (aSEID == iSymbianDeviceSEID)
  1566 		{
  1567 		if (iStateChangeInProgress)
  1568 			{
  1569 			CancelChangeState(KErrDisconnected);
  1570 			}			
  1571 		else
  1572 			{
  1573 			iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrDisconnected);
  1574 			}
  1575 		TInt err = iGavdp.Listen();//can't do much if this errors
  1576 		}
  1577 	}
  1578 
  1579 
  1580 /**
  1581 MGavdpUser error callback 
  1582 
  1583 @see MGavdpUser
  1584 */
  1585 void CGAVDPStateMachine::GAVDP_Error(TInt aError, const TDesC8& /*aErrorData*/)
  1586 	{	
  1587 	TInt error = ConvertToStandardSymbianOSError(aError);
  1588 	if (iStateChangeInProgress)
  1589 		{
  1590 		CancelChangeState(error);
  1591 		}
  1592 	else
  1593 		{
  1594 		//error must have occured while no state change was in progress
  1595 		//this could be due to a problem on the headset eg no longer in range
  1596 		//Make callback on a2dpBTHeadsetIf so it can reset back to the idle state
  1597 		iGAVDPStateChangeObserver.GAVDPStateMachineEvent(error);
  1598 		}
  1599 	//start listening for connect event from headset
  1600 	TInt err = iGavdp.Listen();//can't do much if this errors	
  1601 	}
  1602 
  1603 
  1604 /**
  1605 Internal function to put the headset in the streaming state
  1606 */	
  1607 void CGAVDPStateMachine::StartStream()
  1608 	{
  1609 	//we're only going to start one transport stream
  1610 	iGavdp.StartStream(iHeadsetSEID);
  1611 	}
  1612 
  1613 
  1614 /**
  1615 MGavdpUser callback in response to StartStream
  1616 
  1617 @see MGavdpUser
  1618 */	
  1619 void CGAVDPStateMachine::GAVDP_StartStreamsConfirm()
  1620 	{
  1621 	StateChangeComplete();
  1622 	}
  1623 
  1624 
  1625 /**
  1626 Internal function to tell the headset we are suspending the stream
  1627 */	
  1628 void CGAVDPStateMachine::SuspendStream()
  1629 	{
  1630 	//we're only going to suspend one transport stream
  1631 	iGavdp.SuspendStream(iHeadsetSEID);
  1632 	}
  1633 
  1634 
  1635 /**
  1636 MGavdpUser callback in response to SuspendStream
  1637 
  1638 @see MGavdpUser
  1639 */	
  1640 void CGAVDPStateMachine::GAVDP_SuspendStreamsConfirm()
  1641 	{
  1642 	StateChangeComplete();
  1643 	}
  1644 
  1645 	
  1646 /**
  1647 RunsL for GAVDP state machine
  1648 */
  1649 void CGAVDPStateMachine::RunL()
  1650 	{
  1651 	if (iStateChangeInProgress)
  1652 		{
  1653 		switch (iCurrentState.State())
  1654 			{
  1655 			case TGAVDPState::EGAVDPIdle:
  1656 				ConnectToGAVDP();
  1657 				break;
  1658 			case TGAVDPState::EConnectedToGavdp:
  1659 				DiscoverRemoteSEPs();
  1660 				break;
  1661 			case TGAVDPState::ESEPsDiscovered:
  1662 				GetRemoteSEPCapabilities();
  1663 				break;
  1664 			case TGAVDPState::ESEPSelected:
  1665 				ConfigureSEP();
  1666 				break;
  1667 			case TGAVDPState::EConfigured:
  1668 				CreateBearerSocket();
  1669 				break;
  1670 			case TGAVDPState::EGAVDPOpen:
  1671 				StartStream();
  1672 				break;
  1673 			case TGAVDPState::EGAVDPStreaming:
  1674 				SuspendStream();
  1675 				break;
  1676 			default:
  1677 				Panic(EGavdpStateMachineBadState);
  1678 				break;
  1679 			}
  1680 		}
  1681 	else
  1682 		{
  1683 		//if RunL should get called when no state
  1684 		//change is in progress eg during a reconfiguration
  1685 		//then the current state should always be identical to the target state
  1686 		__ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));
  1687 		StateChangeComplete();
  1688 		}
  1689 	}
  1690 
  1691 
  1692 /**
  1693 Cancel
  1694 */
  1695 void CGAVDPStateMachine::DoCancel()
  1696 	{
  1697 	TRequestStatus* stat = &iStatus;
  1698 	User::RequestComplete(stat, KErrCancel);
  1699 	}
  1700 
  1701 
  1702 
  1703 
  1704 CGavdpTimeout* CGavdpTimeout::NewL(CGAVDPStateMachine& aGAVDPStateMachine)
  1705 	{
  1706 	CGavdpTimeout* self = new(ELeave)CGavdpTimeout();
  1707 	CleanupStack::PushL(self);
  1708 	self->ConstructL(aGAVDPStateMachine);
  1709 	CleanupStack::Pop();	
  1710 	return self;
  1711 	}
  1712 
  1713 
  1714 void CGavdpTimeout::ConstructL(CGAVDPStateMachine& aGAVDPStateMachine)
  1715 	{
  1716 	CTimer::ConstructL();
  1717 	CActiveScheduler::Add(this);
  1718 	iGAVDPStateMachine = &aGAVDPStateMachine;
  1719 	}
  1720 
  1721 
  1722 CGavdpTimeout::CGavdpTimeout() : CTimer(EPriorityLow)
  1723 	{
  1724 	}
  1725 
  1726 
  1727 void CGavdpTimeout::StartTimer(TTimeIntervalMicroSeconds32 aTimeInterval)
  1728 	{
  1729 	Cancel(); //just in case
  1730 	After(aTimeInterval);	
  1731 	}
  1732 
  1733 
  1734 void CGavdpTimeout::RunL()
  1735 	{
  1736 	//the GAVDP callback has timed out - check the GAVDP state machine
  1737 	//is in the connected state to cover ourselves in the event of a race
  1738 	//condition
  1739 	if ((iGAVDPStateMachine->State() == TGAVDPState::EConnectedToGavdp)||
  1740 	(iGAVDPStateMachine->State() == TGAVDPState::ESEPsDiscovered))
  1741 		{
  1742 		iGAVDPStateMachine->CancelChangeState(KErrTimedOut);
  1743 		}
  1744 	}
  1745 	
  1746 
  1747