os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/GavdpStateMachine.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/GavdpStateMachine.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1747 @@
     1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "A2dpCodecUtilities.h"
    1.20 +#include "GavdpStateMachine.h"
    1.21 +
    1.22 +
    1.23 +/**
    1.24 +GAVDP State Machine Panics
    1.25 +**/
    1.26 +enum TGavdpStateMachinePanic
    1.27 +	{
    1.28 +	EGavdpStateMachineBadState,//0
    1.29 +	EGavdpStateMachineBadConfigByRemoteHeadsetState,//1
    1.30 +	EGavdpStateMachineBadBTAddr,//2
    1.31 +	EGavdpStateMachineUnexpectedCallback,//3
    1.32 +	EGavdpStateMachineDataTypeMismatch//4
    1.33 +	};
    1.34 +
    1.35 +
    1.36 +static void Panic(TGavdpStateMachinePanic aPanic)
    1.37 +// Panic client
    1.38 +	{
    1.39 +	_LIT(KGavdpStateMachinePanicName, "GAVDP State Mchn");
    1.40 +	User::Panic(KGavdpStateMachinePanicName, aPanic);
    1.41 +	}
    1.42 +
    1.43 +
    1.44 +/**
    1.45 +Utility function to map a bluetooth code to a standard SymbianOS code
    1.46 +Where a standard Symbian error code exists the error is mapped
    1.47 +to the standard code.  Ideally all HCI, L2CAP, AVDTP, GAVDP errors
    1.48 +should be mapped to standard SymbianOS codes since bluetooth specific
    1.49 +error codes aren't meaningful in the multimedia domain
    1.50 +*/
    1.51 +static TInt ConvertToStandardSymbianOSError(TInt aError)
    1.52 +	{
    1.53 +	TInt error;
    1.54 +	
    1.55 +	switch (aError)
    1.56 +		{
    1.57 +		case KHCIErrorBase-EPageTimedOut://-6004
    1.58 +			error = KErrCouldNotConnect;
    1.59 +			break;
    1.60 +		case KHCIErrorBase-EAuthenticationFailure://-6005
    1.61 +			error = KErrCouldNotConnect;
    1.62 +			break;
    1.63 +		case KHCIErrorBase-EPairingNotAllowed: //-6024
    1.64 +			error = KErrCouldNotConnect;
    1.65 +			break;
    1.66 +		case KHCIErrorBase-ELMPResponseTimeout: //-6034
    1.67 +			error = KErrTimedOut;
    1.68 +			break;
    1.69 +		case KErrHCIConnectFailed: //-6304
    1.70 +			error = KErrCouldNotConnect;
    1.71 +			break;
    1.72 +		case KErrHCILinkDisconnection: //-6305
    1.73 +			error = KErrDisconnected;
    1.74 +			break;
    1.75 +		default:
    1.76 +			error = aError;
    1.77 +			break;
    1.78 +		}
    1.79 +	return error;
    1.80 +	}
    1.81 +
    1.82 +
    1.83 +/**
    1.84 +Creates CGAVDPStateMachine
    1.85 +
    1.86 +@internalComponent
    1.87 +@return CGAVDPStateMachine*
    1.88 +*/
    1.89 +CGAVDPStateMachine* CGAVDPStateMachine::NewL(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer)
    1.90 +	{
    1.91 +	CGAVDPStateMachine* self = new(ELeave) CGAVDPStateMachine(aGAVDPStateChangeObserver, aA2dpCodecSettings, aSocketServer);
    1.92 +	CleanupStack::PushL(self);
    1.93 +	self->ConstructL();
    1.94 +	CleanupStack::Pop(self);
    1.95 +	return self;
    1.96 +	}
    1.97 +
    1.98 +
    1.99 +/**
   1.100 +Constructor
   1.101 +[TODO] change default stereo mode to EMMFJoint when hardware has sufficient bandwidth
   1.102 +Note we make the AO priority one less than normal to give the AOs in GAVDP
   1.103 +preference
   1.104 +*/
   1.105 +CGAVDPStateMachine::CGAVDPStateMachine(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer) : CActive(EPriorityNormal-1), 
   1.106 +iGAVDPStateChangeObserver(aGAVDPStateChangeObserver) ,iA2dpCodecSettings(aA2dpCodecSettings), iSocketServer(aSocketServer)
   1.107 +	{
   1.108 +	CActiveScheduler::Add(this);
   1.109 +	}
   1.110 +
   1.111 +
   1.112 +void CGAVDPStateMachine::ConstructL()
   1.113 +	{
   1.114 +	User::LeaveIfError(iGavdp.Open(*this, iSocketServer));
   1.115 +	User::LeaveIfError(RegisterLocalSEP());
   1.116 +	iSignallingTransactionTimeout = CGavdpTimeout::NewL(*this);
   1.117 +	}
   1.118 +	
   1.119 +
   1.120 +/**
   1.121 +Internal function to register local SEPs with GAVDP
   1.122 +The function sets the iSymbianDeviceSEID to the TSEID 
   1.123 +of the Symbian device
   1.124 +*/	
   1.125 +TInt CGAVDPStateMachine::RegisterLocalSEP()
   1.126 +	{
   1.127 +	//register SEPs - currently SBC & mp3 SEPs are supported
   1.128 +	TAvdtpSEPInfo avdtpSEPInfo;	
   1.129 +	avdtpSEPInfo.SetInUse(EFalse);
   1.130 +	avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio);
   1.131 +	avdtpSEPInfo.SetIsSink(EFalse);
   1.132 +	TInt err = iGavdp.RegisterSEP(avdtpSEPInfo);	
   1.133 +	TUsableSEP sep;
   1.134 +	sep.iSEID = avdtpSEPInfo.SEID();
   1.135 +	sep.iDataType = KMMFFourCCCodeSBC;
   1.136 +	err = iSymbianDeviceSEPs.Append(sep);
   1.137 +	
   1.138 +	if (!err)
   1.139 +		{
   1.140 +		avdtpSEPInfo.SetInUse(EFalse);
   1.141 +		avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio);
   1.142 +		avdtpSEPInfo.SetIsSink(EFalse);
   1.143 +		err = iGavdp.RegisterSEP(avdtpSEPInfo);
   1.144 +		if (!err)
   1.145 +			{
   1.146 +			sep.iSEID = avdtpSEPInfo.SEID();
   1.147 +			sep.iDataType = KMMFFourCCCodeMP3;
   1.148 +			err = iSymbianDeviceSEPs.Append(sep);
   1.149 +			}
   1.150 +		}			
   1.151 +	if (!err)
   1.152 +		{
   1.153 +		TBool SEPDataTypeFound(EFalse);
   1.154 +		for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
   1.155 +			{
   1.156 +			if (iSymbianDeviceSEPs[i].iDataType == iA2dpCodecSettings.HeadsetCodecDataType()) 
   1.157 +				{
   1.158 +				iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID;
   1.159 +				SEPDataTypeFound = ETrue;
   1.160 +				break;
   1.161 +				}
   1.162 +			}
   1.163 +		if (!SEPDataTypeFound)
   1.164 +			{
   1.165 +			err = KErrNotFound;
   1.166 +			}
   1.167 +		}
   1.168 +	return err;
   1.169 +	}
   1.170 +
   1.171 +
   1.172 +/**
   1.173 +Standard destructor.
   1.174 +*/
   1.175 +CGAVDPStateMachine::~CGAVDPStateMachine()
   1.176 +	{
   1.177 +	Cancel();
   1.178 +	iBearerSocket.Close();
   1.179 +	iGavdp.Close();
   1.180 +	iPotentialSEPs.Close();
   1.181 +	iUsableSEPs.Close();
   1.182 +	iSymbianDeviceSEPs.Close();
   1.183 +	iSEPCapabilities.ResetAndDestroy();
   1.184 +	iSEPCapabilities.Close();
   1.185 +	delete iSignallingTransactionTimeout;
   1.186 +	}
   1.187 +
   1.188 +
   1.189 +/**
   1.190 +Function to set the Bluetooth address of the headset.
   1.191 +
   1.192 +@param aRemoteAddress Bluetooth address of the headset
   1.193 +*/
   1.194 +void CGAVDPStateMachine::SetBTAddress(const TBTDevAddr& aRemoteAddress)
   1.195 +	{
   1.196 +	if (iBTDevAddr != aRemoteAddress)
   1.197 +		{//must be using a new headet so reset state machine
   1.198 +		Reset();
   1.199 +		iBTDevAddr = aRemoteAddress;
   1.200 +		}
   1.201 +	}
   1.202 +	
   1.203 +	
   1.204 +/**
   1.205 +Function to returns the current state of the GAVDP state machine.
   1.206 +
   1.207 +@return the current state of the GAVDP state machine
   1.208 +*/
   1.209 +TGAVDPState CGAVDPStateMachine::State() const
   1.210 +	{
   1.211 +	return iCurrentState ;
   1.212 +	}
   1.213 +
   1.214 +
   1.215 +/**
   1.216 +Internal function to resets the GAVDP state machine to the EGAVDPIdle state
   1.217 +Note that if the headset is already connected Reseting
   1.218 +will cause a subsequent call to RGavdp.Connect, however
   1.219 +if we are already connected this should complete straight away
   1.220 +
   1.221 +Note we don't close the bearer socket here as we need to ensure
   1.222 +this is closed after the RTP streamer is deleted so this is handled by the CA2dpBTHeadsetAudioInterface
   1.223 +*/
   1.224 +void CGAVDPStateMachine::Reset()
   1.225 +	{
   1.226 +	iPotentialSEPs.Reset();
   1.227 +	iUsableSEPs.Reset();
   1.228 +	iSEPCapabilities.ResetAndDestroy();
   1.229 +	iSEPIterator = 0;
   1.230 +	iSEPCapabilityEntry = 0;
   1.231 +	iA2dpCodecSettings.Reset();
   1.232 +	iInitialState = TGAVDPState::EGAVDPIdle;
   1.233 +	iCurrentState = TGAVDPState::EGAVDPIdle;
   1.234 +	iNextState = TGAVDPState::EGAVDPIdle;
   1.235 +	iTargetState = TGAVDPState::EGAVDPIdle;
   1.236 +	iConfigurationByRemoteHeadsetState.Reset();
   1.237 +	iHeadsetSEID.Reset();
   1.238 +	iLocalSEPConfigured = EFalse;
   1.239 +	iChangeOfSelectedHeadsetSEP = EFalse;
   1.240 +	iGavdp.Cancel();
   1.241 +	iSignallingTransactionTimeout->Cancel();
   1.242 +	}
   1.243 +
   1.244 +
   1.245 +/**
   1.246 +Function to move the GAVDP state machine to the state specified in aNewState
   1.247 +Not all state changes are allowed, however. 
   1.248 +Permitted state changes are anystate to ->EGAVDPIdle,EConnectedToGavdp,ESEPsDiscovered
   1.249 +which causes a reset.  
   1.250 +Anything prior to EGAVDPOpen->EGAVDPOpen
   1.251 +EGAVDPOpen->EGAVDPStreaming
   1.252 +EGAVDPStreaming->EGAVDPOpen
   1.253 +
   1.254 +When the state change is completed a GAVDPStateChangeComplete callback is 
   1.255 +made on the MGAVDPStateChangeObserver, which is the CA2dpBTHeadsetAudioInterface
   1.256 +
   1.257 +@param aNewState The state we wish to go to
   1.258 +@return standard SymbianOS error code
   1.259 +*/
   1.260 +TInt CGAVDPStateMachine::ChangeState(const TGAVDPState& aNewState)
   1.261 +	{
   1.262 +	if (iStateChangeInProgress)
   1.263 +		{//can't change state if a state change is already in progress
   1.264 +		return KErrNotReady; 
   1.265 +		}
   1.266 +	if (aNewState.State()<= TGAVDPState::ESEPSelected)
   1.267 +		{
   1.268 +		//if the state is ESEPSelected or less then
   1.269 +		//the assumption is we need to reselect the SEP and in
   1.270 +		//effect redo the entire initialization prior to selecting the SEP
   1.271 +		//therefore roll back to EGAVDPIdle and reset.
   1.272 +		Reset();
   1.273 +		}
   1.274 +	else if (aNewState == TGAVDPState::EGAVDPStreaming)
   1.275 +		{
   1.276 +		//must be in the EGAVDPOpen state in order to go to EGAVDPStreaming
   1.277 +		if (iCurrentState != TGAVDPState::EGAVDPOpen)
   1.278 +			{
   1.279 +			return KErrNotReady;
   1.280 +			}
   1.281 +		}
   1.282 +		
   1.283 +	if (aNewState == iCurrentState)
   1.284 +		{
   1.285 +		//then we are already in the requested state so don't move to
   1.286 +		//next state- so just call the RunL and complete
   1.287 +		iStateChangeInProgress = EFalse;//we're not going to change the state
   1.288 +		TRequestStatus* stat = &iStatus;
   1.289 +		if (!IsActive())
   1.290 +			{
   1.291 +			User::RequestComplete(stat, KErrNone);
   1.292 +			SetActive();
   1.293 +			}
   1.294 +		}
   1.295 +	else
   1.296 +		{//need to move to the next state
   1.297 +		iInitialState = iCurrentState; //incase we need to wind back if state change fails
   1.298 +		iTargetState = aNewState;
   1.299 +		NextState();
   1.300 +		}
   1.301 +	return KErrNone;
   1.302 +	}
   1.303 +
   1.304 +
   1.305 +/**
   1.306 +Function to cause a reconfiguration of the SEP.  The function determines 
   1.307 +whether a reconfiguration is required ie becuase the settings have changed.
   1.308 +And if so the SEP is reconfigured or a new SEP is selected if the reconfiguration
   1.309 +results in a change of SEP ie because the datatype has changed
   1.310 +This function makes a GAVDPStateChangeComplete callback on the CA2dpBTHeadsetAudioInterface
   1.311 +If the SEP changes because of a change in data type then the 	iChangeOfSelectedHeadsetSEP
   1.312 +flag is set which is used by the state machine to cause the media transport
   1.313 +caps to be added to the SEP
   1.314 +
   1.315 +@param aSettingsHaveChanged set to ETrue if the settings have changed
   1.316 +
   1.317 +@return SymbianOS error code
   1.318 +*/	
   1.319 +TInt CGAVDPStateMachine::Reconfigure(TBool aSettingsHaveChanged)
   1.320 +	{
   1.321 +	//not allowed to reconfigure in the middle of a state change	
   1.322 +	if ((iStateChangeInProgress)||(IsActive()))
   1.323 +		{
   1.324 +		return KErrNotReady;
   1.325 +		}	
   1.326 +		
   1.327 +	//in order to perform a reconfigure the current state must
   1.328 +	//be either EConfigured or EGAVDPOpen
   1.329 +	//reconfiguration by the SymbianOs device in the streaming state is not supported
   1.330 +	//in this implementation even though it is allowed by the GAVDP profile
   1.331 +	if ((iCurrentState != TGAVDPState::EConfigured) &&
   1.332 +		(iCurrentState != TGAVDPState::EGAVDPOpen))
   1.333 +		{
   1.334 +		return KErrNotReady;
   1.335 +		}
   1.336 +		
   1.337 +	__ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));//this should always be true if no state change is in progress
   1.338 +	
   1.339 +	iChangeOfSelectedHeadsetSEP = EFalse;
   1.340 +	if (aSettingsHaveChanged)
   1.341 +		{//then see if we need to change SEP
   1.342 +		//data type has changed so we need to choose a different SEP
   1.343 +		//and configure it
   1.344 +		//note if no match is found then we go with the exiting
   1.345 +		//selected SEP
   1.346 +		for (TUint i=0;  i<iUsableSEPs.Count() ; i++)
   1.347 +			{
   1.348 +			TUsableSEP sep = iUsableSEPs[i];
   1.349 +			if (sep.iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
   1.350 +				{//then we have a match so use this SEP
   1.351 +				if (sep.iSEID != iHeadsetSEID)
   1.352 +					{//then this is a different SEP to the one we were already using
   1.353 +					iHeadsetSEID = sep.iSEID;
   1.354 +					iLocalSEPConfigured = EFalse;
   1.355 +					iChangeOfSelectedHeadsetSEP = ETrue;//need to config transport capabilites again if change of SEP
   1.356 +					//need to change the symbian device SEP as well
   1.357 +					TBool symbianDeviceSupportsNewSEPDataType(EFalse);
   1.358 +					for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
   1.359 +						{
   1.360 +						if (iSymbianDeviceSEPs[i].iDataType == sep.iDataType) 
   1.361 +							{
   1.362 +							iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID;
   1.363 +							symbianDeviceSupportsNewSEPDataType = ETrue;
   1.364 +							break;
   1.365 +							}
   1.366 +						}
   1.367 +					__ASSERT_DEBUG(symbianDeviceSupportsNewSEPDataType, Panic(EGavdpStateMachineDataTypeMismatch));
   1.368 +					
   1.369 +					//the if condition below is totaly unnecesaary since we have already
   1.370 +					//ASSERTed symbianDeviceSupportsNewSEPDataType, however the ARM 5 compiler
   1.371 +					//does not seem to recognize code in ASSERT statements so the if statement
   1.372 +					//supresses an ARM v5 compiler warning
   1.373 +					if (symbianDeviceSupportsNewSEPDataType)
   1.374 +						{
   1.375 +						iBearerSocket.Close(); //if we change headset SEP then the old bearer is no longer valid 
   1.376 +						}
   1.377 +					}
   1.378 +				}
   1.379 +			}
   1.380 +		}
   1.381 +		
   1.382 +	
   1.383 +		
   1.384 +	//if a reconfigure is required then we need to reset the current state
   1.385 +	//to ESEPSelected and reconfigure 
   1.386 +	iInitialState = iCurrentState; //incase we need to wind back if state change fails
   1.387 +	
   1.388 +	if ((aSettingsHaveChanged)||(iChangeOfSelectedHeadsetSEP))
   1.389 +		{
   1.390 +		iTargetState = iCurrentState;  //need to end up in the same state we started at
   1.391 +		iCurrentState = TGAVDPState::ESEPSelected; //roll back the state machine to ESEPSelected
   1.392 +		iNextState = iCurrentState;
   1.393 +		NextState(); //make sure the NextState is EConfigured
   1.394 +		}
   1.395 +	else
   1.396 +		{//go to RunL to make GAVDPStateChangeComplete callback
   1.397 +		if (!IsActive())
   1.398 +			{
   1.399 +			TRequestStatus* stat = &iStatus;
   1.400 +			User::RequestComplete(stat, KErrNone);
   1.401 +			SetActive();
   1.402 +			}
   1.403 +		}
   1.404 +	return KErrNone;
   1.405 +	}
   1.406 +
   1.407 +
   1.408 +/**
   1.409 +Advance to Next state
   1.410 +*/	
   1.411 +void CGAVDPStateMachine::NextState()
   1.412 +	{
   1.413 +	iStateChangeInProgress = ETrue;
   1.414 +	TRequestStatus* stat = &iStatus;
   1.415 +	++iNextState;
   1.416 +	if (!IsActive())
   1.417 +		{
   1.418 +		User::RequestComplete(stat, KErrNone);
   1.419 +		SetActive();
   1.420 +		}
   1.421 +	}
   1.422 +	
   1.423 +
   1.424 +/**
   1.425 +Internal function to complete the state change
   1.426 +*/	
   1.427 +void CGAVDPStateMachine::StateChangeComplete()
   1.428 +	{
   1.429 +	iCurrentState = iNextState;
   1.430 +	if (iCurrentState == iTargetState)
   1.431 +		{
   1.432 +		iStateChangeInProgress = EFalse;
   1.433 +		iGAVDPStateChangeObserver.GAVDPStateChangeComplete(iInitialState, KErrNone);
   1.434 +		}
   1.435 +	else
   1.436 +		{//we've completed the internal state change but have not reached the target state
   1.437 +		NextState();
   1.438 +		}
   1.439 +	}
   1.440 +
   1.441 +
   1.442 +/**
   1.443 +Function to cancel a state change initialited by the ChangeState function
   1.444 +This function is called when the change state is explicitly cancelled by the client
   1.445 +*/
   1.446 +void CGAVDPStateMachine::CancelChangeState()
   1.447 +	{
   1.448 +	//if we call this externally then the reason is KErrCancel
   1.449 +	//as the state change has been explicitely cancelled
   1.450 +	CancelChangeState(KErrCancel);
   1.451 +	}
   1.452 +
   1.453 +	
   1.454 +/**
   1.455 +Internal function to cancel a state change initiated by the ChangeState function
   1.456 +Usually called when an error occurs that would prevent the state change
   1.457 +from completing
   1.458 +*/	
   1.459 +void CGAVDPStateMachine::CancelChangeState(TInt aReason)
   1.460 +	{
   1.461 +	if (iStateChangeInProgress)
   1.462 +		{//unwind the request as far as possible
   1.463 +		switch (iInitialState.State())
   1.464 +			{
   1.465 +			case TGAVDPState::EGAVDPIdle:
   1.466 +				Reset();
   1.467 +				break;
   1.468 +			case TGAVDPState::EGAVDPOpen:
   1.469 +				iGavdp.Cancel();
   1.470 +				iCurrentState = TGAVDPState::EGAVDPOpen;
   1.471 +				iNextState = TGAVDPState::EGAVDPOpen;
   1.472 +				iTargetState = TGAVDPState::EGAVDPOpen;
   1.473 +				break;
   1.474 +			case TGAVDPState::EGAVDPStreaming:
   1.475 +				iGavdp.Cancel();
   1.476 +				iNextState = TGAVDPState::EGAVDPStreaming;
   1.477 +				iTargetState = TGAVDPState::EGAVDPStreaming;
   1.478 +				break;
   1.479 +			default:
   1.480 +				Panic(EGavdpStateMachineBadState);
   1.481 +				break;		
   1.482 +			}	
   1.483 +		}
   1.484 +	if (IsActive())
   1.485 +		{
   1.486 +		Cancel();
   1.487 +		}
   1.488 +	iStateChangeInProgress = EFalse;
   1.489 +	iGAVDPStateChangeObserver.GAVDPStateChangeComplete(iInitialState, aReason);
   1.490 +	}
   1.491 +	
   1.492 +
   1.493 +/**
   1.494 +Internal function to initiate the connection to the headset
   1.495 +*/
   1.496 +void CGAVDPStateMachine::ConnectToGAVDP()
   1.497 +	{
   1.498 +	iGavdp.Connect(iBTDevAddr);
   1.499 +	}
   1.500 +	
   1.501 +
   1.502 +/**
   1.503 +MGavdpUser callback to indicate the headset is connected
   1.504 +
   1.505 +@see MGavdpUser
   1.506 +*/	
   1.507 +void CGAVDPStateMachine::GAVDP_ConnectConfirm(const TBTDevAddr& aDevice)
   1.508 +	{
   1.509 +	if (!iStateChangeInProgress)
   1.510 +		{//connect initiated by remote headset so we'll accept the address
   1.511 +		iBTDevAddr = aDevice;
   1.512 +		iCurrentState == TGAVDPState::EConnectedToGavdp;
   1.513 +		}
   1.514 +	else if (iBTDevAddr == aDevice)
   1.515 +		{//if a state change is in progress then we have already set the bt
   1.516 +		//address so the above should be true
   1.517 +		//if its not we'll treat the connect as a spurious connect and ignore
   1.518 +		if (iCurrentState.State() == TGAVDPState::EGAVDPIdle)
   1.519 +			{//if the above isn't true then must be a spurious connect from the headset
   1.520 +			//now connected to the device in question
   1.521 +			StateChangeComplete();
   1.522 +			}	
   1.523 +		}
   1.524 +	}
   1.525 +
   1.526 +
   1.527 +/**
   1.528 +MGavdpUser callback to indicate the headset has suspended streaming
   1.529 +Makes a GAVDPStateMachineStreamSuspendedByRemoteHeadset MGAVDPStateChangeObserver
   1.530 +callback on the CA2dpBTHeadsetAudioInterface
   1.531 +
   1.532 +@see MGavdpUser
   1.533 +*/
   1.534 +TInt CGAVDPStateMachine::GAVDP_SuspendIndication(TSEID aSEID)
   1.535 +	{
   1.536 +	TInt err = KErrNone;
   1.537 +	//first check the callback is for the symbian device SEP we are using to 
   1.538 +	//send data to the a2dp headset - incase the Symbian device has more than one SEP
   1.539 +	if (aSEID == iSymbianDeviceSEID)
   1.540 +		{
   1.541 +		__ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   1.542 +	
   1.543 +		//need to stop the RTP streamer from sending more packets to the headset
   1.544 +		iGAVDPStateChangeObserver.GAVDPStateMachineStreamSuspendedByRemoteHeadset();
   1.545 +	
   1.546 +		iCurrentState = TGAVDPState::EGAVDPSuspended;
   1.547 +		}
   1.548 +	else
   1.549 +		{
   1.550 +		err = ConvertToSymbianError::AvdtpError(EAvdtpBadACPSEID);
   1.551 +		}
   1.552 +	return err;
   1.553 +	}
   1.554 +
   1.555 +
   1.556 +/**
   1.557 +MGavdpUser callback to indicate the headset wished to configure the SymbianDevice
   1.558 +
   1.559 +@see MGavdpUser
   1.560 +*/
   1.561 +void CGAVDPStateMachine::GAVDP_ConfigurationStartIndication(TSEID aLocalSEID, TSEID aRemoteSEID)
   1.562 +	{
   1.563 +	//first check the callback is for the symbian device SEP we are using to 
   1.564 +	//send data to the a2dp headset - incase the Symbian device has more than one SEP
   1.565 +	if (aLocalSEID == iSymbianDeviceSEID)
   1.566 +		{
   1.567 +		__ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   1.568 +		__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ENotBeingConfiguredByRemoteHeadset, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   1.569 +	
   1.570 +		//cancel any current state changes - config is being driven by headset
   1.571 +		Cancel();
   1.572 +		iGavdp.Cancel();
   1.573 +		//no timeouts are required as if the headset goes down ie does not 
   1.574 +		//result in the expected GAVDP_ConfigurationIndication callbacks a GAVDP_Error
   1.575 +		//callback occurs.
   1.576 +		
   1.577 +		iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart;
   1.578 +		
   1.579 +		//we just store the remote SEP for now
   1.580 +		iConfigurationByRemoteHeadsetState.SetSEPRequestedByRemoteHeadset(aRemoteSEID);
   1.581 +		}
   1.582 +	//	else we can't return an error if the aLocalSEID is not for the SymbianOS device
   1.583 +	}
   1.584 +	
   1.585 +
   1.586 +/**
   1.587 +MGavdpUser callback to request the SymbianOS device to take the configuration passed in aCapability
   1.588 +Only SBC reconfigurations by the remote headset are supported, sample rate changes
   1.589 +are not supported, changes in the number of channels are not suported
   1.590 +if the capability is TSBCCodecCapabilities then the function checks that the values
   1.591 +requested can be accepted.
   1.592 +
   1.593 +@see MGavdpUser
   1.594 +*/
   1.595 +TInt CGAVDPStateMachine::GAVDP_ConfigurationIndication(TAvdtpServiceCapability* aCapability)
   1.596 +	{
   1.597 +	//the underlying GAVDP/AVDTP code should ensure that this 
   1.598 +	//callback from GAVDP never occurs once the headset has been configured	
   1.599 +	__ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   1.600 +	__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   1.601 +		
   1.602 +	TInt err = KErrNone;
   1.603 +
   1.604 +	switch(aCapability->Category())
   1.605 +		{
   1.606 +		case EServiceCategoryMediaTransport:
   1.607 +			{
   1.608 +			TAvdtpMediaTransportCapabilities* mediaTransportCaps = static_cast<TAvdtpMediaTransportCapabilities*>(aCapability);
   1.609 +			iConfigurationByRemoteHeadsetState.SetTransportCapsRequestedByRemoteHeadset(mediaTransportCaps);
   1.610 +			}
   1.611 +			break;
   1.612 +		case EServiceCategoryMediaCodec:
   1.613 +			{
   1.614 +			TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(aCapability);
   1.615 +			if (codecCaps->MediaType() != EAvdtpMediaTypeAudio)
   1.616 +				{
   1.617 +				err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec);
   1.618 +				}
   1.619 +			//we're only going to allow a reconfiguration for SBC
   1.620 +			if ((codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCCodeSBC))
   1.621 +				{
   1.622 +				TSBCCodecCapabilities* sbcCodecCapabilities = static_cast<TSBCCodecCapabilities*>(codecCaps);
   1.623 +				TSBCSamplingFrequencyBitmask samplingFreqBitMask = sbcCodecCapabilities->SamplingFrequencies();
   1.624 +				
   1.625 +				//if the headset has already been configured then we don't allow a change 
   1.626 +				//of sampling frequency.  This is because once the DevSound has been configured
   1.627 +				//with a sampling frequency after the DevSound is initialized and hence
   1.628 +				//the a2dpheadsetif is initialized, it is no longer possible to change the sample frequency
   1.629 +				TBool headsetAlreadyConfigured(EFalse);
   1.630 +				if ((iCurrentState.State() == TGAVDPState::EGAVDPOpen) ||
   1.631 +				(iCurrentState.State() == TGAVDPState::EGAVDPSuspended))
   1.632 +					{
   1.633 +					headsetAlreadyConfigured = ETrue;
   1.634 +					}
   1.635 +				//only one bit of the sampling frequency mask should be set
   1.636 +				//note we're using switch statements rather than if then else
   1.637 +				//it makes it easier to pick up the case where we have an invalid
   1.638 +				//value or more than one value has been set in the bit mask
   1.639 +				switch (samplingFreqBitMask)
   1.640 +					{
   1.641 +					case E16kHz:
   1.642 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 16000))
   1.643 +							{
   1.644 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   1.645 +							}
   1.646 +						break;
   1.647 +					case E32kHz:
   1.648 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 32000))
   1.649 +							{
   1.650 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   1.651 +							}
   1.652 +						break;
   1.653 +					case E44100Hz:
   1.654 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 44100))
   1.655 +							{
   1.656 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   1.657 +							}
   1.658 +						break;
   1.659 +					case E48kHz:
   1.660 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 48000))
   1.661 +							{
   1.662 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
   1.663 +							}
   1.664 +						break;
   1.665 +					default:
   1.666 +						err = ConvertToSymbianError::A2dpError(EA2dpInvalidSamplingFrequency);
   1.667 +						break;
   1.668 +					}
   1.669 +				TSBCChannelModeBitmask channelModeBitMask =  sbcCodecCapabilities->ChannelModes();
   1.670 +				
   1.671 +				//if the headset has already been configured then we don't allow a change 
   1.672 +				//of channels.  This is because once the DevSound has been configured
   1.673 +				//with a sampling frequency after the DevSound is initialized and hence
   1.674 +				//the a2dpheadsetif is initialized, it is no longer possible to change the number of channels
   1.675 +				switch (channelModeBitMask)
   1.676 +					{
   1.677 +					case EMono:
   1.678 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFMono))
   1.679 +							{
   1.680 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   1.681 +							}
   1.682 +						break;
   1.683 +					case EDualChannel: //we don't support dual channel
   1.684 +						err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   1.685 +						break;
   1.686 +					case EStereo:
   1.687 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo))
   1.688 +							{
   1.689 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   1.690 +							}
   1.691 +						break;
   1.692 +					case EJointStereo:
   1.693 +						if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo))
   1.694 +							{
   1.695 +							err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
   1.696 +							}
   1.697 +						break;
   1.698 +					default:
   1.699 +						err = ConvertToSymbianError::A2dpError(EA2dpInvalidChannelMode);
   1.700 +						break;
   1.701 +					}
   1.702 +					
   1.703 +				TSBCBlockLengthBitmask blockLengthBitMask = sbcCodecCapabilities->BlockLengths();
   1.704 +				
   1.705 +				switch (blockLengthBitMask)
   1.706 +					{
   1.707 +					case EBlockLenFour:
   1.708 +						break;
   1.709 +					case EBlockLenEight:
   1.710 +						break;
   1.711 +					case EBlockLenTwelve:
   1.712 +						break;
   1.713 +					case EBlockLenSixteen:
   1.714 +						break;
   1.715 +					default:
   1.716 +						err = ConvertToSymbianError::A2dpError(EA2dpInvalidBlockLength);
   1.717 +						break;
   1.718 +					}
   1.719 +					
   1.720 +				TSBCSubbandsBitmask subbandsBitMask = sbcCodecCapabilities->Subbands();
   1.721 +				
   1.722 +				TUint subbands = 0;
   1.723 +				switch (subbandsBitMask) 
   1.724 +					{
   1.725 +					case EFourSubbands:
   1.726 +						subbands = 4;
   1.727 +						break;
   1.728 +					case EEightSubbands:
   1.729 +						subbands = 8;
   1.730 +						break;
   1.731 +					default:
   1.732 +						err = ConvertToSymbianError::A2dpError(EA2dpInvalidSubbands);
   1.733 +						break;
   1.734 +					}
   1.735 +					
   1.736 +				TSBCAllocationMethodBitmask allocationMethodBitMask = sbcCodecCapabilities->AllocationMethods();
   1.737 +				
   1.738 +				switch (allocationMethodBitMask)
   1.739 +					{
   1.740 +					case ELoudness:
   1.741 +						break;
   1.742 +					case ESNR:
   1.743 +						break;
   1.744 +					default:
   1.745 +						err = ConvertToSymbianError::A2dpError(EA2dpInvalidAllocationMethod);
   1.746 +						break;
   1.747 +					}
   1.748 +					
   1.749 +				TInt bitPoolValue = sbcCodecCapabilities->MinBitpoolValue();
   1.750 +				
   1.751 +				if (bitPoolValue < KMinBitPoolValue)
   1.752 +					{
   1.753 +					err = ConvertToSymbianError::A2dpError(EA2dpInvalidMinimumBitPoolValue);
   1.754 +					}
   1.755 +					
   1.756 +				bitPoolValue = sbcCodecCapabilities->MaxBitpoolValue();
   1.757 +				
   1.758 +				//The bitpool value must be in the range of 2-250 and must not exceed
   1.759 +				// 16*numberOfSubbands*channels
   1.760 +				if ((bitPoolValue > KMaxBitPoolValue)||(bitPoolValue > (16*subbands*iA2dpCodecSettings.Channels())))
   1.761 +					{		
   1.762 +					err = ConvertToSymbianError::A2dpError(EA2dpInvalidMaximumBitPoolValue);
   1.763 +					}
   1.764 +				if (!err)
   1.765 +					{//note ownership of codecCaps is transferred
   1.766 +					iConfigurationByRemoteHeadsetState.SetCodecConfigRequestedByRemoteHeadset(codecCaps);
   1.767 +					}
   1.768 +				}//if (codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCodeSBC))
   1.769 +			else
   1.770 +				{//only support SBC for now
   1.771 +				err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec);
   1.772 +				}
   1.773 +			}
   1.774 +			break; //case EServiceCategoryMediaCodec:
   1.775 +		default: //	switch(aCapability->Category())
   1.776 +			err = KErrNotSupported;
   1.777 +			break;
   1.778 +		}
   1.779 +	
   1.780 +	if (err)
   1.781 +		{
   1.782 +		iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed;
   1.783 +		if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle))
   1.784 +			{//we only abort if the remote headset has not been configured
   1.785 +			//need to abort using SEID of remote headset - this resets config at remote headset
   1.786 +			Cancel(); //probably not necessary - but just in case
   1.787 +			iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset());
   1.788 +			}
   1.789 +		//else
   1.790 +		//config is a reconfig in suspend streams 
   1.791 +		//wait on a Start_Indication if the headset is ok with the existing config
   1.792 +		//or an Abort_Indication if the headset is not
   1.793 +		}
   1.794 +	
   1.795 +	return err;
   1.796 +	}
   1.797 +
   1.798 +
   1.799 +/*
   1.800 +MGavdpUser callback to indicate to the SymbianOS device that all the GAVDP_ConfigurationIndications
   1.801 +have been sent.
   1.802 +This callback should only occur if there have been no errored GAVDP_ConfigurationIndications
   1.803 +
   1.804 +@see MGavdpUser
   1.805 +*/
   1.806 +TInt CGAVDPStateMachine::GAVDP_ConfigurationEndIndication()
   1.807 +	{	
   1.808 +	//the underlying GAVDP/AVDTP code should ensure that this 
   1.809 +	//callback from GAVDP never occurs once the headset has been configured
   1.810 +	__ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
   1.811 +	__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   1.812 +	
   1.813 +	TInt err = KErrNone;
   1.814 +	
   1.815 +	TAvdtpMediaCodecCapabilities* configRequestedByRemoteHeadset = iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset();
   1.816 +	if (configRequestedByRemoteHeadset)
   1.817 +		{
   1.818 +		__ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset().IsValid(), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   1.819 +		
   1.820 +		//the headset settings have been accepted so use the headset settings
   1.821 +		//the only usable SEP shall be the once specified by the headset
   1.822 +		//for now this will always be SBC
   1.823 +		TUsableSEP SEP;
   1.824 +		SEP.iSEID = iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset();
   1.825 +		TFourCC dataTypeSupport;
   1.826 +		switch (configRequestedByRemoteHeadset->MediaCodecType())
   1.827 +			{
   1.828 +			case EAudioCodecSBC:
   1.829 +				dataTypeSupport.Set(KMMFFourCCCodeSBC);
   1.830 +				break;
   1.831 +			case EAudioCodecMPEG12Audio:
   1.832 +				dataTypeSupport.Set(KMMFFourCCCodeMP3);
   1.833 +				break;
   1.834 +			case EAudioCodecMPEG24AAC:
   1.835 +				dataTypeSupport.Set(KMMFFourCCCodeAAC);
   1.836 +				break;
   1.837 +			case EAudioCodecATRAC:
   1.838 +				dataTypeSupport.Set(KMMFFourCCCodeATRAC3);
   1.839 +				break;
   1.840 +			default://should never get here
   1.841 +				Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState);
   1.842 +				break;
   1.843 +			}
   1.844 +		SEP.iDataType.Set(dataTypeSupport);
   1.845 +		iUsableSEPs.Reset();
   1.846 +		err = iUsableSEPs.Append(SEP);
   1.847 +		
   1.848 +		//the only service capabilities are codec caps provided by the headset and transport
   1.849 +		if (!(iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*configRequestedByRemoteHeadset)))
   1.850 +			{
   1.851 +			err = KErrNoMemory;
   1.852 +			}
   1.853 +		if (!err)
   1.854 +			{
   1.855 +			iSEPCapabilities.ResetAndDestroy();
   1.856 +			err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.TransportCapsRequestedByRemoteHeadset());
   1.857 +			if (!err)
   1.858 +				{
   1.859 +				err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset());
   1.860 +				}
   1.861 +			}	
   1.862 +		}//	if (codecCaps)
   1.863 +
   1.864 +	if (!err)
   1.865 +		{
   1.866 +		if ((iStateChangeInProgress) && (iInitialState.State() == TGAVDPState::EGAVDPIdle))
   1.867 +			{//the headset configured us during an a2dpheadsetif Initialize()
   1.868 +			//we're now configured so now wait for GAVDP_Bearer ready
   1.869 +			iCurrentState == TGAVDPState::EConfigured;
   1.870 +			}
   1.871 +		else if (iCurrentState == TGAVDPState::EGAVDPSuspended)
   1.872 +			{
   1.873 +			//we have reconfigured so the SBC codec needs reconfiguring
   1.874 +			err = iGAVDPStateChangeObserver.GAVDPStateMachineReconfigureByRemoteHeadset();
   1.875 +			}
   1.876 +		}
   1.877 +	if (err)
   1.878 +		{
   1.879 +		if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle))
   1.880 +			{//we only abort if the remote headset has not been configured
   1.881 +			//need to abort using SEID of remote headset - this resets config at remote headset
   1.882 +			Cancel(); //probably not necessary - but just in case
   1.883 +			iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset());
   1.884 +			}
   1.885 +		}
   1.886 +		//else
   1.887 +		//config is a reconfig in suspend streams 
   1.888 +		//wait on a Start_Indication if the headset is ok with the existing config
   1.889 +		//or an Abort_Indication if the headset is not
   1.890 +	iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationEnd;
   1.891 +	return err;
   1.892 +	}
   1.893 +
   1.894 +
   1.895 +/**
   1.896 +MGavdpUser callback to indicate to the SymbianOS device that it has started streaming
   1.897 +There are two circumstances we can get a start indication
   1.898 +1) The headset can request to start the streams itself once we are in the open state
   1.899 +2) The headset can request a restart after suspending the streams eg to perform a reconfiguration
   1.900 +
   1.901 +@see MGavdpUser
   1.902 +*/
   1.903 +TInt CGAVDPStateMachine::GAVDP_StartIndication(TSEID aSEID)
   1.904 +	{
   1.905 +	__ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPOpen) ||
   1.906 +	(iCurrentState.State() == TGAVDPState::EGAVDPSuspended), Panic(EGavdpStateMachineUnexpectedCallback));
   1.907 +	__ASSERT_DEBUG((iConfigurationByRemoteHeadsetState.State() != TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart),Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   1.908 +	//first check the callback is for the symbian device SEP we are using to 
   1.909 +	//send data to the a2dp headset - incase the Symbian device has more than one SEP
   1.910 +	if (aSEID == iSymbianDeviceSEID)
   1.911 +		{
   1.912 +		if (iCurrentState.State() ==  TGAVDPState::EGAVDPOpen)
   1.913 +			{
   1.914 +			if (iStateChangeInProgress)
   1.915 +				{
   1.916 +				if (iTargetState.State() == TGAVDPState::EGAVDPStreaming)
   1.917 +					{
   1.918 +					//a EGAVDPOpen->Streaming transistion
   1.919 +					//which has been completed for us by the headset
   1.920 +					Cancel();
   1.921 +					iGavdp.Cancel();
   1.922 +					iCurrentState = TGAVDPState::EGAVDPStreaming;
   1.923 +					StateChangeComplete();
   1.924 +					}
   1.925 +				//else only other state change would be open->idle
   1.926 +				//this is unlikely/impossible if we get a GAVDP_StartIndication
   1.927 +				//do nothing
   1.928 +				}
   1.929 +			else
   1.930 +				{
   1.931 +				//note if no state change is in progress then the headset itself
   1.932 +				//has put itself in the streaming state 
   1.933 +				//normally we put the headset in the streaming state
   1.934 +				//when we call OpenDevice() on the a2dpaudioif
   1.935 +				//but if the headset does this then it is no longer possible
   1.936 +				//for the client to change the audio settings 
   1.937 +				iCurrentState = TGAVDPState::EGAVDPStreaming;
   1.938 +				}
   1.939 +			}//(iCurrentState.State() ==  TGAVDPState::EGAVDPOpen)
   1.940 +		else if (iCurrentState.State() ==  TGAVDPState::EGAVDPSuspended)
   1.941 +			{//most probably restarting after a reconfigure
   1.942 +			iCurrentState = TGAVDPState::EGAVDPStreaming;
   1.943 +			iGAVDPStateChangeObserver.GAVDPStateMachineStreamResumedByRemoteHeadset();
   1.944 +			}
   1.945 +		}//if (aSEID == iSymbianDeviceSEID)
   1.946 +	return KErrNone;	
   1.947 +	}
   1.948 +	
   1.949 +	
   1.950 +/**
   1.951 +MGavdpUser callback to indicate to the SymbianOS device that the request to abort the headset
   1.952 +which means it is not configured has completed
   1.953 +Can request an abort stream if headset configuration fails
   1.954 +
   1.955 +@see MGavdpUser
   1.956 +*/
   1.957 +void CGAVDPStateMachine::GAVDP_AbortStreamConfirm()
   1.958 +	{
   1.959 +	//if abort stream was caused by aborting the headset in response
   1.960 +	//to a headset configuration in GAVDP_ConfigurationIndication
   1.961 +	//then restart state machine from EConnectedToGavdp
   1.962 +	if (iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed)
   1.963 +		{//then the abort was caused an aborted configuration from the headset
   1.964 +		__ASSERT_DEBUG((iCurrentState.State() < TGAVDPState::EConfigured), Panic(EGavdpStateMachineUnexpectedCallback));
   1.965 +		
   1.966 +		//since we only aborted if the headset was not yet configured
   1.967 +		//there must be a state change in progress and since we cancelled
   1.968 +		//the GAVDPStateMachine should not be active
   1.969 +		__ASSERT_DEBUG((iStateChangeInProgress) && (!IsActive()), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
   1.970 +		
   1.971 +		iConfigurationByRemoteHeadsetState.Reset();	
   1.972 +		//just to make extra sure we'll rediscover the SEPs
   1.973 +		iPotentialSEPs.Reset();
   1.974 +		iUsableSEPs.Reset();
   1.975 +		iSEPCapabilities.ResetAndDestroy();
   1.976 +		iCurrentState = TGAVDPState::EConnectedToGavdp;
   1.977 +		iNextState = TGAVDPState::EConnectedToGavdp;
   1.978 +		iConfigurationByRemoteHeadsetState.Reset();
   1.979 +		iA2dpCodecSettings.Reset();
   1.980 +		iHeadsetSEID.Reset();
   1.981 +		iBearerSocket.Close();
   1.982 +		iLocalSEPConfigured = EFalse;
   1.983 +		iChangeOfSelectedHeadsetSEP = EFalse;
   1.984 +		iSignallingTransactionTimeout->Cancel();	
   1.985 +		NextState();
   1.986 +		}
   1.987 +	iConfigurationByRemoteHeadsetState.Reset();	
   1.988 +	}
   1.989 +
   1.990 +
   1.991 +/**
   1.992 +MGavdpUser callback to indicate to the SymbianOS device that the headset has aborted
   1.993 +ie it can no longer be regarded as configured
   1.994 +This makes a GAVDPStateMachineEvent MGAVDPStateChangeObserver callback on the CA2dpBTHeadsetAudioInterface
   1.995 +(which inturn will cause a Reset on the GAVDP state machine)
   1.996 +
   1.997 +@see MGavdpUser
   1.998 +*/	
   1.999 +void CGAVDPStateMachine::GAVDP_AbortIndication(TSEID aSEID)
  1.1000 +	{
  1.1001 +	//first check the callback is for the symbian device SEP we are using to 
  1.1002 +	//send data to the a2dp headset - incase the Symbian device has more than one SEP
  1.1003 +	if (aSEID == iSymbianDeviceSEID)
  1.1004 +		{
  1.1005 +		if (iStateChangeInProgress)
  1.1006 +			{
  1.1007 +			CancelChangeState(KErrAbort);		
  1.1008 +			}
  1.1009 +		else 
  1.1010 +			{
  1.1011 +			iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrAbort);
  1.1012 +			}
  1.1013 +		}
  1.1014 +	//else not much we can do it aSEID isn't the Symbian device ID
  1.1015 +	iConfigurationByRemoteHeadsetState.Reset();
  1.1016 +	}
  1.1017 +
  1.1018 +
  1.1019 +/**
  1.1020 +Internal function to initiate the discovery of the headset SEPs
  1.1021 +Note that the SEP discovery does not have a built in timeout
  1.1022 +so the GAVDP_SEPDiscovered callback must occur withing the GAVDP callback timeout 30s
  1.1023 +or the state change will be cancelled with KErrTimedOut
  1.1024 +*/
  1.1025 +void CGAVDPStateMachine::DiscoverRemoteSEPs()
  1.1026 +	{
  1.1027 +	iPotentialSEPs.Reset();
  1.1028 +	iGavdp.DiscoverRemoteSEPs();
  1.1029 +	iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout));
  1.1030 +	}
  1.1031 +
  1.1032 +
  1.1033 +/**
  1.1034 +MGavdpUser callback in response to DiscoverRemoteSEPs
  1.1035 +
  1.1036 +@see MGavdpUser
  1.1037 +*/	
  1.1038 +void CGAVDPStateMachine::GAVDP_SEPDiscovered(const TAvdtpSEPInfo& aSEP)
  1.1039 +	{
  1.1040 +	//check whether the SEP is suitable for connection
  1.1041 +	if ((!aSEP.InUse()) && (aSEP.MediaType() == EAvdtpMediaTypeAudio) && (aSEP.IsSink()))
  1.1042 +		{//the SEP is a potentialy suitable for connection
  1.1043 +		//so add to list of potential SEPs
  1.1044 +		TInt err = iPotentialSEPs.Append(aSEP.SEID());
  1.1045 +		if (err)
  1.1046 +			{
  1.1047 +			CancelChangeState(err);
  1.1048 +			}
  1.1049 +		}
  1.1050 +	//else SEP is not suitable so ignore it
  1.1051 +	}
  1.1052 +
  1.1053 +
  1.1054 +/**
  1.1055 +MGavdpUser callback
  1.1056 +
  1.1057 +@see MGavdpUser
  1.1058 +*/	
  1.1059 +void CGAVDPStateMachine::GAVDP_SEPDiscoveryComplete()
  1.1060 +	{
  1.1061 +	iSignallingTransactionTimeout->Cancel();
  1.1062 +	if (iPotentialSEPs.Count())
  1.1063 +		{//we have at least one potential SEP
  1.1064 +		StateChangeComplete();
  1.1065 +		}
  1.1066 +	else
  1.1067 +		{//no potential SEPs were found so cannot proceed any further
  1.1068 +		CancelChangeState(KErrCouldNotConnect);
  1.1069 +		}
  1.1070 +	}
  1.1071 +
  1.1072 +
  1.1073 +/**
  1.1074 +Internal function to get the capability of an individual SEP
  1.1075 +*/
  1.1076 +void CGAVDPStateMachine::GetRemoteSEPCapability()
  1.1077 +	{
  1.1078 +	TAvdtpServiceCategories serviceCategories;
  1.1079 +	serviceCategories.SetCapability(EServiceCategoryMediaTransport);
  1.1080 +	serviceCategories.SetCapability(EServiceCategoryMediaCodec);
  1.1081 +	TSEID SEPtoGetCapabilityOf = iPotentialSEPs[iSEPIterator];
  1.1082 +	iGavdp.GetRemoteSEPCapabilities(SEPtoGetCapabilityOf, serviceCategories);
  1.1083 +	iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout));
  1.1084 +	}
  1.1085 +
  1.1086 +
  1.1087 +/**
  1.1088 +Internal function to iterate through the list of potential SEPs and asking
  1.1089 +for the capabilites of each one.
  1.1090 +*/	
  1.1091 +void CGAVDPStateMachine::GetRemoteSEPCapabilities()
  1.1092 +	{
  1.1093 +	iSEPCapabilities.ResetAndDestroy(); //clear what's already there
  1.1094 +	iUsableSEPs.Reset();
  1.1095 +	iSEPIterator = 0;
  1.1096 +	iSEPCapabilityEntry = 0;
  1.1097 +	//go and get the capability of the first SEP in the list of potential SEPs
  1.1098 +	//the GAVDP_SEPCapabilityComplete() callback will cause the next potential
  1.1099 +	//SEP capability to be obtained.
  1.1100 +	GetRemoteSEPCapability(); 
  1.1101 +	}
  1.1102 +
  1.1103 +
  1.1104 +/**
  1.1105 +MGavdpUser callback in response to GetRemoteSEPCapabilities
  1.1106 +
  1.1107 +@see MGavdpUser
  1.1108 +*/	
  1.1109 +void CGAVDPStateMachine::GAVDP_SEPCapability(TAvdtpServiceCapability* aCapability)
  1.1110 +	{
  1.1111 +	// we own cap, stash it in the iSEPCapabilities array for owning and later use
  1.1112 +	TInt err = iSEPCapabilities.Append(aCapability);
  1.1113 +	if (err)
  1.1114 +		{
  1.1115 +		CancelChangeState(err);
  1.1116 +		}
  1.1117 +	}
  1.1118 +
  1.1119 +
  1.1120 +/**
  1.1121 +MGavdpUser callback in response to GetRemoteSEPCapabilities when all the 
  1.1122 +GAVDP_SEPCapability callbacks have been made for an individual SEP
  1.1123 +
  1.1124 +The function iterates through the SEP capabilites looking for transport and media codec support
  1.1125 +and if so the SEP is added to the list of usableSEPs.
  1.1126 +
  1.1127 +@see MGavdpUser
  1.1128 +*/	
  1.1129 +void CGAVDPStateMachine::GAVDP_SEPCapabilityComplete()
  1.1130 +	{
  1.1131 +	TInt err = KErrNone;
  1.1132 +	iSignallingTransactionTimeout->Cancel();
  1.1133 +	//iterate through the capabilities
  1.1134 +	TAvdtpServiceCapability* avdtpServiceCapability;
  1.1135 +	TBool mediaTransport(EFalse);
  1.1136 +	TBool audioSupport(EFalse);
  1.1137 +	TFourCC dataTypeSupport; //note we are assuming here that each SEP only has one codec capability
  1.1138 +	TUint i = 0;
  1.1139 +	//iterate through the capabilities
  1.1140 +	//looking for media transport and codec support
  1.1141 +	for	(;iSEPCapabilityEntry < iSEPCapabilities.Count() ; iSEPCapabilityEntry++)
  1.1142 +		{
  1.1143 +		avdtpServiceCapability = iSEPCapabilities[iSEPCapabilityEntry];
  1.1144 +		switch (avdtpServiceCapability->Category())
  1.1145 +			{
  1.1146 +			case EServiceCategoryMediaTransport:
  1.1147 +				mediaTransport = ETrue;
  1.1148 +				break;
  1.1149 +			case EServiceCategoryMediaCodec:
  1.1150 +				{
  1.1151 +				TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(avdtpServiceCapability);
  1.1152 +				if (codecCaps->MediaType() == EAvdtpMediaTypeAudio)
  1.1153 +					{
  1.1154 +					audioSupport = ETrue;
  1.1155 +					}
  1.1156 +				switch (codecCaps->MediaCodecType())
  1.1157 +					{
  1.1158 +					case EAudioCodecSBC:
  1.1159 +						dataTypeSupport.Set(KMMFFourCCCodeSBC);
  1.1160 +						break;
  1.1161 +					case EAudioCodecMPEG12Audio:
  1.1162 +						dataTypeSupport.Set(KMMFFourCCCodeMP3);
  1.1163 +						break;
  1.1164 +					case EAudioCodecMPEG24AAC:
  1.1165 +						dataTypeSupport.Set(KMMFFourCCCodeAAC);
  1.1166 +						break;
  1.1167 +					case EAudioCodecATRAC:
  1.1168 +						dataTypeSupport.Set(KMMFFourCCCodeATRAC3);
  1.1169 +						break;
  1.1170 +					default:
  1.1171 +						//the datatype is an unsupported datatype
  1.1172 +						//so set to NULL to show we can't use it
  1.1173 +						dataTypeSupport.Set(KMMFFourCCCodeNULL);
  1.1174 +						break;
  1.1175 +					}
  1.1176 +				}
  1.1177 +			}//switch (avdtpServiceCapability->Category())
  1.1178 +		}//	for (TUint i=0; i++; i<iSEPCapabilities.Count())
  1.1179 +	//check if the capabilities indicate that the SEP is usable
  1.1180 +	//for audio transport
  1.1181 +	if ((mediaTransport) && (audioSupport) && 
  1.1182 +		(dataTypeSupport != KMMFFourCCCodeNULL))
  1.1183 +		{//then we can use this SEP to stream audio to the headset
  1.1184 +		// however we ie the Symbian device must
  1.1185 +		//also be able to support the data type
  1.1186 +		//before we can add it to the list of usable SEPs
  1.1187 +		TBool symbianDeviceSupportsDataType(EFalse);
  1.1188 +		for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
  1.1189 +			{
  1.1190 +			if (iSymbianDeviceSEPs[i].iDataType == dataTypeSupport) 
  1.1191 +				{
  1.1192 +				symbianDeviceSupportsDataType = ETrue;
  1.1193 +				break;
  1.1194 +				}
  1.1195 +			}
  1.1196 +		if (symbianDeviceSupportsDataType)
  1.1197 +			{
  1.1198 +			TUsableSEP usableSEP;
  1.1199 +			usableSEP.iSEID = iPotentialSEPs[iSEPIterator];
  1.1200 +			usableSEP.iDataType.Set(dataTypeSupport);
  1.1201 +			err = iUsableSEPs.Append(usableSEP);
  1.1202 +			if (err)
  1.1203 +				{
  1.1204 +				CancelChangeState(err);
  1.1205 +				}
  1.1206 +			}
  1.1207 +		}
  1.1208 +	if (!err)
  1.1209 +		{
  1.1210 +		//check if we have finished going through our list of potential SEPs
  1.1211 +		//that we need to find the capabilities of
  1.1212 +		iSEPIterator++;
  1.1213 +		if (iSEPIterator >= iPotentialSEPs.Count())
  1.1214 +			{//then we have finished getting all the capabilities
  1.1215 +			//so lets choose a SEP by iterating through the
  1.1216 +			//usable SEPs and stopping at the first one that supports the
  1.1217 +			//required data type 
  1.1218 +			TUsableSEP SEP;
  1.1219 +			TBool SEPFound(EFalse);
  1.1220 +			for (i=0; i<iUsableSEPs.Count(); i++)
  1.1221 +				{
  1.1222 +				SEP = iUsableSEPs[i];
  1.1223 +				if (SEP.iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
  1.1224 +					{//one of the usable SEPs supports the requested data type
  1.1225 +					SEPFound = ETrue;
  1.1226 +					iHeadsetSEID = SEP.iSEID; //we'll use this SEID for now			
  1.1227 +					break;
  1.1228 +					}
  1.1229 +				}
  1.1230 +			iSEPIterator = 0;
  1.1231 +			iSEPCapabilityEntry = 0;
  1.1232 +			if (SEPFound)
  1.1233 +				{
  1.1234 +				//we've selected a SEP
  1.1235 +				StateChangeComplete(); //so move on to the next state
  1.1236 +				}
  1.1237 +			else
  1.1238 +				{
  1.1239 +				//then non  of the SEPs have SBC codec capabilites
  1.1240 +				//or no usable SEPs have been found or SEP may be in use
  1.1241 +				//since SBC support is mandatory we do not have a suitable SEP
  1.1242 +				CancelChangeState(KErrCouldNotConnect);
  1.1243 +				}
  1.1244 +			}//	if (iPotentialSEPs.Count() >= iSEPIterator)
  1.1245 +		else
  1.1246 +			{//get the capability of the next SEP
  1.1247 +			GetRemoteSEPCapability();
  1.1248 +			}
  1.1249 +		}
  1.1250 +	}
  1.1251 +
  1.1252 +
  1.1253 +/**
  1.1254 +Function used to return a TAvdtpMediaCodecCapabilities structure
  1.1255 +that can be used to configure the SEP at the remote end ie on the headset
  1.1256 +The capabilities are used to determine the configuration
  1.1257 +need to return by pointer rather than by ref as TAvdtpMediaCodecCapabilities is abstract 
  1.1258 +*/
  1.1259 +TAvdtpMediaCodecCapabilities* CGAVDPStateMachine::RemoteCodecConfiguration()
  1.1260 +	{
  1.1261 +	TAvdtpMediaCodecCapabilities* codecCaps = NULL;
  1.1262 +	TAvdtpMediaCodecCapabilities* codecConfiguration = NULL;
  1.1263 +	
  1.1264 +	//first get the capabilities of the codec
  1.1265 +	TInt error = CodecCaps(codecCaps);
  1.1266 +	if (!error)
  1.1267 +		{//and use the capabilities to get a valid remote codec configuration
  1.1268 +		codecConfiguration = iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*codecCaps);
  1.1269 +		}
  1.1270 +
  1.1271 +	return codecConfiguration;
  1.1272 +	}
  1.1273 +
  1.1274 +
  1.1275 +/**
  1.1276 +Internal function to configure the local SEP
  1.1277 +*/	
  1.1278 +TInt CGAVDPStateMachine::ConfigureLocalSEP()
  1.1279 +	{
  1.1280 +	TInt err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID);
  1.1281 +	if (err == KErrNotFound)
  1.1282 +		{
  1.1283 +		//could be a problem with the local SEP no longer being registered
  1.1284 +		//so register and try again
  1.1285 +		err = RegisterLocalSEP();
  1.1286 +		if (!err)
  1.1287 +			{
  1.1288 +			err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID);
  1.1289 +			}
  1.1290 +		}
  1.1291 +	if (!err)
  1.1292 +		{//configure local SEP - we only advertise one local SEP with SBC support
  1.1293 +		//in future when capability structures are defined for mp3,AAC,ATRAC3
  1.1294 +		//then these can also be advertised as local SEPs
  1.1295 +		TAvdtpMediaTransportCapabilities media;
  1.1296 +		err = iGavdp.AddSEPCapability(media);
  1.1297 +		
  1.1298 +		if (!err)
  1.1299 +			{
  1.1300 +			CA2dpLocalCodecCapabilities* localCodecCapabilities = NULL;
  1.1301 +			TRAP(err, localCodecCapabilities = CA2dpLocalCodecCapabilities::NewL())
  1.1302 +			if (!err)
  1.1303 +				{
  1.1304 +				TAvdtpMediaCodecCapabilities* localSEPCapability = localCodecCapabilities->LocalCodecCapabilities(iA2dpCodecSettings.HeadsetCodecDataType());
  1.1305 +				if (localSEPCapability)
  1.1306 +					{
  1.1307 +					err = iGavdp.AddSEPCapability(*localSEPCapability);
  1.1308 +					}
  1.1309 +				else
  1.1310 +					{
  1.1311 +					err = KErrNoMemory;
  1.1312 +					}
  1.1313 +				delete localCodecCapabilities;
  1.1314 +				localCodecCapabilities = NULL;
  1.1315 +				}
  1.1316 +			}	
  1.1317 +		}
  1.1318 +	return err;
  1.1319 +	}
  1.1320 +
  1.1321 +
  1.1322 +/**
  1.1323 +Internal function to configure the remote SEP ie the headset
  1.1324 +
  1.1325 +If the SEP has never been configured before then the transport caps are added
  1.1326 +If we are doing a reconfigure of the remote SEP then just the codec caps are added
  1.1327 +*/
  1.1328 +TInt CGAVDPStateMachine::ConfigureRemoteSEP()
  1.1329 +	{
  1.1330 +	TInt err = iGavdp.BeginConfiguringRemoteSEP(iHeadsetSEID, iSymbianDeviceSEID);
  1.1331 +	if (!err)
  1.1332 +		{
  1.1333 +		if ((iInitialState.State() < TGAVDPState::EConfigured)||(iChangeOfSelectedHeadsetSEP))
  1.1334 +			{//then this SEP has never been configured before
  1.1335 +			//in which case we need to configure it with transport capabilities
  1.1336 +			//note that if the SEP has been configured before ie the above condition
  1.1337 +			//is false then we are performing a reconfiguration and are not allowed
  1.1338 +			//to reconfigure the media transport capabilities
  1.1339 +			TAvdtpMediaTransportCapabilities avdtpMediaTransportCapabilities;
  1.1340 +			err = iGavdp.AddSEPCapability(avdtpMediaTransportCapabilities);
  1.1341 +			iChangeOfSelectedHeadsetSEP = EFalse;//reset
  1.1342 +			}
  1.1343 +		if (!err)
  1.1344 +			{
  1.1345 +			TAvdtpMediaCodecCapabilities* codecConfiguration = RemoteCodecConfiguration();
  1.1346 +			//note we are setting a configuration here not a capability
  1.1347 +			if (codecConfiguration)
  1.1348 +				{
  1.1349 +				err = iGavdp.AddSEPCapability(*codecConfiguration);
  1.1350 +				}
  1.1351 +			else
  1.1352 +				{//we were not able to get a valid configuration
  1.1353 +				//so abort configuration
  1.1354 +				err = KErrAbort;
  1.1355 +				}
  1.1356 +			}//	if (!err)
  1.1357 +		}
  1.1358 +	return err;
  1.1359 +	}
  1.1360 +
  1.1361 +
  1.1362 +/**
  1.1363 +Internal function to initiate SEP configuration of both the local and remote SEPs
  1.1364 +*/			
  1.1365 +void CGAVDPStateMachine::ConfigureSEP()
  1.1366 +	{
  1.1367 +	if (iHeadsetSEID.IsValid())
  1.1368 +		{
  1.1369 +		TInt err;
  1.1370 +		if (!iLocalSEPConfigured)
  1.1371 +			{//the local SEP must be configured first before configuring the remote SEP
  1.1372 +			err = ConfigureLocalSEP();	
  1.1373 +			}
  1.1374 +		else
  1.1375 +			{//local SEP is already configured so configure remote SEP
  1.1376 +			err = ConfigureRemoteSEP();
  1.1377 +			}
  1.1378 +		if (err)
  1.1379 +			{
  1.1380 +			CancelChangeState(err);
  1.1381 +			}
  1.1382 +		else
  1.1383 +			{
  1.1384 +			iGavdp.CommitSEPConfiguration();
  1.1385 +			}
  1.1386 +		}
  1.1387 +	else
  1.1388 +		{//we've requested to configure a SEP before we have
  1.1389 +		//a valid SEP to configure
  1.1390 +		CancelChangeState(KErrNotReady);
  1.1391 +		}
  1.1392 +	}
  1.1393 +	
  1.1394 +
  1.1395 +/**
  1.1396 +MGavdpUser callback to confirm that the SEP configuration has been acepted
  1.1397 +This callback should occur for both the local SEP and the remote SEP 
  1.1398 +*/
  1.1399 +void CGAVDPStateMachine::GAVDP_ConfigurationConfirm()
  1.1400 +	{
  1.1401 +	TInt err = KErrNone;
  1.1402 +	if (!iLocalSEPConfigured)
  1.1403 +		{//the local SEP is configured first so this call back must be from
  1.1404 +		 //a local SEP configuration
  1.1405 +		iLocalSEPConfigured = ETrue;
  1.1406 +		//now configure the remote SEP
  1.1407 +		err = ConfigureRemoteSEP();
  1.1408 +		if (!err)
  1.1409 +			{
  1.1410 +			iGavdp.CommitSEPConfiguration();
  1.1411 +			}
  1.1412 +		else
  1.1413 +			{
  1.1414 +			CancelChangeState(err);
  1.1415 +			}
  1.1416 +		}
  1.1417 +	else
  1.1418 +		{
  1.1419 +		//local and remote SEPs now configured
  1.1420 +		TInt err = iGavdp.Listen();	
  1.1421 +		//note that if there is an error above
  1.1422 +		// there is not much we can do so ignore it
  1.1423 +		StateChangeComplete();
  1.1424 +		}
  1.1425 +	}
  1.1426 +	
  1.1427 +
  1.1428 +/**
  1.1429 +Internal function to request a bearer RSocket in order to stream audio to the headset
  1.1430 +*/
  1.1431 +void CGAVDPStateMachine::CreateBearerSocket()
  1.1432 +	{
  1.1433 +	//then we need to request for one from the remote SEP
  1.1434 +	//this reference code does not support reporting and recovery channels
  1.1435 +
  1.1436 +	if (!iBearerSocket.SubSessionHandle())
  1.1437 +		{//we don't already have a bearer socket, create one - note no reporting and recovery implementation
  1.1438 +		TInt err = iGavdp.CreateBearerSockets(iHeadsetSEID, EFalse, EFalse);
  1.1439 +		if (err)
  1.1440 +			{
  1.1441 +			CancelChangeState(err);
  1.1442 +			}
  1.1443 +		}
  1.1444 +	else
  1.1445 +		{
  1.1446 +		//we already have a bearer socket so no need to create a new one
  1.1447 +		//just complete the state change
  1.1448 +		StateChangeComplete();
  1.1449 +		}
  1.1450 +	}
  1.1451 +	
  1.1452 +
  1.1453 +/**
  1.1454 +MGavdpUser callback to supply the RSocket used to stream audio to the headset
  1.1455 +
  1.1456 +This callback can occur either via a direct request from the headset or in response
  1.1457 +to a CreateBearerSocket
  1.1458 +
  1.1459 +@see MGavdpUser
  1.1460 +*/
  1.1461 +void CGAVDPStateMachine::GAVDP_BearerReady(RSocket aSocket, const TAvdtpSockAddr& /*aAddress*/)
  1.1462 +	{
  1.1463 +	//This call back can occur without a prior call to CreateBearerSocket
  1.1464 +	iBearerSocket = aSocket;
  1.1465 +	if ((iCurrentState == TGAVDPState::EConfigured)&&(iStateChangeInProgress))
  1.1466 +		{//we've completed the state	
  1.1467 +		StateChangeComplete();
  1.1468 +		}
  1.1469 +	// else this came from the headset without a call to RGavdp::CreateBearerSockets
  1.1470 +	}
  1.1471 +
  1.1472 +
  1.1473 +/**
  1.1474 +Function to return an array of usable SEPs on the headset.
  1.1475 +By 'usable' we mean the SEP supports audio, has media transport caps, is not in use,
  1.1476 +has a supported audio codec and the audio codec is supported by the symbianOS device
  1.1477 +@return array of usable SEPs
  1.1478 +*/	
  1.1479 +RArray<TUsableSEP>& CGAVDPStateMachine::UsableSEPs() const
  1.1480 +	{
  1.1481 +	return const_cast<RArray<TUsableSEP>&>(iUsableSEPs);
  1.1482 +	}
  1.1483 +
  1.1484 +
  1.1485 +/**
  1.1486 +Function to return the bearer socket used to stream audio to the headset
  1.1487 +@return socket
  1.1488 +*/	
  1.1489 +RSocket& CGAVDPStateMachine::BearerSocket() const
  1.1490 +	{
  1.1491 +	return const_cast<RSocket&>(iBearerSocket);
  1.1492 +	}
  1.1493 +
  1.1494 +
  1.1495 +/**
  1.1496 +Function to return the headset BT address
  1.1497 +@return headset BT address
  1.1498 +*/	
  1.1499 +TBTDevAddr& CGAVDPStateMachine::BTAddress() const
  1.1500 +	{
  1.1501 +	return const_cast<TBTDevAddr&>(iBTDevAddr);
  1.1502 +	}
  1.1503 +
  1.1504 +
  1.1505 +/** 
  1.1506 +Function to return the SEPCapability for the codec settings
  1.1507 +used by CA2dpBTHeadsetAudioInterface to determine the audio settings
  1.1508 +ie sample rate / stereo support.
  1.1509 +aCodecCaps is set with the TAvdtpMediaCodecCapabilities of the codec in use
  1.1510 +if no codec has been specified via the Reconfigure()	function then
  1.1511 +the codec defaults to SBC
  1.1512 +returns KErrNotReady if no SEP capablities have been obtained from the SEP
  1.1513 +return KErrNotSupported if the codec type is not known
  1.1514 +aCodecCaps Note that ownership is not transferred to the calling class.
  1.1515 +
  1.1516 +@param aCodecCaps  The pointer points to a codec capabilities structure
  1.1517 +
  1.1518 +@return SymbianOS error code
  1.1519 +*/
  1.1520 +TInt CGAVDPStateMachine::CodecCaps(TAvdtpMediaCodecCapabilities*& aCodecCaps) const
  1.1521 +	{
  1.1522 +	TInt err = KErrNotReady;
  1.1523 +	TAvdtpServiceCapability* avdtpServiceCapability;
  1.1524 +	TFourCC dataType;
  1.1525 +	for (TUint i=0;  i<iSEPCapabilities.Count(); i++)
  1.1526 +		{
  1.1527 +		avdtpServiceCapability = iSEPCapabilities[i];
  1.1528 +		if (avdtpServiceCapability->Category() == EServiceCategoryMediaCodec)
  1.1529 +			{
  1.1530 +			TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(avdtpServiceCapability);
  1.1531 +			switch (codecCaps->MediaCodecType())
  1.1532 +				{
  1.1533 +				case EAudioCodecSBC:
  1.1534 +					dataType.Set(KMMFFourCCCodeSBC);
  1.1535 +					break;
  1.1536 +				case EAudioCodecMPEG12Audio:
  1.1537 +					dataType.Set(KMMFFourCCCodeMP3);
  1.1538 +					break;
  1.1539 +				case EAudioCodecMPEG24AAC:
  1.1540 +					dataType.Set(KMMFFourCCCodeAAC);
  1.1541 +					break;
  1.1542 +				case EAudioCodecATRAC:
  1.1543 +					dataType.Set(KMMFFourCCCodeATRAC3);
  1.1544 +					break;
  1.1545 +				default:
  1.1546 +					err = KErrNotSupported;
  1.1547 +					break;
  1.1548 +				}
  1.1549 +			if (dataType == iA2dpCodecSettings.HeadsetCodecDataType())
  1.1550 +				{//then we have the capabilities for the selected datatype
  1.1551 +				aCodecCaps = codecCaps;
  1.1552 +				err = KErrNone;
  1.1553 +				break;
  1.1554 +				}	
  1.1555 +			}	
  1.1556 +		}	//for (TUint i=0;  i<iSEPCapabilities.Count(); i++)
  1.1557 +	return err;
  1.1558 +	}
  1.1559 +	
  1.1560 +
  1.1561 +/**
  1.1562 +MGavdpUser callback when headset releases stream
  1.1563 +
  1.1564 +@see MGavdpUser
  1.1565 +*/
  1.1566 +void CGAVDPStateMachine::GAVDP_ReleaseIndication(TSEID aSEID)
  1.1567 +	{
  1.1568 +	if (aSEID == iSymbianDeviceSEID)
  1.1569 +		{
  1.1570 +		if (iStateChangeInProgress)
  1.1571 +			{
  1.1572 +			CancelChangeState(KErrDisconnected);
  1.1573 +			}			
  1.1574 +		else
  1.1575 +			{
  1.1576 +			iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrDisconnected);
  1.1577 +			}
  1.1578 +		TInt err = iGavdp.Listen();//can't do much if this errors
  1.1579 +		}
  1.1580 +	}
  1.1581 +
  1.1582 +
  1.1583 +/**
  1.1584 +MGavdpUser error callback 
  1.1585 +
  1.1586 +@see MGavdpUser
  1.1587 +*/
  1.1588 +void CGAVDPStateMachine::GAVDP_Error(TInt aError, const TDesC8& /*aErrorData*/)
  1.1589 +	{	
  1.1590 +	TInt error = ConvertToStandardSymbianOSError(aError);
  1.1591 +	if (iStateChangeInProgress)
  1.1592 +		{
  1.1593 +		CancelChangeState(error);
  1.1594 +		}
  1.1595 +	else
  1.1596 +		{
  1.1597 +		//error must have occured while no state change was in progress
  1.1598 +		//this could be due to a problem on the headset eg no longer in range
  1.1599 +		//Make callback on a2dpBTHeadsetIf so it can reset back to the idle state
  1.1600 +		iGAVDPStateChangeObserver.GAVDPStateMachineEvent(error);
  1.1601 +		}
  1.1602 +	//start listening for connect event from headset
  1.1603 +	TInt err = iGavdp.Listen();//can't do much if this errors	
  1.1604 +	}
  1.1605 +
  1.1606 +
  1.1607 +/**
  1.1608 +Internal function to put the headset in the streaming state
  1.1609 +*/	
  1.1610 +void CGAVDPStateMachine::StartStream()
  1.1611 +	{
  1.1612 +	//we're only going to start one transport stream
  1.1613 +	iGavdp.StartStream(iHeadsetSEID);
  1.1614 +	}
  1.1615 +
  1.1616 +
  1.1617 +/**
  1.1618 +MGavdpUser callback in response to StartStream
  1.1619 +
  1.1620 +@see MGavdpUser
  1.1621 +*/	
  1.1622 +void CGAVDPStateMachine::GAVDP_StartStreamsConfirm()
  1.1623 +	{
  1.1624 +	StateChangeComplete();
  1.1625 +	}
  1.1626 +
  1.1627 +
  1.1628 +/**
  1.1629 +Internal function to tell the headset we are suspending the stream
  1.1630 +*/	
  1.1631 +void CGAVDPStateMachine::SuspendStream()
  1.1632 +	{
  1.1633 +	//we're only going to suspend one transport stream
  1.1634 +	iGavdp.SuspendStream(iHeadsetSEID);
  1.1635 +	}
  1.1636 +
  1.1637 +
  1.1638 +/**
  1.1639 +MGavdpUser callback in response to SuspendStream
  1.1640 +
  1.1641 +@see MGavdpUser
  1.1642 +*/	
  1.1643 +void CGAVDPStateMachine::GAVDP_SuspendStreamsConfirm()
  1.1644 +	{
  1.1645 +	StateChangeComplete();
  1.1646 +	}
  1.1647 +
  1.1648 +	
  1.1649 +/**
  1.1650 +RunsL for GAVDP state machine
  1.1651 +*/
  1.1652 +void CGAVDPStateMachine::RunL()
  1.1653 +	{
  1.1654 +	if (iStateChangeInProgress)
  1.1655 +		{
  1.1656 +		switch (iCurrentState.State())
  1.1657 +			{
  1.1658 +			case TGAVDPState::EGAVDPIdle:
  1.1659 +				ConnectToGAVDP();
  1.1660 +				break;
  1.1661 +			case TGAVDPState::EConnectedToGavdp:
  1.1662 +				DiscoverRemoteSEPs();
  1.1663 +				break;
  1.1664 +			case TGAVDPState::ESEPsDiscovered:
  1.1665 +				GetRemoteSEPCapabilities();
  1.1666 +				break;
  1.1667 +			case TGAVDPState::ESEPSelected:
  1.1668 +				ConfigureSEP();
  1.1669 +				break;
  1.1670 +			case TGAVDPState::EConfigured:
  1.1671 +				CreateBearerSocket();
  1.1672 +				break;
  1.1673 +			case TGAVDPState::EGAVDPOpen:
  1.1674 +				StartStream();
  1.1675 +				break;
  1.1676 +			case TGAVDPState::EGAVDPStreaming:
  1.1677 +				SuspendStream();
  1.1678 +				break;
  1.1679 +			default:
  1.1680 +				Panic(EGavdpStateMachineBadState);
  1.1681 +				break;
  1.1682 +			}
  1.1683 +		}
  1.1684 +	else
  1.1685 +		{
  1.1686 +		//if RunL should get called when no state
  1.1687 +		//change is in progress eg during a reconfiguration
  1.1688 +		//then the current state should always be identical to the target state
  1.1689 +		__ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));
  1.1690 +		StateChangeComplete();
  1.1691 +		}
  1.1692 +	}
  1.1693 +
  1.1694 +
  1.1695 +/**
  1.1696 +Cancel
  1.1697 +*/
  1.1698 +void CGAVDPStateMachine::DoCancel()
  1.1699 +	{
  1.1700 +	TRequestStatus* stat = &iStatus;
  1.1701 +	User::RequestComplete(stat, KErrCancel);
  1.1702 +	}
  1.1703 +
  1.1704 +
  1.1705 +
  1.1706 +
  1.1707 +CGavdpTimeout* CGavdpTimeout::NewL(CGAVDPStateMachine& aGAVDPStateMachine)
  1.1708 +	{
  1.1709 +	CGavdpTimeout* self = new(ELeave)CGavdpTimeout();
  1.1710 +	CleanupStack::PushL(self);
  1.1711 +	self->ConstructL(aGAVDPStateMachine);
  1.1712 +	CleanupStack::Pop();	
  1.1713 +	return self;
  1.1714 +	}
  1.1715 +
  1.1716 +
  1.1717 +void CGavdpTimeout::ConstructL(CGAVDPStateMachine& aGAVDPStateMachine)
  1.1718 +	{
  1.1719 +	CTimer::ConstructL();
  1.1720 +	CActiveScheduler::Add(this);
  1.1721 +	iGAVDPStateMachine = &aGAVDPStateMachine;
  1.1722 +	}
  1.1723 +
  1.1724 +
  1.1725 +CGavdpTimeout::CGavdpTimeout() : CTimer(EPriorityLow)
  1.1726 +	{
  1.1727 +	}
  1.1728 +
  1.1729 +
  1.1730 +void CGavdpTimeout::StartTimer(TTimeIntervalMicroSeconds32 aTimeInterval)
  1.1731 +	{
  1.1732 +	Cancel(); //just in case
  1.1733 +	After(aTimeInterval);	
  1.1734 +	}
  1.1735 +
  1.1736 +
  1.1737 +void CGavdpTimeout::RunL()
  1.1738 +	{
  1.1739 +	//the GAVDP callback has timed out - check the GAVDP state machine
  1.1740 +	//is in the connected state to cover ourselves in the event of a race
  1.1741 +	//condition
  1.1742 +	if ((iGAVDPStateMachine->State() == TGAVDPState::EConnectedToGavdp)||
  1.1743 +	(iGAVDPStateMachine->State() == TGAVDPState::ESEPsDiscovered))
  1.1744 +		{
  1.1745 +		iGAVDPStateMachine->CancelChangeState(KErrTimedOut);
  1.1746 +		}
  1.1747 +	}
  1.1748 +	
  1.1749 +
  1.1750 +