os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/A2dpBTheadsetAudioIf.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <mmf/server/mmfcodec.h>
    17 #include "mmfSBCCodecImplementationUIDs.hrh"
    18 #include <mmffourcc.h>
    19 #include "A2dpCodecUtilities.h"
    20 #include "A2dpBTheadsetAudioIf.h"
    21 #include "MMFBtRoutingSoundDevice.h"	// for TRange
    22 
    23 /**
    24 Panics
    25 **/
    26 enum TA2dpBTHeadsetPanic
    27 	{
    28 	EA2dpBTHeadsetUnExpectedState,//0
    29 	EA2dpBTHeadsetNoRTPStreamer,//1
    30 	EA2dpBTHeadsetNoData,//2
    31 	EA2dpBTHeadsetUnexpectedDataType,//3
    32 	EA2dpBTHeadsetBTAddrNotSet, //4
    33 	EA2dpBTHeadsetNoCodec //5
    34 	};
    35 
    36 
    37 static void Panic(TA2dpBTHeadsetPanic aPanic)
    38 // Panic client
    39 	{
    40 	_LIT(KA2dpBTHeadsetPanicName, "A2DP BT If Panic");
    41 	User::Panic(KA2dpBTHeadsetPanicName, aPanic);
    42 	}
    43 
    44 
    45 CA2dpBTHeadsetAudioInterface::CA2dpBTHeadsetAudioInterface()
    46 	{
    47 	}
    48 
    49 void CA2dpBTHeadsetAudioInterface::ConstructL()
    50 	{
    51 	iA2dpCodecConfiguration = CA2dpAudioCodecConfiguration::NewL();
    52 	User::LeaveIfError(iSocketServer.Connect());
    53 	iGAVDPStateMachine = CGAVDPStateMachine::NewL(*this, *iA2dpCodecConfiguration, iSocketServer);	
    54 	}
    55 	
    56 /**
    57 Creates CA2dpBTHeadsetAudioInterface
    58 Note there should only ever be one CA2dpBTHeadsetAudioInterface*
    59 However this being a singleton is not enforced in this class however
    60 The client of this class ie the CA2dpBTHeadsetAudioServer should enforce this.
    61  
    62 @return CA2dpBTHeadsetAudioInterface*
    63 */	
    64 EXPORT_C CA2dpBTHeadsetAudioInterface* CA2dpBTHeadsetAudioInterface::NewL()
    65 	{
    66 	CA2dpBTHeadsetAudioInterface* self = new(ELeave) CA2dpBTHeadsetAudioInterface();
    67 	CleanupStack::PushL(self);
    68 	self->ConstructL();
    69 	CleanupStack::Pop(self);
    70 	return self;
    71 	}
    72 
    73 /**
    74 destructor
    75 */	
    76 EXPORT_C CA2dpBTHeadsetAudioInterface::~CA2dpBTHeadsetAudioInterface()
    77 	{
    78 	SetSniffMode(ETrue);
    79 	delete iGAVDPStateMachine;
    80 	delete iCodec;
    81 	delete iA2dpCodecConfiguration;
    82 	delete iRTPStreamer;
    83 	iSocketServer.Close();
    84 	}
    85 	
    86 
    87 /**
    88 Procedure to perform a GAVDP initialization sequence on an A2DP headset
    89 If the headset is already initialized then this procedure does not perform
    90 any further initialization.
    91 if link has gone down since a previous call to Initialize then
    92 calling this function will perform a full reinitialize.
    93 if link goes down during initialization will generate error
    94 The GAVDPStateChangeComplete callback is called when the headset device
    95 is in the open state.
    96 The headset is in the GAVDP_Open state on completion
    97 It is not possible to perform an Initialize if the headset is already in the
    98 streaming state or is already being initialized.
    99 
   100 @param aRemoteAddress Address of the bluetooth headset we are trying to initialize
   101 @param aStatus
   102 */	
   103 EXPORT_C void CA2dpBTHeadsetAudioInterface::Initialize(const TBTDevAddr& aRemoteAddress, TRequestStatus& aStatus)
   104 	{
   105 	__ASSERT_ALWAYS(((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)||
   106 					(iGAVDPStateMachine->State() == TGAVDPState::EGAVDPOpen)), Panic(EA2dpBTHeadsetUnExpectedState));
   107 	__ASSERT_ALWAYS(!iReconfiguring, Panic(EA2dpBTHeadsetUnExpectedState)); //can't initialize while we're reconfiguring
   108 	iInitializeRequestStatus = &aStatus;
   109 	*iInitializeRequestStatus = KRequestPending;
   110 	
   111 	//this will cause a full initialization if the address has changed
   112 	iGAVDPStateMachine->SetBTAddress(aRemoteAddress);
   113 	
   114 	TGAVDPState state(TGAVDPState::EGAVDPOpen);
   115 	TInt err = iGAVDPStateMachine->ChangeState(state);
   116 	if (err)
   117 		{
   118 		User::RequestComplete(iInitializeRequestStatus, err);
   119 		}	
   120 	}
   121 
   122 
   123 /**
   124 Procedure to cancel a GAVDP initialization sequence on an A2DP headset
   125 */		
   126 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelInitialize()
   127 	{
   128 	if (iInitializeRequestStatus)
   129 		{
   130 		if (*iInitializeRequestStatus == KRequestPending)//make sure there is a pending request to cancel
   131 			{
   132 			iGAVDPStateMachine->CancelChangeState();
   133 			}
   134 		}
   135 	}
   136 	
   137 
   138 /**
   139 Handles the state change GAVDPIdle->GAVDPOpen
   140 This state change usually occurs as a result to an Initialize call
   141 Can also occur due to an error condition resulting in a GAVDP state machine reset 
   142 */
   143 void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeIdleToOpen(TInt aError)
   144 	{
   145 	__ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPOpen||
   146 	iGAVDPStateMachine->State()==TGAVDPState::EGAVDPIdle),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
   147 	
   148 	if (!aError)
   149 		{
   150 		SetSniffMode(ETrue);
   151 		iPaused = EFalse;
   152 		iReconfiguring = EFalse;
   153 		if (iRTPStreamer) //if this is true then an error has occured somewhere
   154 			{//and we need to reset the streamer and close the socket
   155 			delete iRTPStreamer;
   156 			iRTPStreamer = NULL;
   157 			iGAVDPStateMachine->BearerSocket().Close();
   158 			}
   159 		}
   160 
   161 	if (iInitializeRequestStatus)
   162 		{
   163 		if (*iInitializeRequestStatus == KRequestPending)
   164 			{
   165 			User::RequestComplete(iInitializeRequestStatus, aError);
   166 			}
   167 		}
   168 	}
   169 	
   170 
   171 /**
   172 Handles the state change GAVDPOpen->GAVDPStreaming
   173 This state change occurs as a result to an OpenDevice call 
   174 This can get called twice, once if a reconfiguration is needed prior 
   175 to going in the streaming state where the state machine should still be in the open state
   176 and a second time when the state machine is in the streaming state
   177 */	
   178 void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeOpenToStreaming(TInt aError)
   179 	{
   180 	if (iOpenDeviceRequestStatus)
   181 		{
   182 		iOpenDeviceError = aError;
   183 		if (*iOpenDeviceRequestStatus == KRequestPending)
   184 			{
   185 			if (iReconfiguring)
   186 				{//should be in the OPEN state if we are reconfiguring
   187 				__ASSERT_DEBUG((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState));
   188 				iReconfiguring = EFalse;
   189 				if (!iOpenDeviceError)
   190 					{
   191 					//move GAVDP state to streaming
   192 					TGAVDPState state(TGAVDPState::EGAVDPStreaming);
   193 					iOpenDeviceError = iGAVDPStateMachine->ChangeState(state);
   194 					}
   195 				if (iOpenDeviceError)
   196 					{
   197 					SetSniffMode(ETrue); //go back to sniff mode
   198 					User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   199 					}
   200 				}//if (iReconfiguring)
   201 			else
   202 				{//callback must be in response to a streaming change state
   203 				__ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
   204 				if (!iOpenDeviceError)
   205 					{
   206 					__ASSERT_DEBUG((iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming),Panic(EA2dpBTHeadsetUnExpectedState));
   207 					delete iRTPStreamer;
   208 					iRTPStreamer = NULL;
   209 					TRAP(iOpenDeviceError,iRTPStreamer = CActiveRTPStreamer::NewL(iGAVDPStateMachine->BearerSocket(),*this));
   210 					if (!iOpenDeviceError)
   211 						{//create codec
   212 						iAudioSettingsHaveChanged = EFalse;
   213 						iRTPStreamer->SetAudioConfiguration(*iA2dpCodecConfiguration);
   214 						//if we have not set the data type ourselves then get iDataType
   215 						//from the code configuration
   216 						if (iDataType == KMMFFourCCCodeNULL)
   217 							{
   218 							iDataType = iA2dpCodecConfiguration->HeadsetCodecDataType();
   219 							if (iDataType == KMMFFourCCCodeSBC)
   220 								{//then the audio interfacef code will be pcm16
   221 								iDataType = KMMFFourCCCodePCM16;
   222 								}
   223 							}
   224 						if (iDataType == KMMFFourCCCodePCM16)
   225 							{//then an SBC codec is required
   226 							const TUid KSbcCodecUid = { KMmfUidCodecPCM16ToSBC };
   227 							TRAP(iOpenDeviceError,iCodec = CMMFCodec::NewL(KSbcCodecUid));
   228 							if (!iOpenDeviceError)
   229 								{
   230 								TUid configType;
   231 								configType.iUid = KMmfUidSBCConfigure;
   232 								TSBCFrameParameters& SBCFrameParameters = iA2dpCodecConfiguration->UpdateLocalSBCCodecConfiguration();
   233 								//use a package buffer for codec config to keep flexability should
   234 								//it be possible to use other codecs rather than SBC in future.
   235 								TPckgBuf<TSBCFrameParameters> SBCFrameParametersBuf(SBCFrameParameters);
   236 								TRAP(iOpenDeviceError,iCodec->ConfigureL(configType, SBCFrameParametersBuf));
   237 								iRTPStreamer->SetCodec(*iCodec);
   238 								}
   239 							}
   240 						}//if (!iOpenDeviceError)
   241 					}//if (!iOpenDeviceError)
   242 				if ((iOpenDeviceError) && (iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming))
   243 					{
   244 					//there was an error so wind back state to EGAVDPOpen
   245 					//don't complete the OpenDevice request status till we've wound back
   246 					TGAVDPState state(TGAVDPState::EGAVDPOpen);
   247 					TInt iOpenDeviceError = iGAVDPStateMachine->ChangeState(state);
   248 					//if the above fails there's not much we can do
   249 					}
   250 				else
   251 					{
   252 					//if we get to here then we should either be in the streaming state with no errors
   253 					//or in the open state with an error - either way we complete the OpenDevice request status
   254 					User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   255 					if (iOpenDeviceError)
   256 						{
   257 						SetSniffMode(ETrue);
   258 						}
   259 					}
   260 				}//else  if not (iReconfiguring)
   261 			}//	if (*iOpenRequestStatus == KRequestPending)
   262 		}//if (iOpenRequestStatus)
   263 	}
   264 
   265 
   266 /*
   267 Handles the state change GAVDPStreaming->GAVDPOpen
   268 The transition from streaming to open can be caused by one of two ways
   269 1 - A call to CloseDevice
   270 2 - A call to Open device where there was an error after the transition to streaming
   271 */	
   272 void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeStreamingToOpen(TInt aError)
   273 	{
   274 	__ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
   275 	
   276 	//only have streamer and codec in streaming state
   277 	delete iRTPStreamer;
   278 	iRTPStreamer = NULL;
   279 	delete iCodec;
   280 	iCodec = NULL;
   281 	
   282 	if (iCloseDeviceRequestStatus)
   283 		{//state change is in response to a close device
   284 		if (*iCloseDeviceRequestStatus == KRequestPending)
   285 			{
   286 			User::RequestComplete(iCloseDeviceRequestStatus, aError);
   287 			}
   288 		}
   289 	else if (iOpenDeviceRequestStatus)
   290 		{
   291 		//it must be a failed OpenDevice where the state has been wound back to EGAVDPOpen
   292 		__ASSERT_DEBUG((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState));
   293 		//the following ASSERT_DEBUG should be present but is commented out as the RVCT 
   294 		//compiler generates a warning
   295 		//__ASSERT_DEBUG((iOpenDeviceError), EA2dpBTHeadsetUnExpectedState);
   296 		if (*iOpenDeviceRequestStatus == KRequestPending)
   297 			{
   298 			User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   299 			}
   300 		}
   301 	SetSniffMode(ETrue);
   302 	}
   303 
   304 /**
   305 Callback by the GAVDP state machine when a GAVDP state change has been completed
   306 
   307 @param aInitialState The TGAVDPState prior to the start of the state change
   308 @param aCurrentState The current TGAVDPState of the GAVDP state machine
   309 @param aError standard Symbian error code.  
   310 */
   311 void CA2dpBTHeadsetAudioInterface::GAVDPStateChangeComplete(const TGAVDPState& aInitialState, TInt aError)
   312 	{	
   313 	switch(aInitialState.State())
   314 		{
   315 		case TGAVDPState::EGAVDPIdle:
   316 			ProcessGAVDPStateChangeIdleToOpen(aError);
   317 			break;
   318 		case TGAVDPState::EGAVDPOpen:
   319 			ProcessGAVDPStateChangeOpenToStreaming(aError);
   320 			break;
   321 		case TGAVDPState::EGAVDPStreaming:
   322 			ProcessGAVDPStateChangeStreamingToOpen(aError);	
   323 			break;
   324 		default:
   325 			Panic(EA2dpBTHeadsetUnExpectedState);
   326 			break;
   327 		}
   328 	}
   329 
   330 
   331 /**
   332 Returns a list of the supported datatypes for audio that can be sent to the headset.
   333 The list is obtained from the headset, so the headset need to have been Initialized first
   334 	
   335 @param  aSupportedDataTypes
   336 The array of supported data types that will be filled in by this function.
   337 The supported data types are in the form of an array
   338 of TFourCC codes. Any existing entries in the array will be overwritten on 
   339 calling this function. 
   340 @return standard Symbian error code.   
   341 KErrNotReady if headset has not been initialized.
   342 */
   343 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedDataTypes(RArray<TFourCC>& aSupportedDataTypes) const
   344 	{
   345 	aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array
   346 	TInt err = KErrNone;
   347 	RArray<TUsableSEP>& usableSEPs = iGAVDPStateMachine->UsableSEPs();
   348 	TUint numberOfUsableSEPS = usableSEPs.Count();
   349 	if (numberOfUsableSEPS)
   350 		{
   351 		TUint i;
   352 		TUsableSEP SEP;
   353 		//iterate through the list of usable SEPs looking for one that supports
   354 		//the requested data type
   355 		for (i=0;  i<usableSEPs.Count(); i++)
   356 			{
   357 			SEP = usableSEPs[i];
   358 			//both the headset and the A2dpBTHeadsetAudioInterface need to
   359 			//support the datatype so check we also support the datatype
   360 			//currently only SBC & MP3 data types are supported
   361 			if ((SEP.iDataType == KMMFFourCCCodeSBC)||(SEP.iDataType == KMMFFourCCCodeMP3))
   362 				{
   363 				err = aSupportedDataTypes.Append(SEP.iDataType);
   364 				}
   365 			if (err)
   366 				{
   367 				break;
   368 				}
   369 			if (SEP.iDataType == KMMFFourCCCodeSBC)
   370 				{//then we also support pcm16
   371 				err = aSupportedDataTypes.Append(KMMFFourCCCodePCM16);
   372 				if (err)
   373 					{
   374 					break;
   375 					}
   376 				}
   377 			}
   378 		}
   379 	else if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   380 		{//no usable SEPs available so can't yet get supported data types
   381 		err = KErrNotReady;
   382 		}
   383 		
   384 	if (err)
   385 		{
   386 		aSupportedDataTypes.Reset();
   387 		}
   388 	return err;
   389 	}
   390 	
   391 
   392 /**
   393 Returns the sample rates supported by the headset.
   394 In the case of SBC the supported values are obtained from the headset.
   395 In the case of mp3,AAC & ATRAC 3 the values are not obtained from
   396 the headset as the underlying bluetoothav code does not have a defined structure
   397 for containing these values, therefore the mandatory values are returned
   398 	
   399 @param  aSupportedDiscreteRates
   400 The array of supported sample rates that will be filled in by this function.
   401 The supported data types are in the form of an array
   402 of TFourCC codes. Any existing entries in the array will be overwritten on 
   403 calling this function. 
   404 @param aSupportedRateRanges
   405 To cover the case where headsets support a range of sample rates
   406 @return standard Symbian error code.   
   407 KErrNotReady if headset has not been initialized.
   408 */	
   409 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates, RArray<TRange>& aSupportedRateRanges) const
   410 	{
   411 	TInt error = KErrNone;
   412 	aSupportedDiscreteRates.Reset();
   413 	aSupportedRateRanges.Reset();
   414 	
   415 	//get the codec capabilites from the GAVDP state machine
   416 	TAvdtpMediaCodecCapabilities* codecCaps = NULL;
   417 	error = iGAVDPStateMachine->CodecCaps(codecCaps);
   418 
   419 	if (!error)
   420 		{
   421 		error = TA2dpCodecCapabilityParser::GetSupportedSampleRates(*codecCaps,aSupportedDiscreteRates);
   422 		}
   423 	if (error)
   424 		{
   425 		aSupportedDiscreteRates.Reset();
   426 		}
   427 	
   428 	return error;
   429 	}
   430 	
   431 
   432 /**
   433 Returns the number of channels supported by the headset.
   434 In the case of SBC the supported values are obtained from the headset.
   435 In the case of mp3,AAC & ATRAC 3 the values are not obtained from
   436 the headset as the underlying bluetoothav code does not have a defined structure
   437 for containing these values, therefore the mandatory values are returned
   438 	
   439 @param  aSupportedChannels
   440 The array of supported number of channels that will be filled in by this function.
   441 Any existing entries in the array will be overwritten on 
   442 calling this function. 
   443 @param aStereoSupport
   444 Additional parameter to specifiy the stereo support
   445 @return standard Symbian error code.
   446 @see TMMFStereoSupport
   447 KErrNotReady if headset has not been initialized.
   448 */		
   449 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedChannels(RArray<TUint>& aSupportedChannels, TMMFStereoSupport& aStereoSupport) const
   450 	{
   451 	aSupportedChannels.Reset();
   452 	aStereoSupport = EMMFNone;
   453 	
   454 	TInt error = KErrNone;
   455 
   456 	//get the codec capabilites from the GAVDP state machine
   457 	TAvdtpMediaCodecCapabilities* codecCaps = NULL;
   458 	error = iGAVDPStateMachine->CodecCaps(codecCaps);
   459 	
   460 	if (!error)
   461 		{
   462 		error = TA2dpCodecCapabilityParser::GetSupportedChannels(*codecCaps, aSupportedChannels, aStereoSupport);
   463 		}
   464 	if (error) 
   465 		{
   466 		aSupportedChannels.Reset();
   467 		aStereoSupport = EMMFNone;
   468 		}
   469 	return error;
   470 	}
   471 	
   472 
   473 /**
   474 Sets the data type of the data sent to the CA2dpBTHeadsetAudioInterface
   475 Note that data type specified here may not be identical to the data type
   476 sent to the headset and hence the data type used in the the a2dp codec configuration.  
   477 ie if the CA2dpBTHeadsetAudioInterface data type set by this method is pcm16
   478 then the data type sent to the headset is SBC.
   479 note that this method just sets the internal iDatatype member
   480 the datatype cannot be changed on the fly, but only gets changed
   481 when the GAVDP state machine is reconfigured in CA2dpBTHeadsetAudioInterface::OpenDevice()
   482 
   483 @param  aSinkFourCC
   484         The 4CC code of the data to be supplied to this class instance.
   485         
   486 @return System wide error code indicating if the function call was successful.
   487 		KErrNotReady if the headset is not initialized
   488 		KErrInUse if the headset is already streaming
   489 		KErrNotSupported if the datatype is not supported
   490 */
   491 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetDataType(const TFourCC& aDataType)
   492 	{
   493 	TInt error = KErrNone;
   494 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   495 		{
   496 		return KErrNotReady;
   497 		}
   498 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   499 		{
   500 		return KErrInUse; //don't allow this while we're streaming audio
   501 		}
   502 		
   503 	//the requested data type is a non standard data type
   504 	//so first check if there is a SEP that supports it
   505 	RArray<TUsableSEP>& usableSEPs = iGAVDPStateMachine->UsableSEPs();
   506 	TUint i;
   507 	TUsableSEP SEP;
   508 	TBool dataTypeSupported = EFalse;
   509 	//iterate through the list of usable SEPs looking for one that supports
   510 	//the requested data type
   511 	for (i=0; i<usableSEPs.Count(); i++)
   512 		{
   513 		SEP = usableSEPs[i];
   514 		if (SEP.iDataType == aDataType)
   515 			{//one of the usable SEPs supports the requested data type
   516 			dataTypeSupported = ETrue;
   517 			iDataType = aDataType;
   518 			if (aDataType != iA2dpCodecConfiguration->HeadsetCodecDataType())
   519 				{
   520 				iA2dpCodecConfiguration->SetHeadsetCodecDataType(aDataType);
   521 				iAudioSettingsHaveChanged = ETrue;
   522 				}
   523 			break;
   524 			}
   525 		else if ((SEP.iDataType == KMMFFourCCCodeSBC) && (aDataType == KMMFFourCCCodePCM16))
   526 			{
   527 			dataTypeSupported = ETrue;
   528 			iDataType = aDataType;
   529 			if (iA2dpCodecConfiguration->HeadsetCodecDataType()!= KMMFFourCCCodeSBC)
   530 				{
   531 				iA2dpCodecConfiguration->SetHeadsetCodecDataType(KMMFFourCCCodeSBC);
   532 				iAudioSettingsHaveChanged = ETrue;
   533 				}
   534 			break;
   535 			}		
   536 		}
   537 	if (!dataTypeSupported)
   538 		{
   539 		error = KErrNotSupported;
   540 		}		
   541 	return error;
   542 	}
   543 	
   544 
   545 /**
   546 Sets the sample rate 
   547 
   548 @param aSampleRate
   549 @return System wide error code indicating if the function call was successful.
   550 		KErrNotReady if the headset is not initialized
   551 		KErrInUse if the headset is already streaming
   552 		KErrNotSupported if the sample rate is not supported
   553 */	
   554 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetSampleRate(TUint aSampleRate)
   555 	{
   556 	TInt error = KErrNone;
   557 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   558 		{
   559 		return KErrNotReady;
   560 		}
   561 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   562 		{
   563 		//don't allow this while we're streaming audio
   564 		return KErrInUse; 
   565 		}
   566 	
   567 	//check that the sample rate is supported
   568 	RArray<TUint> supportedDiscreteRates;
   569 	RArray<TRange> supportedRateRanges;
   570 	GetSupportedSampleRates(supportedDiscreteRates, supportedRateRanges);
   571 	if (supportedDiscreteRates.Find(aSampleRate) == KErrNotFound)
   572 		{
   573 		//in theory we should iterate through the ranges as well, however
   574 		//SBC only suports discrete values so just return KErrNotSupported
   575 		error = KErrNotSupported;
   576 		}
   577 	else
   578 		{
   579 		if (aSampleRate != iA2dpCodecConfiguration->SampleRate())
   580 			{
   581 			iA2dpCodecConfiguration->SetSampleRate(aSampleRate);
   582 			iAudioSettingsHaveChanged = ETrue;
   583 			}
   584 		}
   585 	supportedDiscreteRates.Close();
   586 	supportedRateRanges.Close();
   587 	return error;
   588 	}
   589 	
   590 
   591 /**
   592 Sets the number of channels 
   593 
   594 @param aSampleChannels
   595 @param aStereoSupport.  note that the aStereoSupport in the case of pcm16 refers to the output to the headset.
   596 the data going for pcm16 is always either interleaved stereo pcm16 or mono
   597 the aStereoSupport parameter is ignored for non stereo
   598 @see TMMFStereoSupport
   599 @return System wide error code indicating if the function call was successful.
   600 		KErrNotReady if the headset is not initialized
   601 		KErrInUse if the headset is already streaming
   602 		KErrNotSupported if the datatype is not supported
   603 */	
   604 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport)
   605 	{
   606 	TInt error = KErrNone;
   607 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   608 		{
   609 		return KErrNotReady;
   610 		}
   611 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   612 		{
   613 		return KErrInUse; //don't allow this while we're streaming audio
   614 		}
   615 
   616 	//check that the number of channels is supported
   617 	RArray<TUint> supportedChannels;
   618 	TMMFStereoSupport stereoSupport;
   619 	GetSupportedChannels(supportedChannels, stereoSupport);
   620 	if (supportedChannels.Find(aChannels) == KErrNotFound)
   621 		{
   622 		error = KErrNotSupported;
   623 		}	
   624 	else if (aChannels == EMMFStereo)
   625 		{
   626 		//now check stereo support
   627 		if ((aStereoSupport & stereoSupport) != aStereoSupport)
   628 			{
   629 			error = KErrNotSupported;
   630 			}
   631 		else if (iA2dpCodecConfiguration->StereoSupport() != aStereoSupport)
   632 			{
   633 			iA2dpCodecConfiguration->SetStereoSupport(aStereoSupport);
   634 			iAudioSettingsHaveChanged = ETrue;
   635 			}
   636 		}
   637 	if (!error)
   638 		{
   639 		if (iA2dpCodecConfiguration->Channels() != aChannels)
   640 			{
   641 			iA2dpCodecConfiguration->SetChannels(aChannels);
   642 			iAudioSettingsHaveChanged = ETrue;
   643 			}
   644 		}
   645 	return error;
   646 	}
   647 
   648 	
   649 /**
   650 Procedure to gets the headset into the GAVDP Streaming state where 
   651 it is ready to accept audio data.  The procedure causes a reconfiguration
   652 of the headset incase the settings have changed - and if they haven't then the 
   653 reconfigure does nothing.
   654 The GAVDPStateChangeComplete callback is called after the reconfigure
   655 where it puts the GAVDP state machine in the streaming state
   656 The GAVDPStateChangeComplete callback is called again when the headset device
   657 is in the streaming state.
   658 
   659 @param aStatus
   660 */
   661 EXPORT_C void CA2dpBTHeadsetAudioInterface::OpenDevice(TRequestStatus& aStatus)
   662 	{
   663 	iOpenDeviceRequestStatus = &aStatus;
   664 	*iOpenDeviceRequestStatus = KRequestPending;
   665 	
   666 	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   667 		{
   668 		//device is already open
   669 		User::RequestComplete(iOpenDeviceRequestStatus, KErrNone);
   670 		return;
   671 		}
   672 	
   673 	//this isn't a local error variable as it is used in the GAVDPStateChangeComplete callback
   674 	iOpenDeviceError = KErrNone;
   675 	//take out of sniff mode - no point in checking error code as there is
   676 	//not much that can be done
   677 	SetSniffMode(EFalse);
   678 	
   679 	//first reconfigure if the configuration has changed
   680 	//note that there is a subtle difference between the configuration of the 
   681 	//CA2dpBTHeadsetAudioInterface and that of the GAVDP state machine
   682 	//the configuration of the CA2dpBTHeadsetAudioInterface is the configuration
   683 	//seen from the DevSound whereas the CGAVDPStateMachine is the configuration
   684 	//as seen by the headset.  In most cases they would be identical, the only
   685 	//current case where the differ is in the data type where the DevSound sees
   686 	//the data tpye as pcm16 but the headset is SBC
   687 	iOpenDeviceError = iGAVDPStateMachine->Reconfigure(iAudioSettingsHaveChanged);
   688 	if (iOpenDeviceError)
   689 		{
   690 		User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   691 		}
   692 	else
   693 		{
   694 		//the Reconfigure will result in a GAVDPStateChangeComplete callback
   695 		iReconfiguring = ETrue;
   696 		}
   697 	}
   698 
   699 
   700 /**
   701  Procedure to cancel a GAVDP initialization sequence on an A2DP headset
   702 */	
   703 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelOpenDevice()
   704 	{
   705 	if (iOpenDeviceRequestStatus)
   706 		{
   707 		if (*iOpenDeviceRequestStatus == KRequestPending)//make sure there is a pending request to cancel
   708 			{
   709 			iGAVDPStateMachine->CancelChangeState();
   710 			}
   711 		}
   712 	}
   713 
   714 /**
   715 Procedure to put a headset that is in the GAVDP Streaming state back into
   716 the GAVDP Open state
   717 The GAVDPStateChangeComplete callback is called again when the headset device
   718 is in the open state.
   719 
   720 @param aStatus
   721 */	
   722 EXPORT_C void CA2dpBTHeadsetAudioInterface::CloseDevice(TRequestStatus& aStatus)
   723 	{
   724 	iCloseDeviceRequestStatus = &aStatus;
   725 	*iCloseDeviceRequestStatus = KRequestPending;
   726 	
   727 	if (iGAVDPStateMachine->State() != TGAVDPState::EGAVDPStreaming)
   728 		{
   729 		//device isn't open
   730 		User::RequestComplete(iCloseDeviceRequestStatus, KErrNone);
   731 		return;
   732 		}
   733 	else
   734 		{
   735 		if (iRTPStreamer)
   736 			{
   737 			iRTPStreamer->Pause();
   738 			}
   739 		//note the callback ProcessGAVDPStateChangeStreamingToOpen
   740 		//will put the BT link back in sniff mode
   741 		TGAVDPState state(TGAVDPState::EGAVDPOpen);
   742 		TInt err = iGAVDPStateMachine->ChangeState(state);
   743 		if (err)
   744 			{
   745 			User::RequestComplete(iCloseDeviceRequestStatus, err);
   746 			}
   747 		}
   748 	}
   749 
   750 /**
   751 Procedure to get the headset volume
   752 
   753 @return volume in the range 0-255
   754 */	
   755 EXPORT_C TUint CA2dpBTHeadsetAudioInterface::Volume() const
   756 	{
   757 	return 0;
   758 	}
   759 	
   760 
   761 /**
   762 Procedure to set the volume in the range 0-255
   763 Note this procedure requires the AVRCP bluettooth profile
   764 in order to change the volume which is not implemented
   765 
   766 @param aVolume the volume in the range 0-255
   767 */	
   768 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetVolume(TUint /*aVolume*/)
   769 	{
   770 	return KErrNone;
   771 	}
   772 	
   773 
   774 /**
   775 This function causes the CA2dpBTHeadsetAudioInterface to send the audio data contained in aData to the initialized A2DP headset.
   776 The data is buffered internally and CA2dpBTHeadsetAudioInterface may already be playing audio
   777 when this method is called.
   778 The TRequestStatus is completed when the CA2dpBTHeadsetAudioInterface  has finished with the audio data contained in aData.  
   779 By 'finished' this does not mean finished as in physically finished playing the audio,
   780 but to inform the client that:
   781 a)	it can repopulate the buffer with new audio data.
   782 b)	the  CA2dpBTHeadsetAudioInterface is ready to accept another buffer of audio data via a further call to PlayData()
   783 (ie the CA2dpBTHeadsetAudioInterface is not expected to accept multiple buffers in succession prior to completing their
   784 TRequestStatus as this would not provide the client with any indication of whether the
   785 sound drivers internal buffers are full).
   786 
   787 @param aStatus  The TRequestStatus completed when the sound driver has finished with the audio data contained in aData.
   788 The TRequestStatus is set to KErrNone unless the request has been cancelled via CancelPlayData()
   789 in which case the status will be set to KErrCancel. 
   790 The TRequestStatus is completed as soon as possible and before the audio has been physically played
   791 in order for the client to send further audio buffers before the buffers already in the sound driver
   792 are played out. 
   793 Prior to calling PlayData() the client would be expected to Initialize Configure and Open the CA2dpBTHeadsetAudioInterface
   794 and register with the sound driver that it requires notification of error conditions via a call to NotifyPlayError().
   795 	
   796 @param aData  Buffer containing the audio data to be played.  
   797 aData, is not owned or created by the sound driver but is owned by the client.  
   798 */
   799 EXPORT_C void CA2dpBTHeadsetAudioInterface::PlayData(const TDesC8& aData, TRequestStatus& aStatus)
   800 	{
   801 	__ASSERT_DEBUG((aData.Length()), Panic(EA2dpBTHeadsetNoData));
   802 	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   803 	
   804 	iRTPStreamer->Send(aData, aStatus);
   805 	}
   806 	
   807 /**
   808 Cancels the current request for PlayData() if currently active.
   809 The currently active PlayData() completes the request status immediately with KErrCancel.
   810 */	
   811 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelPlayData()
   812 	{
   813 	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   814 		
   815 	iRTPStreamer->CancelLastSendBuffer();
   816 	}
   817 	
   818 
   819 /**
   820 Used to clear all internally buffered audio.  
   821 This function does not complete any pending TRequestStatuses.  
   822 */	
   823 EXPORT_C void CA2dpBTHeadsetAudioInterface::FlushBuffer()
   824 	{
   825 	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   826 	
   827 	iRTPStreamer->FlushPendingSendBuffers();
   828 	}
   829 
   830 	
   831 /**
   832 Returns the total number of bytes of data sent in PlayData that have been
   833 sent to the headset.  ie the number of bytes sent prior to any encoding by the SBC codec.
   834 It is updated after each buffer has been sent to the headset. 
   835 The BytesPlayed are not reset to 0 on an error condition.
   836 It must be explicitly reset via a call to ResetBytesPlayed().
   837 	
   838 @param The number of bytes played
   839 */	
   840 EXPORT_C TUint CA2dpBTHeadsetAudioInterface::BytesPlayed() const
   841 	{
   842 	TUint bytesPlayed = 0;
   843 	if (iRTPStreamer)//don't ASSERT iRTPStreamer here as this API still has meaning with no streamer
   844 		{
   845 		bytesPlayed = iRTPStreamer->BytesSent();
   846 		}
   847 	return bytesPlayed;
   848 	}
   849 
   850 
   851 /**
   852 Resets bytes played to 0.
   853 */	
   854 EXPORT_C void CA2dpBTHeadsetAudioInterface::ResetBytesPlayed()
   855 	{
   856 	if (iRTPStreamer)//don't ASSERT iRTPStreamer here as this API still has meaning with no streamer
   857 		{
   858 		iRTPStreamer->ResetBytesSent();
   859 		}
   860 	}
   861 	
   862 
   863 /**
   864 Function to halt the sending of buffers to the headset.
   865 Note that even if no buffers are being send via PlayData buffers
   866 can still be sent to the headset as they are buffered internally
   867 Calling PauseBuffer stops the internally buffered data being sent as well
   868 as any buffers sent via PlayData
   869 If the TRequestStatus from the previous PlayData() is outstanding then PausePlayBuffer()
   870 does not complete the TRequestStatus.
   871 The TRequestStatus will only be completed after ResumePlaying() is called.
   872 */	
   873 EXPORT_C void CA2dpBTHeadsetAudioInterface::PauseBuffer()
   874 	{
   875 	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   876 	
   877 	iRTPStreamer->Pause();
   878 	iPaused = ETrue;
   879 	}
   880 
   881 	
   882 /**
   883 This resumes playing from where playing was halted from the previous call to PauseBuffer().
   884 The next TRequestStatus (if active) to be completed, is the request status from the previous PlayData()
   885 prior to calling PausePlayBuffer().
   886 If PausePlayBuffer() has not been called prior to ResumePlaying(),
   887 then this method does nothing.
   888 */	
   889 EXPORT_C void CA2dpBTHeadsetAudioInterface::ResumePlaying()
   890 	{
   891 	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   892 	
   893 	iRTPStreamer->Resume();
   894 	iPaused = EFalse;
   895 	}
   896 	
   897 
   898 /**
   899 This function is used when the client is requesting notification of an error that occurs during playback.
   900 The TRequestStatus passed in the NotifyPlayError() method is separate to the TRequestStatus passed into the PlayData() method,
   901 and hence the client would typically have a separate active object for both the PlayData()
   902 and NotifyPlayError() TRequestStatuses.
   903 The NotifyPlayError() method is required because if an error occurs during playback,
   904 the PlayData() TRequestStatus may not be active.
   905 If a PlayData() request status is active then the error is reported back via the PlayData()
   906 TRequestStatus and not via the NotifyPlayError() TRequestStatus.
   907 If no PlayData() TRequestStatus is active then the error is reported back by completing the NotifyPlayError()
   908 TRequestStatus with the appropriate error code.
   909 Note that a call to CancelPlayData() should complete the PlayData() request status with KErrCancel
   910 and should not complete the NotifyPlayError() TRequestStatus.
   911 
   912 @param aStatus TRequestStatus completed when a play error occurs.
   913 */	
   914 EXPORT_C void CA2dpBTHeadsetAudioInterface::NotifyError(TRequestStatus& aStatus)
   915 	{
   916 	iNotifyRequestStatus= &aStatus;
   917 	*iNotifyRequestStatus = KRequestPending;
   918 	}
   919 	
   920 
   921 /**
   922 Cancels the NotifyPlayError() TRequestStatus if currently active.
   923 The TRequestStatus completes immediately with KErrCancel.
   924 */	
   925 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelNotifyError()
   926 	{
   927 	User::RequestComplete(iNotifyRequestStatus, KErrCancel);
   928 	}
   929 
   930 
   931 /**
   932 Callback from the RTPStreamer when an unexpected event occurs
   933 
   934 @param aError
   935 */
   936 void CA2dpBTHeadsetAudioInterface::RTPStreamerEvent(TInt aError)
   937 	{
   938 	//an error has occured while streaming
   939 	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   940 	//could also be EGAVDPIdle as we could have just received a GAVDPStateMachineEvent
   941 	//which would reset the state to EGAVDPIdle
   942 	__ASSERT_DEBUG((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming) ||
   943 	(iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle), Panic(EA2dpBTHeadsetUnExpectedState));
   944 	TGAVDPState state(TGAVDPState::EGAVDPIdle);
   945 	TInt err = iGAVDPStateMachine->ChangeState(state);
   946 	//the above returns an error code but there's not much we can do if it returns an error
   947 
   948 	if (iNotifyRequestStatus)
   949 		{
   950 		if (*iNotifyRequestStatus == KRequestPending)
   951 			{
   952 			User::RequestComplete(iNotifyRequestStatus, aError);
   953 			}
   954 		}
   955 	}
   956 
   957 
   958 /**
   959 Callback from the GAVDPStateMachine when an error event occurs
   960 
   961 @param aError
   962 */	
   963 void  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineEvent(TInt aError)
   964 	{
   965 	//an error has occured - if an error occurs then it could be
   966 	//because we've lost the connection to the headset eg because it is out of range
   967 	//has been switched off etc there we assume that the connection has been
   968 	//lost and put the GAVDP state back to idle
   969 	//note we're simplifying things somewhat as some errors may not be a result 
   970 	//of a loss of connection to the headset
   971 	TGAVDPState state(TGAVDPState::EGAVDPIdle);
   972 	TInt err = iGAVDPStateMachine->ChangeState(state);
   973 	if (!iRTPStreamer)
   974 		{//if we don't have an RTP streamer
   975 		//then close the bearer socket.  If we do have an RTP streamer
   976 		//then delay the close till after we have deleted the RTPStreamer in the
   977 		//the GAVDPStateChangeComplete callback.  this is because
   978 		//closing the bearer socket before the RTP streamer is deleted
   979 		//can panic the RTP stack.
   980 		iGAVDPStateMachine->BearerSocket().Close();
   981 		}	
   982 	if (iNotifyRequestStatus)
   983 		{
   984 		if (*iNotifyRequestStatus == KRequestPending)
   985 			{
   986 			User::RequestComplete(iNotifyRequestStatus, aError);
   987 			}
   988 		}
   989 	}
   990 
   991 	
   992 /**
   993 Callback from the GAVDPStateMachine when the headset has suspended the stream
   994 */
   995 void  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineStreamSuspendedByRemoteHeadset()
   996 	{
   997 	if (iRTPStreamer)
   998 		{
   999 		iRTPStreamer->Pause();
  1000 		}
  1001 	}
  1002 
  1003 
  1004 /**
  1005 Callback from the GAVDPStateMachine when the headset has resumed a suspended stream
  1006 */	
  1007 void  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineStreamResumedByRemoteHeadset()
  1008 	{
  1009 	if ((!iPaused)&&(iRTPStreamer))
  1010 		{
  1011 		iRTPStreamer->Resume();
  1012 		}
  1013 	}
  1014 
  1015 
  1016 /**
  1017 Callback from the GAVDPStateMachine when the headset has reconfigured the parameters
  1018 reconfigures codec with new configuration and inform RTP streamer
  1019 
  1020 @return SymbianOS error code
  1021 */
  1022 TInt  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineReconfigureByRemoteHeadset()
  1023 	{
  1024 	//we're only allowing the headset to reconfigure for SBC SEP
  1025 	__ASSERT_DEBUG(iA2dpCodecConfiguration->HeadsetCodecDataType() == KMMFFourCCCodeSBC, Panic(	EA2dpBTHeadsetUnexpectedDataType));
  1026 	__ASSERT_DEBUG(iCodec,Panic(EA2dpBTHeadsetNoCodec));
  1027 	TUid configType;
  1028 	TInt err = KErrNone;
  1029 	configType.iUid = KMmfUidSBCConfigure;
  1030 	TSBCFrameParameters& SBCFrameParameters = iA2dpCodecConfiguration->UpdateLocalSBCCodecConfiguration();
  1031 	TPckgBuf<TSBCFrameParameters> SBCFrameParametersBuf(SBCFrameParameters);
  1032 	TRAP(err,iCodec->ConfigureL(configType, SBCFrameParametersBuf)); //update codec with new configuration
  1033 	iRTPStreamer->SetAudioConfiguration(*iA2dpCodecConfiguration); //and tell RTP streamer	
  1034 	return err;
  1035 	}
  1036 
  1037 
  1038 /**
  1039 Function to set/release the BT link into low power sniff mode
  1040 
  1041 @internalComponent
  1042 @return Error code, this is used for debugging, it's not checked
  1043 by the calling code as if SetSniffMode fails there's not much that can be
  1044 done in the calling code
  1045 */
  1046 TInt CA2dpBTHeadsetAudioInterface::SetSniffMode(TBool aSniffMode)
  1047 	{
  1048 	TInt err = KErrNone;
  1049 	
  1050 	if (!iGAVDPStateMachine)
  1051 		{
  1052 		return KErrNotReady;
  1053 		}
  1054 		
  1055 	if (iGAVDPStateMachine->BTAddress() == TBTDevAddr(0))
  1056 		{
  1057 		return KErrNotReady;
  1058 		}
  1059 
  1060 	err = iBTPhysicalLinkAdapter.Open(iSocketServer, iGAVDPStateMachine->BTAddress());
  1061 	if (!err)
  1062 		{
  1063 		if (aSniffMode)
  1064 			{
  1065 			err = iBTPhysicalLinkAdapter.AllowLowPowerModes(ESniffMode);
  1066 			err = iBTPhysicalLinkAdapter.ActivateSniffRequester();
  1067 			}
  1068 		else
  1069 			{
  1070 			err = iBTPhysicalLinkAdapter.CancelLowPowerModeRequester();
  1071 			}
  1072 		iBTPhysicalLinkAdapter.Close();
  1073 		}
  1074 
  1075 	return err;
  1076 	}
  1077 	
  1078 
  1079 /**
  1080 This function should only used by the TSU_MMF_A2DPBLUETOOTH unit test harness
  1081 It allows the test harness to get at the MGavdpUser in order
  1082 to emulate actions from the headset
  1083 
  1084 @return the GavdpState machine as a MGavdpUser mixin
  1085 */	
  1086 EXPORT_C MGavdpUser* CA2dpBTHeadsetAudioInterface::TEST_MGavdpUser()
  1087 	{
  1088 	return static_cast<MGavdpUser*>(iGAVDPStateMachine);
  1089 	}
  1090 	
  1091 
  1092 /**
  1093 This function should only used by the TSU_MMF_A2DPBLUETOOTH unit test harness
  1094 It allows the test harness to override the configuration of the remote headset
  1095 for the SBC codec with regard to sampling frequencies, block size; subbands and allocation method
  1096 
  1097 @param
  1098 */
  1099 EXPORT_C void CA2dpBTHeadsetAudioInterface::TEST_ForceRemoteSBCCodecConfiguration(const TSBCCodecCapabilities& aRemoteCodecConfiguration)
  1100 	{
  1101 	iA2dpCodecConfiguration->TEST_ForceRemoteSBCCodecConfiguration(aRemoteCodecConfiguration);
  1102 	}