os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/A2dpBTheadsetAudioIf.cpp
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 + }