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