os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/A2dpBTheadsetAudioIf.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/A2dpBTheadsetAudioIf.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1102 @@
     1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include <mmf/server/mmfcodec.h>
    1.20 +#include "mmfSBCCodecImplementationUIDs.hrh"
    1.21 +#include <mmffourcc.h>
    1.22 +#include "A2dpCodecUtilities.h"
    1.23 +#include "A2dpBTheadsetAudioIf.h"
    1.24 +#include "MMFBtRoutingSoundDevice.h"	// for TRange
    1.25 +
    1.26 +/**
    1.27 +Panics
    1.28 +**/
    1.29 +enum TA2dpBTHeadsetPanic
    1.30 +	{
    1.31 +	EA2dpBTHeadsetUnExpectedState,//0
    1.32 +	EA2dpBTHeadsetNoRTPStreamer,//1
    1.33 +	EA2dpBTHeadsetNoData,//2
    1.34 +	EA2dpBTHeadsetUnexpectedDataType,//3
    1.35 +	EA2dpBTHeadsetBTAddrNotSet, //4
    1.36 +	EA2dpBTHeadsetNoCodec //5
    1.37 +	};
    1.38 +
    1.39 +
    1.40 +static void Panic(TA2dpBTHeadsetPanic aPanic)
    1.41 +// Panic client
    1.42 +	{
    1.43 +	_LIT(KA2dpBTHeadsetPanicName, "A2DP BT If Panic");
    1.44 +	User::Panic(KA2dpBTHeadsetPanicName, aPanic);
    1.45 +	}
    1.46 +
    1.47 +
    1.48 +CA2dpBTHeadsetAudioInterface::CA2dpBTHeadsetAudioInterface()
    1.49 +	{
    1.50 +	}
    1.51 +
    1.52 +void CA2dpBTHeadsetAudioInterface::ConstructL()
    1.53 +	{
    1.54 +	iA2dpCodecConfiguration = CA2dpAudioCodecConfiguration::NewL();
    1.55 +	User::LeaveIfError(iSocketServer.Connect());
    1.56 +	iGAVDPStateMachine = CGAVDPStateMachine::NewL(*this, *iA2dpCodecConfiguration, iSocketServer);	
    1.57 +	}
    1.58 +	
    1.59 +/**
    1.60 +Creates CA2dpBTHeadsetAudioInterface
    1.61 +Note there should only ever be one CA2dpBTHeadsetAudioInterface*
    1.62 +However this being a singleton is not enforced in this class however
    1.63 +The client of this class ie the CA2dpBTHeadsetAudioServer should enforce this.
    1.64 + 
    1.65 +@return CA2dpBTHeadsetAudioInterface*
    1.66 +*/	
    1.67 +EXPORT_C CA2dpBTHeadsetAudioInterface* CA2dpBTHeadsetAudioInterface::NewL()
    1.68 +	{
    1.69 +	CA2dpBTHeadsetAudioInterface* self = new(ELeave) CA2dpBTHeadsetAudioInterface();
    1.70 +	CleanupStack::PushL(self);
    1.71 +	self->ConstructL();
    1.72 +	CleanupStack::Pop(self);
    1.73 +	return self;
    1.74 +	}
    1.75 +
    1.76 +/**
    1.77 +destructor
    1.78 +*/	
    1.79 +EXPORT_C CA2dpBTHeadsetAudioInterface::~CA2dpBTHeadsetAudioInterface()
    1.80 +	{
    1.81 +	SetSniffMode(ETrue);
    1.82 +	delete iGAVDPStateMachine;
    1.83 +	delete iCodec;
    1.84 +	delete iA2dpCodecConfiguration;
    1.85 +	delete iRTPStreamer;
    1.86 +	iSocketServer.Close();
    1.87 +	}
    1.88 +	
    1.89 +
    1.90 +/**
    1.91 +Procedure to perform a GAVDP initialization sequence on an A2DP headset
    1.92 +If the headset is already initialized then this procedure does not perform
    1.93 +any further initialization.
    1.94 +if link has gone down since a previous call to Initialize then
    1.95 +calling this function will perform a full reinitialize.
    1.96 +if link goes down during initialization will generate error
    1.97 +The GAVDPStateChangeComplete callback is called when the headset device
    1.98 +is in the open state.
    1.99 +The headset is in the GAVDP_Open state on completion
   1.100 +It is not possible to perform an Initialize if the headset is already in the
   1.101 +streaming state or is already being initialized.
   1.102 +
   1.103 +@param aRemoteAddress Address of the bluetooth headset we are trying to initialize
   1.104 +@param aStatus
   1.105 +*/	
   1.106 +EXPORT_C void CA2dpBTHeadsetAudioInterface::Initialize(const TBTDevAddr& aRemoteAddress, TRequestStatus& aStatus)
   1.107 +	{
   1.108 +	__ASSERT_ALWAYS(((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)||
   1.109 +					(iGAVDPStateMachine->State() == TGAVDPState::EGAVDPOpen)), Panic(EA2dpBTHeadsetUnExpectedState));
   1.110 +	__ASSERT_ALWAYS(!iReconfiguring, Panic(EA2dpBTHeadsetUnExpectedState)); //can't initialize while we're reconfiguring
   1.111 +	iInitializeRequestStatus = &aStatus;
   1.112 +	*iInitializeRequestStatus = KRequestPending;
   1.113 +	
   1.114 +	//this will cause a full initialization if the address has changed
   1.115 +	iGAVDPStateMachine->SetBTAddress(aRemoteAddress);
   1.116 +	
   1.117 +	TGAVDPState state(TGAVDPState::EGAVDPOpen);
   1.118 +	TInt err = iGAVDPStateMachine->ChangeState(state);
   1.119 +	if (err)
   1.120 +		{
   1.121 +		User::RequestComplete(iInitializeRequestStatus, err);
   1.122 +		}	
   1.123 +	}
   1.124 +
   1.125 +
   1.126 +/**
   1.127 +Procedure to cancel a GAVDP initialization sequence on an A2DP headset
   1.128 +*/		
   1.129 +EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelInitialize()
   1.130 +	{
   1.131 +	if (iInitializeRequestStatus)
   1.132 +		{
   1.133 +		if (*iInitializeRequestStatus == KRequestPending)//make sure there is a pending request to cancel
   1.134 +			{
   1.135 +			iGAVDPStateMachine->CancelChangeState();
   1.136 +			}
   1.137 +		}
   1.138 +	}
   1.139 +	
   1.140 +
   1.141 +/**
   1.142 +Handles the state change GAVDPIdle->GAVDPOpen
   1.143 +This state change usually occurs as a result to an Initialize call
   1.144 +Can also occur due to an error condition resulting in a GAVDP state machine reset 
   1.145 +*/
   1.146 +void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeIdleToOpen(TInt aError)
   1.147 +	{
   1.148 +	__ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPOpen||
   1.149 +	iGAVDPStateMachine->State()==TGAVDPState::EGAVDPIdle),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
   1.150 +	
   1.151 +	if (!aError)
   1.152 +		{
   1.153 +		SetSniffMode(ETrue);
   1.154 +		iPaused = EFalse;
   1.155 +		iReconfiguring = EFalse;
   1.156 +		if (iRTPStreamer) //if this is true then an error has occured somewhere
   1.157 +			{//and we need to reset the streamer and close the socket
   1.158 +			delete iRTPStreamer;
   1.159 +			iRTPStreamer = NULL;
   1.160 +			iGAVDPStateMachine->BearerSocket().Close();
   1.161 +			}
   1.162 +		}
   1.163 +
   1.164 +	if (iInitializeRequestStatus)
   1.165 +		{
   1.166 +		if (*iInitializeRequestStatus == KRequestPending)
   1.167 +			{
   1.168 +			User::RequestComplete(iInitializeRequestStatus, aError);
   1.169 +			}
   1.170 +		}
   1.171 +	}
   1.172 +	
   1.173 +
   1.174 +/**
   1.175 +Handles the state change GAVDPOpen->GAVDPStreaming
   1.176 +This state change occurs as a result to an OpenDevice call 
   1.177 +This can get called twice, once if a reconfiguration is needed prior 
   1.178 +to going in the streaming state where the state machine should still be in the open state
   1.179 +and a second time when the state machine is in the streaming state
   1.180 +*/	
   1.181 +void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeOpenToStreaming(TInt aError)
   1.182 +	{
   1.183 +	if (iOpenDeviceRequestStatus)
   1.184 +		{
   1.185 +		iOpenDeviceError = aError;
   1.186 +		if (*iOpenDeviceRequestStatus == KRequestPending)
   1.187 +			{
   1.188 +			if (iReconfiguring)
   1.189 +				{//should be in the OPEN state if we are reconfiguring
   1.190 +				__ASSERT_DEBUG((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState));
   1.191 +				iReconfiguring = EFalse;
   1.192 +				if (!iOpenDeviceError)
   1.193 +					{
   1.194 +					//move GAVDP state to streaming
   1.195 +					TGAVDPState state(TGAVDPState::EGAVDPStreaming);
   1.196 +					iOpenDeviceError = iGAVDPStateMachine->ChangeState(state);
   1.197 +					}
   1.198 +				if (iOpenDeviceError)
   1.199 +					{
   1.200 +					SetSniffMode(ETrue); //go back to sniff mode
   1.201 +					User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   1.202 +					}
   1.203 +				}//if (iReconfiguring)
   1.204 +			else
   1.205 +				{//callback must be in response to a streaming change state
   1.206 +				__ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
   1.207 +				if (!iOpenDeviceError)
   1.208 +					{
   1.209 +					__ASSERT_DEBUG((iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming),Panic(EA2dpBTHeadsetUnExpectedState));
   1.210 +					delete iRTPStreamer;
   1.211 +					iRTPStreamer = NULL;
   1.212 +					TRAP(iOpenDeviceError,iRTPStreamer = CActiveRTPStreamer::NewL(iGAVDPStateMachine->BearerSocket(),*this));
   1.213 +					if (!iOpenDeviceError)
   1.214 +						{//create codec
   1.215 +						iAudioSettingsHaveChanged = EFalse;
   1.216 +						iRTPStreamer->SetAudioConfiguration(*iA2dpCodecConfiguration);
   1.217 +						//if we have not set the data type ourselves then get iDataType
   1.218 +						//from the code configuration
   1.219 +						if (iDataType == KMMFFourCCCodeNULL)
   1.220 +							{
   1.221 +							iDataType = iA2dpCodecConfiguration->HeadsetCodecDataType();
   1.222 +							if (iDataType == KMMFFourCCCodeSBC)
   1.223 +								{//then the audio interfacef code will be pcm16
   1.224 +								iDataType = KMMFFourCCCodePCM16;
   1.225 +								}
   1.226 +							}
   1.227 +						if (iDataType == KMMFFourCCCodePCM16)
   1.228 +							{//then an SBC codec is required
   1.229 +							const TUid KSbcCodecUid = { KMmfUidCodecPCM16ToSBC };
   1.230 +							TRAP(iOpenDeviceError,iCodec = CMMFCodec::NewL(KSbcCodecUid));
   1.231 +							if (!iOpenDeviceError)
   1.232 +								{
   1.233 +								TUid configType;
   1.234 +								configType.iUid = KMmfUidSBCConfigure;
   1.235 +								TSBCFrameParameters& SBCFrameParameters = iA2dpCodecConfiguration->UpdateLocalSBCCodecConfiguration();
   1.236 +								//use a package buffer for codec config to keep flexability should
   1.237 +								//it be possible to use other codecs rather than SBC in future.
   1.238 +								TPckgBuf<TSBCFrameParameters> SBCFrameParametersBuf(SBCFrameParameters);
   1.239 +								TRAP(iOpenDeviceError,iCodec->ConfigureL(configType, SBCFrameParametersBuf));
   1.240 +								iRTPStreamer->SetCodec(*iCodec);
   1.241 +								}
   1.242 +							}
   1.243 +						}//if (!iOpenDeviceError)
   1.244 +					}//if (!iOpenDeviceError)
   1.245 +				if ((iOpenDeviceError) && (iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming))
   1.246 +					{
   1.247 +					//there was an error so wind back state to EGAVDPOpen
   1.248 +					//don't complete the OpenDevice request status till we've wound back
   1.249 +					TGAVDPState state(TGAVDPState::EGAVDPOpen);
   1.250 +					TInt iOpenDeviceError = iGAVDPStateMachine->ChangeState(state);
   1.251 +					//if the above fails there's not much we can do
   1.252 +					}
   1.253 +				else
   1.254 +					{
   1.255 +					//if we get to here then we should either be in the streaming state with no errors
   1.256 +					//or in the open state with an error - either way we complete the OpenDevice request status
   1.257 +					User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   1.258 +					if (iOpenDeviceError)
   1.259 +						{
   1.260 +						SetSniffMode(ETrue);
   1.261 +						}
   1.262 +					}
   1.263 +				}//else  if not (iReconfiguring)
   1.264 +			}//	if (*iOpenRequestStatus == KRequestPending)
   1.265 +		}//if (iOpenRequestStatus)
   1.266 +	}
   1.267 +
   1.268 +
   1.269 +/*
   1.270 +Handles the state change GAVDPStreaming->GAVDPOpen
   1.271 +The transition from streaming to open can be caused by one of two ways
   1.272 +1 - A call to CloseDevice
   1.273 +2 - A call to Open device where there was an error after the transition to streaming
   1.274 +*/	
   1.275 +void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeStreamingToOpen(TInt aError)
   1.276 +	{
   1.277 +	__ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
   1.278 +	
   1.279 +	//only have streamer and codec in streaming state
   1.280 +	delete iRTPStreamer;
   1.281 +	iRTPStreamer = NULL;
   1.282 +	delete iCodec;
   1.283 +	iCodec = NULL;
   1.284 +	
   1.285 +	if (iCloseDeviceRequestStatus)
   1.286 +		{//state change is in response to a close device
   1.287 +		if (*iCloseDeviceRequestStatus == KRequestPending)
   1.288 +			{
   1.289 +			User::RequestComplete(iCloseDeviceRequestStatus, aError);
   1.290 +			}
   1.291 +		}
   1.292 +	else if (iOpenDeviceRequestStatus)
   1.293 +		{
   1.294 +		//it must be a failed OpenDevice where the state has been wound back to EGAVDPOpen
   1.295 +		__ASSERT_DEBUG((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState));
   1.296 +		//the following ASSERT_DEBUG should be present but is commented out as the RVCT 
   1.297 +		//compiler generates a warning
   1.298 +		//__ASSERT_DEBUG((iOpenDeviceError), EA2dpBTHeadsetUnExpectedState);
   1.299 +		if (*iOpenDeviceRequestStatus == KRequestPending)
   1.300 +			{
   1.301 +			User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   1.302 +			}
   1.303 +		}
   1.304 +	SetSniffMode(ETrue);
   1.305 +	}
   1.306 +
   1.307 +/**
   1.308 +Callback by the GAVDP state machine when a GAVDP state change has been completed
   1.309 +
   1.310 +@param aInitialState The TGAVDPState prior to the start of the state change
   1.311 +@param aCurrentState The current TGAVDPState of the GAVDP state machine
   1.312 +@param aError standard Symbian error code.  
   1.313 +*/
   1.314 +void CA2dpBTHeadsetAudioInterface::GAVDPStateChangeComplete(const TGAVDPState& aInitialState, TInt aError)
   1.315 +	{	
   1.316 +	switch(aInitialState.State())
   1.317 +		{
   1.318 +		case TGAVDPState::EGAVDPIdle:
   1.319 +			ProcessGAVDPStateChangeIdleToOpen(aError);
   1.320 +			break;
   1.321 +		case TGAVDPState::EGAVDPOpen:
   1.322 +			ProcessGAVDPStateChangeOpenToStreaming(aError);
   1.323 +			break;
   1.324 +		case TGAVDPState::EGAVDPStreaming:
   1.325 +			ProcessGAVDPStateChangeStreamingToOpen(aError);	
   1.326 +			break;
   1.327 +		default:
   1.328 +			Panic(EA2dpBTHeadsetUnExpectedState);
   1.329 +			break;
   1.330 +		}
   1.331 +	}
   1.332 +
   1.333 +
   1.334 +/**
   1.335 +Returns a list of the supported datatypes for audio that can be sent to the headset.
   1.336 +The list is obtained from the headset, so the headset need to have been Initialized first
   1.337 +	
   1.338 +@param  aSupportedDataTypes
   1.339 +The array of supported data types that will be filled in by this function.
   1.340 +The supported data types are in the form of an array
   1.341 +of TFourCC codes. Any existing entries in the array will be overwritten on 
   1.342 +calling this function. 
   1.343 +@return standard Symbian error code.   
   1.344 +KErrNotReady if headset has not been initialized.
   1.345 +*/
   1.346 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedDataTypes(RArray<TFourCC>& aSupportedDataTypes) const
   1.347 +	{
   1.348 +	aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array
   1.349 +	TInt err = KErrNone;
   1.350 +	RArray<TUsableSEP>& usableSEPs = iGAVDPStateMachine->UsableSEPs();
   1.351 +	TUint numberOfUsableSEPS = usableSEPs.Count();
   1.352 +	if (numberOfUsableSEPS)
   1.353 +		{
   1.354 +		TUint i;
   1.355 +		TUsableSEP SEP;
   1.356 +		//iterate through the list of usable SEPs looking for one that supports
   1.357 +		//the requested data type
   1.358 +		for (i=0;  i<usableSEPs.Count(); i++)
   1.359 +			{
   1.360 +			SEP = usableSEPs[i];
   1.361 +			//both the headset and the A2dpBTHeadsetAudioInterface need to
   1.362 +			//support the datatype so check we also support the datatype
   1.363 +			//currently only SBC & MP3 data types are supported
   1.364 +			if ((SEP.iDataType == KMMFFourCCCodeSBC)||(SEP.iDataType == KMMFFourCCCodeMP3))
   1.365 +				{
   1.366 +				err = aSupportedDataTypes.Append(SEP.iDataType);
   1.367 +				}
   1.368 +			if (err)
   1.369 +				{
   1.370 +				break;
   1.371 +				}
   1.372 +			if (SEP.iDataType == KMMFFourCCCodeSBC)
   1.373 +				{//then we also support pcm16
   1.374 +				err = aSupportedDataTypes.Append(KMMFFourCCCodePCM16);
   1.375 +				if (err)
   1.376 +					{
   1.377 +					break;
   1.378 +					}
   1.379 +				}
   1.380 +			}
   1.381 +		}
   1.382 +	else if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   1.383 +		{//no usable SEPs available so can't yet get supported data types
   1.384 +		err = KErrNotReady;
   1.385 +		}
   1.386 +		
   1.387 +	if (err)
   1.388 +		{
   1.389 +		aSupportedDataTypes.Reset();
   1.390 +		}
   1.391 +	return err;
   1.392 +	}
   1.393 +	
   1.394 +
   1.395 +/**
   1.396 +Returns the sample rates supported by the headset.
   1.397 +In the case of SBC the supported values are obtained from the headset.
   1.398 +In the case of mp3,AAC & ATRAC 3 the values are not obtained from
   1.399 +the headset as the underlying bluetoothav code does not have a defined structure
   1.400 +for containing these values, therefore the mandatory values are returned
   1.401 +	
   1.402 +@param  aSupportedDiscreteRates
   1.403 +The array of supported sample rates that will be filled in by this function.
   1.404 +The supported data types are in the form of an array
   1.405 +of TFourCC codes. Any existing entries in the array will be overwritten on 
   1.406 +calling this function. 
   1.407 +@param aSupportedRateRanges
   1.408 +To cover the case where headsets support a range of sample rates
   1.409 +@return standard Symbian error code.   
   1.410 +KErrNotReady if headset has not been initialized.
   1.411 +*/	
   1.412 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates, RArray<TRange>& aSupportedRateRanges) const
   1.413 +	{
   1.414 +	TInt error = KErrNone;
   1.415 +	aSupportedDiscreteRates.Reset();
   1.416 +	aSupportedRateRanges.Reset();
   1.417 +	
   1.418 +	//get the codec capabilites from the GAVDP state machine
   1.419 +	TAvdtpMediaCodecCapabilities* codecCaps = NULL;
   1.420 +	error = iGAVDPStateMachine->CodecCaps(codecCaps);
   1.421 +
   1.422 +	if (!error)
   1.423 +		{
   1.424 +		error = TA2dpCodecCapabilityParser::GetSupportedSampleRates(*codecCaps,aSupportedDiscreteRates);
   1.425 +		}
   1.426 +	if (error)
   1.427 +		{
   1.428 +		aSupportedDiscreteRates.Reset();
   1.429 +		}
   1.430 +	
   1.431 +	return error;
   1.432 +	}
   1.433 +	
   1.434 +
   1.435 +/**
   1.436 +Returns the number of channels supported by the headset.
   1.437 +In the case of SBC the supported values are obtained from the headset.
   1.438 +In the case of mp3,AAC & ATRAC 3 the values are not obtained from
   1.439 +the headset as the underlying bluetoothav code does not have a defined structure
   1.440 +for containing these values, therefore the mandatory values are returned
   1.441 +	
   1.442 +@param  aSupportedChannels
   1.443 +The array of supported number of channels that will be filled in by this function.
   1.444 +Any existing entries in the array will be overwritten on 
   1.445 +calling this function. 
   1.446 +@param aStereoSupport
   1.447 +Additional parameter to specifiy the stereo support
   1.448 +@return standard Symbian error code.
   1.449 +@see TMMFStereoSupport
   1.450 +KErrNotReady if headset has not been initialized.
   1.451 +*/		
   1.452 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedChannels(RArray<TUint>& aSupportedChannels, TMMFStereoSupport& aStereoSupport) const
   1.453 +	{
   1.454 +	aSupportedChannels.Reset();
   1.455 +	aStereoSupport = EMMFNone;
   1.456 +	
   1.457 +	TInt error = KErrNone;
   1.458 +
   1.459 +	//get the codec capabilites from the GAVDP state machine
   1.460 +	TAvdtpMediaCodecCapabilities* codecCaps = NULL;
   1.461 +	error = iGAVDPStateMachine->CodecCaps(codecCaps);
   1.462 +	
   1.463 +	if (!error)
   1.464 +		{
   1.465 +		error = TA2dpCodecCapabilityParser::GetSupportedChannels(*codecCaps, aSupportedChannels, aStereoSupport);
   1.466 +		}
   1.467 +	if (error) 
   1.468 +		{
   1.469 +		aSupportedChannels.Reset();
   1.470 +		aStereoSupport = EMMFNone;
   1.471 +		}
   1.472 +	return error;
   1.473 +	}
   1.474 +	
   1.475 +
   1.476 +/**
   1.477 +Sets the data type of the data sent to the CA2dpBTHeadsetAudioInterface
   1.478 +Note that data type specified here may not be identical to the data type
   1.479 +sent to the headset and hence the data type used in the the a2dp codec configuration.  
   1.480 +ie if the CA2dpBTHeadsetAudioInterface data type set by this method is pcm16
   1.481 +then the data type sent to the headset is SBC.
   1.482 +note that this method just sets the internal iDatatype member
   1.483 +the datatype cannot be changed on the fly, but only gets changed
   1.484 +when the GAVDP state machine is reconfigured in CA2dpBTHeadsetAudioInterface::OpenDevice()
   1.485 +
   1.486 +@param  aSinkFourCC
   1.487 +        The 4CC code of the data to be supplied to this class instance.
   1.488 +        
   1.489 +@return System wide error code indicating if the function call was successful.
   1.490 +		KErrNotReady if the headset is not initialized
   1.491 +		KErrInUse if the headset is already streaming
   1.492 +		KErrNotSupported if the datatype is not supported
   1.493 +*/
   1.494 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetDataType(const TFourCC& aDataType)
   1.495 +	{
   1.496 +	TInt error = KErrNone;
   1.497 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   1.498 +		{
   1.499 +		return KErrNotReady;
   1.500 +		}
   1.501 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   1.502 +		{
   1.503 +		return KErrInUse; //don't allow this while we're streaming audio
   1.504 +		}
   1.505 +		
   1.506 +	//the requested data type is a non standard data type
   1.507 +	//so first check if there is a SEP that supports it
   1.508 +	RArray<TUsableSEP>& usableSEPs = iGAVDPStateMachine->UsableSEPs();
   1.509 +	TUint i;
   1.510 +	TUsableSEP SEP;
   1.511 +	TBool dataTypeSupported = EFalse;
   1.512 +	//iterate through the list of usable SEPs looking for one that supports
   1.513 +	//the requested data type
   1.514 +	for (i=0; i<usableSEPs.Count(); i++)
   1.515 +		{
   1.516 +		SEP = usableSEPs[i];
   1.517 +		if (SEP.iDataType == aDataType)
   1.518 +			{//one of the usable SEPs supports the requested data type
   1.519 +			dataTypeSupported = ETrue;
   1.520 +			iDataType = aDataType;
   1.521 +			if (aDataType != iA2dpCodecConfiguration->HeadsetCodecDataType())
   1.522 +				{
   1.523 +				iA2dpCodecConfiguration->SetHeadsetCodecDataType(aDataType);
   1.524 +				iAudioSettingsHaveChanged = ETrue;
   1.525 +				}
   1.526 +			break;
   1.527 +			}
   1.528 +		else if ((SEP.iDataType == KMMFFourCCCodeSBC) && (aDataType == KMMFFourCCCodePCM16))
   1.529 +			{
   1.530 +			dataTypeSupported = ETrue;
   1.531 +			iDataType = aDataType;
   1.532 +			if (iA2dpCodecConfiguration->HeadsetCodecDataType()!= KMMFFourCCCodeSBC)
   1.533 +				{
   1.534 +				iA2dpCodecConfiguration->SetHeadsetCodecDataType(KMMFFourCCCodeSBC);
   1.535 +				iAudioSettingsHaveChanged = ETrue;
   1.536 +				}
   1.537 +			break;
   1.538 +			}		
   1.539 +		}
   1.540 +	if (!dataTypeSupported)
   1.541 +		{
   1.542 +		error = KErrNotSupported;
   1.543 +		}		
   1.544 +	return error;
   1.545 +	}
   1.546 +	
   1.547 +
   1.548 +/**
   1.549 +Sets the sample rate 
   1.550 +
   1.551 +@param aSampleRate
   1.552 +@return System wide error code indicating if the function call was successful.
   1.553 +		KErrNotReady if the headset is not initialized
   1.554 +		KErrInUse if the headset is already streaming
   1.555 +		KErrNotSupported if the sample rate is not supported
   1.556 +*/	
   1.557 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetSampleRate(TUint aSampleRate)
   1.558 +	{
   1.559 +	TInt error = KErrNone;
   1.560 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   1.561 +		{
   1.562 +		return KErrNotReady;
   1.563 +		}
   1.564 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   1.565 +		{
   1.566 +		//don't allow this while we're streaming audio
   1.567 +		return KErrInUse; 
   1.568 +		}
   1.569 +	
   1.570 +	//check that the sample rate is supported
   1.571 +	RArray<TUint> supportedDiscreteRates;
   1.572 +	RArray<TRange> supportedRateRanges;
   1.573 +	GetSupportedSampleRates(supportedDiscreteRates, supportedRateRanges);
   1.574 +	if (supportedDiscreteRates.Find(aSampleRate) == KErrNotFound)
   1.575 +		{
   1.576 +		//in theory we should iterate through the ranges as well, however
   1.577 +		//SBC only suports discrete values so just return KErrNotSupported
   1.578 +		error = KErrNotSupported;
   1.579 +		}
   1.580 +	else
   1.581 +		{
   1.582 +		if (aSampleRate != iA2dpCodecConfiguration->SampleRate())
   1.583 +			{
   1.584 +			iA2dpCodecConfiguration->SetSampleRate(aSampleRate);
   1.585 +			iAudioSettingsHaveChanged = ETrue;
   1.586 +			}
   1.587 +		}
   1.588 +	supportedDiscreteRates.Close();
   1.589 +	supportedRateRanges.Close();
   1.590 +	return error;
   1.591 +	}
   1.592 +	
   1.593 +
   1.594 +/**
   1.595 +Sets the number of channels 
   1.596 +
   1.597 +@param aSampleChannels
   1.598 +@param aStereoSupport.  note that the aStereoSupport in the case of pcm16 refers to the output to the headset.
   1.599 +the data going for pcm16 is always either interleaved stereo pcm16 or mono
   1.600 +the aStereoSupport parameter is ignored for non stereo
   1.601 +@see TMMFStereoSupport
   1.602 +@return System wide error code indicating if the function call was successful.
   1.603 +		KErrNotReady if the headset is not initialized
   1.604 +		KErrInUse if the headset is already streaming
   1.605 +		KErrNotSupported if the datatype is not supported
   1.606 +*/	
   1.607 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport)
   1.608 +	{
   1.609 +	TInt error = KErrNone;
   1.610 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
   1.611 +		{
   1.612 +		return KErrNotReady;
   1.613 +		}
   1.614 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   1.615 +		{
   1.616 +		return KErrInUse; //don't allow this while we're streaming audio
   1.617 +		}
   1.618 +
   1.619 +	//check that the number of channels is supported
   1.620 +	RArray<TUint> supportedChannels;
   1.621 +	TMMFStereoSupport stereoSupport;
   1.622 +	GetSupportedChannels(supportedChannels, stereoSupport);
   1.623 +	if (supportedChannels.Find(aChannels) == KErrNotFound)
   1.624 +		{
   1.625 +		error = KErrNotSupported;
   1.626 +		}	
   1.627 +	else if (aChannels == EMMFStereo)
   1.628 +		{
   1.629 +		//now check stereo support
   1.630 +		if ((aStereoSupport & stereoSupport) != aStereoSupport)
   1.631 +			{
   1.632 +			error = KErrNotSupported;
   1.633 +			}
   1.634 +		else if (iA2dpCodecConfiguration->StereoSupport() != aStereoSupport)
   1.635 +			{
   1.636 +			iA2dpCodecConfiguration->SetStereoSupport(aStereoSupport);
   1.637 +			iAudioSettingsHaveChanged = ETrue;
   1.638 +			}
   1.639 +		}
   1.640 +	if (!error)
   1.641 +		{
   1.642 +		if (iA2dpCodecConfiguration->Channels() != aChannels)
   1.643 +			{
   1.644 +			iA2dpCodecConfiguration->SetChannels(aChannels);
   1.645 +			iAudioSettingsHaveChanged = ETrue;
   1.646 +			}
   1.647 +		}
   1.648 +	return error;
   1.649 +	}
   1.650 +
   1.651 +	
   1.652 +/**
   1.653 +Procedure to gets the headset into the GAVDP Streaming state where 
   1.654 +it is ready to accept audio data.  The procedure causes a reconfiguration
   1.655 +of the headset incase the settings have changed - and if they haven't then the 
   1.656 +reconfigure does nothing.
   1.657 +The GAVDPStateChangeComplete callback is called after the reconfigure
   1.658 +where it puts the GAVDP state machine in the streaming state
   1.659 +The GAVDPStateChangeComplete callback is called again when the headset device
   1.660 +is in the streaming state.
   1.661 +
   1.662 +@param aStatus
   1.663 +*/
   1.664 +EXPORT_C void CA2dpBTHeadsetAudioInterface::OpenDevice(TRequestStatus& aStatus)
   1.665 +	{
   1.666 +	iOpenDeviceRequestStatus = &aStatus;
   1.667 +	*iOpenDeviceRequestStatus = KRequestPending;
   1.668 +	
   1.669 +	if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
   1.670 +		{
   1.671 +		//device is already open
   1.672 +		User::RequestComplete(iOpenDeviceRequestStatus, KErrNone);
   1.673 +		return;
   1.674 +		}
   1.675 +	
   1.676 +	//this isn't a local error variable as it is used in the GAVDPStateChangeComplete callback
   1.677 +	iOpenDeviceError = KErrNone;
   1.678 +	//take out of sniff mode - no point in checking error code as there is
   1.679 +	//not much that can be done
   1.680 +	SetSniffMode(EFalse);
   1.681 +	
   1.682 +	//first reconfigure if the configuration has changed
   1.683 +	//note that there is a subtle difference between the configuration of the 
   1.684 +	//CA2dpBTHeadsetAudioInterface and that of the GAVDP state machine
   1.685 +	//the configuration of the CA2dpBTHeadsetAudioInterface is the configuration
   1.686 +	//seen from the DevSound whereas the CGAVDPStateMachine is the configuration
   1.687 +	//as seen by the headset.  In most cases they would be identical, the only
   1.688 +	//current case where the differ is in the data type where the DevSound sees
   1.689 +	//the data tpye as pcm16 but the headset is SBC
   1.690 +	iOpenDeviceError = iGAVDPStateMachine->Reconfigure(iAudioSettingsHaveChanged);
   1.691 +	if (iOpenDeviceError)
   1.692 +		{
   1.693 +		User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
   1.694 +		}
   1.695 +	else
   1.696 +		{
   1.697 +		//the Reconfigure will result in a GAVDPStateChangeComplete callback
   1.698 +		iReconfiguring = ETrue;
   1.699 +		}
   1.700 +	}
   1.701 +
   1.702 +
   1.703 +/**
   1.704 + Procedure to cancel a GAVDP initialization sequence on an A2DP headset
   1.705 +*/	
   1.706 +EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelOpenDevice()
   1.707 +	{
   1.708 +	if (iOpenDeviceRequestStatus)
   1.709 +		{
   1.710 +		if (*iOpenDeviceRequestStatus == KRequestPending)//make sure there is a pending request to cancel
   1.711 +			{
   1.712 +			iGAVDPStateMachine->CancelChangeState();
   1.713 +			}
   1.714 +		}
   1.715 +	}
   1.716 +
   1.717 +/**
   1.718 +Procedure to put a headset that is in the GAVDP Streaming state back into
   1.719 +the GAVDP Open state
   1.720 +The GAVDPStateChangeComplete callback is called again when the headset device
   1.721 +is in the open state.
   1.722 +
   1.723 +@param aStatus
   1.724 +*/	
   1.725 +EXPORT_C void CA2dpBTHeadsetAudioInterface::CloseDevice(TRequestStatus& aStatus)
   1.726 +	{
   1.727 +	iCloseDeviceRequestStatus = &aStatus;
   1.728 +	*iCloseDeviceRequestStatus = KRequestPending;
   1.729 +	
   1.730 +	if (iGAVDPStateMachine->State() != TGAVDPState::EGAVDPStreaming)
   1.731 +		{
   1.732 +		//device isn't open
   1.733 +		User::RequestComplete(iCloseDeviceRequestStatus, KErrNone);
   1.734 +		return;
   1.735 +		}
   1.736 +	else
   1.737 +		{
   1.738 +		if (iRTPStreamer)
   1.739 +			{
   1.740 +			iRTPStreamer->Pause();
   1.741 +			}
   1.742 +		//note the callback ProcessGAVDPStateChangeStreamingToOpen
   1.743 +		//will put the BT link back in sniff mode
   1.744 +		TGAVDPState state(TGAVDPState::EGAVDPOpen);
   1.745 +		TInt err = iGAVDPStateMachine->ChangeState(state);
   1.746 +		if (err)
   1.747 +			{
   1.748 +			User::RequestComplete(iCloseDeviceRequestStatus, err);
   1.749 +			}
   1.750 +		}
   1.751 +	}
   1.752 +
   1.753 +/**
   1.754 +Procedure to get the headset volume
   1.755 +
   1.756 +@return volume in the range 0-255
   1.757 +*/	
   1.758 +EXPORT_C TUint CA2dpBTHeadsetAudioInterface::Volume() const
   1.759 +	{
   1.760 +	return 0;
   1.761 +	}
   1.762 +	
   1.763 +
   1.764 +/**
   1.765 +Procedure to set the volume in the range 0-255
   1.766 +Note this procedure requires the AVRCP bluettooth profile
   1.767 +in order to change the volume which is not implemented
   1.768 +
   1.769 +@param aVolume the volume in the range 0-255
   1.770 +*/	
   1.771 +EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetVolume(TUint /*aVolume*/)
   1.772 +	{
   1.773 +	return KErrNone;
   1.774 +	}
   1.775 +	
   1.776 +
   1.777 +/**
   1.778 +This function causes the CA2dpBTHeadsetAudioInterface to send the audio data contained in aData to the initialized A2DP headset.
   1.779 +The data is buffered internally and CA2dpBTHeadsetAudioInterface may already be playing audio
   1.780 +when this method is called.
   1.781 +The TRequestStatus is completed when the CA2dpBTHeadsetAudioInterface  has finished with the audio data contained in aData.  
   1.782 +By 'finished' this does not mean finished as in physically finished playing the audio,
   1.783 +but to inform the client that:
   1.784 +a)	it can repopulate the buffer with new audio data.
   1.785 +b)	the  CA2dpBTHeadsetAudioInterface is ready to accept another buffer of audio data via a further call to PlayData()
   1.786 +(ie the CA2dpBTHeadsetAudioInterface is not expected to accept multiple buffers in succession prior to completing their
   1.787 +TRequestStatus as this would not provide the client with any indication of whether the
   1.788 +sound drivers internal buffers are full).
   1.789 +
   1.790 +@param aStatus  The TRequestStatus completed when the sound driver has finished with the audio data contained in aData.
   1.791 +The TRequestStatus is set to KErrNone unless the request has been cancelled via CancelPlayData()
   1.792 +in which case the status will be set to KErrCancel. 
   1.793 +The TRequestStatus is completed as soon as possible and before the audio has been physically played
   1.794 +in order for the client to send further audio buffers before the buffers already in the sound driver
   1.795 +are played out. 
   1.796 +Prior to calling PlayData() the client would be expected to Initialize Configure and Open the CA2dpBTHeadsetAudioInterface
   1.797 +and register with the sound driver that it requires notification of error conditions via a call to NotifyPlayError().
   1.798 +	
   1.799 +@param aData  Buffer containing the audio data to be played.  
   1.800 +aData, is not owned or created by the sound driver but is owned by the client.  
   1.801 +*/
   1.802 +EXPORT_C void CA2dpBTHeadsetAudioInterface::PlayData(const TDesC8& aData, TRequestStatus& aStatus)
   1.803 +	{
   1.804 +	__ASSERT_DEBUG((aData.Length()), Panic(EA2dpBTHeadsetNoData));
   1.805 +	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   1.806 +	
   1.807 +	iRTPStreamer->Send(aData, aStatus);
   1.808 +	}
   1.809 +	
   1.810 +/**
   1.811 +Cancels the current request for PlayData() if currently active.
   1.812 +The currently active PlayData() completes the request status immediately with KErrCancel.
   1.813 +*/	
   1.814 +EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelPlayData()
   1.815 +	{
   1.816 +	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   1.817 +		
   1.818 +	iRTPStreamer->CancelLastSendBuffer();
   1.819 +	}
   1.820 +	
   1.821 +
   1.822 +/**
   1.823 +Used to clear all internally buffered audio.  
   1.824 +This function does not complete any pending TRequestStatuses.  
   1.825 +*/	
   1.826 +EXPORT_C void CA2dpBTHeadsetAudioInterface::FlushBuffer()
   1.827 +	{
   1.828 +	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   1.829 +	
   1.830 +	iRTPStreamer->FlushPendingSendBuffers();
   1.831 +	}
   1.832 +
   1.833 +	
   1.834 +/**
   1.835 +Returns the total number of bytes of data sent in PlayData that have been
   1.836 +sent to the headset.  ie the number of bytes sent prior to any encoding by the SBC codec.
   1.837 +It is updated after each buffer has been sent to the headset. 
   1.838 +The BytesPlayed are not reset to 0 on an error condition.
   1.839 +It must be explicitly reset via a call to ResetBytesPlayed().
   1.840 +	
   1.841 +@param The number of bytes played
   1.842 +*/	
   1.843 +EXPORT_C TUint CA2dpBTHeadsetAudioInterface::BytesPlayed() const
   1.844 +	{
   1.845 +	TUint bytesPlayed = 0;
   1.846 +	if (iRTPStreamer)//don't ASSERT iRTPStreamer here as this API still has meaning with no streamer
   1.847 +		{
   1.848 +		bytesPlayed = iRTPStreamer->BytesSent();
   1.849 +		}
   1.850 +	return bytesPlayed;
   1.851 +	}
   1.852 +
   1.853 +
   1.854 +/**
   1.855 +Resets bytes played to 0.
   1.856 +*/	
   1.857 +EXPORT_C void CA2dpBTHeadsetAudioInterface::ResetBytesPlayed()
   1.858 +	{
   1.859 +	if (iRTPStreamer)//don't ASSERT iRTPStreamer here as this API still has meaning with no streamer
   1.860 +		{
   1.861 +		iRTPStreamer->ResetBytesSent();
   1.862 +		}
   1.863 +	}
   1.864 +	
   1.865 +
   1.866 +/**
   1.867 +Function to halt the sending of buffers to the headset.
   1.868 +Note that even if no buffers are being send via PlayData buffers
   1.869 +can still be sent to the headset as they are buffered internally
   1.870 +Calling PauseBuffer stops the internally buffered data being sent as well
   1.871 +as any buffers sent via PlayData
   1.872 +If the TRequestStatus from the previous PlayData() is outstanding then PausePlayBuffer()
   1.873 +does not complete the TRequestStatus.
   1.874 +The TRequestStatus will only be completed after ResumePlaying() is called.
   1.875 +*/	
   1.876 +EXPORT_C void CA2dpBTHeadsetAudioInterface::PauseBuffer()
   1.877 +	{
   1.878 +	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   1.879 +	
   1.880 +	iRTPStreamer->Pause();
   1.881 +	iPaused = ETrue;
   1.882 +	}
   1.883 +
   1.884 +	
   1.885 +/**
   1.886 +This resumes playing from where playing was halted from the previous call to PauseBuffer().
   1.887 +The next TRequestStatus (if active) to be completed, is the request status from the previous PlayData()
   1.888 +prior to calling PausePlayBuffer().
   1.889 +If PausePlayBuffer() has not been called prior to ResumePlaying(),
   1.890 +then this method does nothing.
   1.891 +*/	
   1.892 +EXPORT_C void CA2dpBTHeadsetAudioInterface::ResumePlaying()
   1.893 +	{
   1.894 +	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   1.895 +	
   1.896 +	iRTPStreamer->Resume();
   1.897 +	iPaused = EFalse;
   1.898 +	}
   1.899 +	
   1.900 +
   1.901 +/**
   1.902 +This function is used when the client is requesting notification of an error that occurs during playback.
   1.903 +The TRequestStatus passed in the NotifyPlayError() method is separate to the TRequestStatus passed into the PlayData() method,
   1.904 +and hence the client would typically have a separate active object for both the PlayData()
   1.905 +and NotifyPlayError() TRequestStatuses.
   1.906 +The NotifyPlayError() method is required because if an error occurs during playback,
   1.907 +the PlayData() TRequestStatus may not be active.
   1.908 +If a PlayData() request status is active then the error is reported back via the PlayData()
   1.909 +TRequestStatus and not via the NotifyPlayError() TRequestStatus.
   1.910 +If no PlayData() TRequestStatus is active then the error is reported back by completing the NotifyPlayError()
   1.911 +TRequestStatus with the appropriate error code.
   1.912 +Note that a call to CancelPlayData() should complete the PlayData() request status with KErrCancel
   1.913 +and should not complete the NotifyPlayError() TRequestStatus.
   1.914 +
   1.915 +@param aStatus TRequestStatus completed when a play error occurs.
   1.916 +*/	
   1.917 +EXPORT_C void CA2dpBTHeadsetAudioInterface::NotifyError(TRequestStatus& aStatus)
   1.918 +	{
   1.919 +	iNotifyRequestStatus= &aStatus;
   1.920 +	*iNotifyRequestStatus = KRequestPending;
   1.921 +	}
   1.922 +	
   1.923 +
   1.924 +/**
   1.925 +Cancels the NotifyPlayError() TRequestStatus if currently active.
   1.926 +The TRequestStatus completes immediately with KErrCancel.
   1.927 +*/	
   1.928 +EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelNotifyError()
   1.929 +	{
   1.930 +	User::RequestComplete(iNotifyRequestStatus, KErrCancel);
   1.931 +	}
   1.932 +
   1.933 +
   1.934 +/**
   1.935 +Callback from the RTPStreamer when an unexpected event occurs
   1.936 +
   1.937 +@param aError
   1.938 +*/
   1.939 +void CA2dpBTHeadsetAudioInterface::RTPStreamerEvent(TInt aError)
   1.940 +	{
   1.941 +	//an error has occured while streaming
   1.942 +	__ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
   1.943 +	//could also be EGAVDPIdle as we could have just received a GAVDPStateMachineEvent
   1.944 +	//which would reset the state to EGAVDPIdle
   1.945 +	__ASSERT_DEBUG((iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming) ||
   1.946 +	(iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle), Panic(EA2dpBTHeadsetUnExpectedState));
   1.947 +	TGAVDPState state(TGAVDPState::EGAVDPIdle);
   1.948 +	TInt err = iGAVDPStateMachine->ChangeState(state);
   1.949 +	//the above returns an error code but there's not much we can do if it returns an error
   1.950 +
   1.951 +	if (iNotifyRequestStatus)
   1.952 +		{
   1.953 +		if (*iNotifyRequestStatus == KRequestPending)
   1.954 +			{
   1.955 +			User::RequestComplete(iNotifyRequestStatus, aError);
   1.956 +			}
   1.957 +		}
   1.958 +	}
   1.959 +
   1.960 +
   1.961 +/**
   1.962 +Callback from the GAVDPStateMachine when an error event occurs
   1.963 +
   1.964 +@param aError
   1.965 +*/	
   1.966 +void  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineEvent(TInt aError)
   1.967 +	{
   1.968 +	//an error has occured - if an error occurs then it could be
   1.969 +	//because we've lost the connection to the headset eg because it is out of range
   1.970 +	//has been switched off etc there we assume that the connection has been
   1.971 +	//lost and put the GAVDP state back to idle
   1.972 +	//note we're simplifying things somewhat as some errors may not be a result 
   1.973 +	//of a loss of connection to the headset
   1.974 +	TGAVDPState state(TGAVDPState::EGAVDPIdle);
   1.975 +	TInt err = iGAVDPStateMachine->ChangeState(state);
   1.976 +	if (!iRTPStreamer)
   1.977 +		{//if we don't have an RTP streamer
   1.978 +		//then close the bearer socket.  If we do have an RTP streamer
   1.979 +		//then delay the close till after we have deleted the RTPStreamer in the
   1.980 +		//the GAVDPStateChangeComplete callback.  this is because
   1.981 +		//closing the bearer socket before the RTP streamer is deleted
   1.982 +		//can panic the RTP stack.
   1.983 +		iGAVDPStateMachine->BearerSocket().Close();
   1.984 +		}	
   1.985 +	if (iNotifyRequestStatus)
   1.986 +		{
   1.987 +		if (*iNotifyRequestStatus == KRequestPending)
   1.988 +			{
   1.989 +			User::RequestComplete(iNotifyRequestStatus, aError);
   1.990 +			}
   1.991 +		}
   1.992 +	}
   1.993 +
   1.994 +	
   1.995 +/**
   1.996 +Callback from the GAVDPStateMachine when the headset has suspended the stream
   1.997 +*/
   1.998 +void  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineStreamSuspendedByRemoteHeadset()
   1.999 +	{
  1.1000 +	if (iRTPStreamer)
  1.1001 +		{
  1.1002 +		iRTPStreamer->Pause();
  1.1003 +		}
  1.1004 +	}
  1.1005 +
  1.1006 +
  1.1007 +/**
  1.1008 +Callback from the GAVDPStateMachine when the headset has resumed a suspended stream
  1.1009 +*/	
  1.1010 +void  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineStreamResumedByRemoteHeadset()
  1.1011 +	{
  1.1012 +	if ((!iPaused)&&(iRTPStreamer))
  1.1013 +		{
  1.1014 +		iRTPStreamer->Resume();
  1.1015 +		}
  1.1016 +	}
  1.1017 +
  1.1018 +
  1.1019 +/**
  1.1020 +Callback from the GAVDPStateMachine when the headset has reconfigured the parameters
  1.1021 +reconfigures codec with new configuration and inform RTP streamer
  1.1022 +
  1.1023 +@return SymbianOS error code
  1.1024 +*/
  1.1025 +TInt  CA2dpBTHeadsetAudioInterface::GAVDPStateMachineReconfigureByRemoteHeadset()
  1.1026 +	{
  1.1027 +	//we're only allowing the headset to reconfigure for SBC SEP
  1.1028 +	__ASSERT_DEBUG(iA2dpCodecConfiguration->HeadsetCodecDataType() == KMMFFourCCCodeSBC, Panic(	EA2dpBTHeadsetUnexpectedDataType));
  1.1029 +	__ASSERT_DEBUG(iCodec,Panic(EA2dpBTHeadsetNoCodec));
  1.1030 +	TUid configType;
  1.1031 +	TInt err = KErrNone;
  1.1032 +	configType.iUid = KMmfUidSBCConfigure;
  1.1033 +	TSBCFrameParameters& SBCFrameParameters = iA2dpCodecConfiguration->UpdateLocalSBCCodecConfiguration();
  1.1034 +	TPckgBuf<TSBCFrameParameters> SBCFrameParametersBuf(SBCFrameParameters);
  1.1035 +	TRAP(err,iCodec->ConfigureL(configType, SBCFrameParametersBuf)); //update codec with new configuration
  1.1036 +	iRTPStreamer->SetAudioConfiguration(*iA2dpCodecConfiguration); //and tell RTP streamer	
  1.1037 +	return err;
  1.1038 +	}
  1.1039 +
  1.1040 +
  1.1041 +/**
  1.1042 +Function to set/release the BT link into low power sniff mode
  1.1043 +
  1.1044 +@internalComponent
  1.1045 +@return Error code, this is used for debugging, it's not checked
  1.1046 +by the calling code as if SetSniffMode fails there's not much that can be
  1.1047 +done in the calling code
  1.1048 +*/
  1.1049 +TInt CA2dpBTHeadsetAudioInterface::SetSniffMode(TBool aSniffMode)
  1.1050 +	{
  1.1051 +	TInt err = KErrNone;
  1.1052 +	
  1.1053 +	if (!iGAVDPStateMachine)
  1.1054 +		{
  1.1055 +		return KErrNotReady;
  1.1056 +		}
  1.1057 +		
  1.1058 +	if (iGAVDPStateMachine->BTAddress() == TBTDevAddr(0))
  1.1059 +		{
  1.1060 +		return KErrNotReady;
  1.1061 +		}
  1.1062 +
  1.1063 +	err = iBTPhysicalLinkAdapter.Open(iSocketServer, iGAVDPStateMachine->BTAddress());
  1.1064 +	if (!err)
  1.1065 +		{
  1.1066 +		if (aSniffMode)
  1.1067 +			{
  1.1068 +			err = iBTPhysicalLinkAdapter.AllowLowPowerModes(ESniffMode);
  1.1069 +			err = iBTPhysicalLinkAdapter.ActivateSniffRequester();
  1.1070 +			}
  1.1071 +		else
  1.1072 +			{
  1.1073 +			err = iBTPhysicalLinkAdapter.CancelLowPowerModeRequester();
  1.1074 +			}
  1.1075 +		iBTPhysicalLinkAdapter.Close();
  1.1076 +		}
  1.1077 +
  1.1078 +	return err;
  1.1079 +	}
  1.1080 +	
  1.1081 +
  1.1082 +/**
  1.1083 +This function should only used by the TSU_MMF_A2DPBLUETOOTH unit test harness
  1.1084 +It allows the test harness to get at the MGavdpUser in order
  1.1085 +to emulate actions from the headset
  1.1086 +
  1.1087 +@return the GavdpState machine as a MGavdpUser mixin
  1.1088 +*/	
  1.1089 +EXPORT_C MGavdpUser* CA2dpBTHeadsetAudioInterface::TEST_MGavdpUser()
  1.1090 +	{
  1.1091 +	return static_cast<MGavdpUser*>(iGAVDPStateMachine);
  1.1092 +	}
  1.1093 +	
  1.1094 +
  1.1095 +/**
  1.1096 +This function should only used by the TSU_MMF_A2DPBLUETOOTH unit test harness
  1.1097 +It allows the test harness to override the configuration of the remote headset
  1.1098 +for the SBC codec with regard to sampling frequencies, block size; subbands and allocation method
  1.1099 +
  1.1100 +@param
  1.1101 +*/
  1.1102 +EXPORT_C void CA2dpBTHeadsetAudioInterface::TEST_ForceRemoteSBCCodecConfiguration(const TSBCCodecCapabilities& aRemoteCodecConfiguration)
  1.1103 +	{
  1.1104 +	iA2dpCodecConfiguration->TEST_ForceRemoteSBCCodecConfiguration(aRemoteCodecConfiguration);
  1.1105 +	}