os/mm/devsound/sounddevbt/src/A2dpBlueTooth/headsetaudioif/A2dpBTheadsetAudioIf.cpp
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
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
26 enum TA2dpBTHeadsetPanic
28 EA2dpBTHeadsetUnExpectedState,//0
29 EA2dpBTHeadsetNoRTPStreamer,//1
30 EA2dpBTHeadsetNoData,//2
31 EA2dpBTHeadsetUnexpectedDataType,//3
32 EA2dpBTHeadsetBTAddrNotSet, //4
33 EA2dpBTHeadsetNoCodec //5
37 static void Panic(TA2dpBTHeadsetPanic aPanic)
40 _LIT(KA2dpBTHeadsetPanicName, "A2DP BT If Panic");
41 User::Panic(KA2dpBTHeadsetPanicName, aPanic);
45 CA2dpBTHeadsetAudioInterface::CA2dpBTHeadsetAudioInterface()
49 void CA2dpBTHeadsetAudioInterface::ConstructL()
51 iA2dpCodecConfiguration = CA2dpAudioCodecConfiguration::NewL();
52 User::LeaveIfError(iSocketServer.Connect());
53 iGAVDPStateMachine = CGAVDPStateMachine::NewL(*this, *iA2dpCodecConfiguration, iSocketServer);
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.
62 @return CA2dpBTHeadsetAudioInterface*
64 EXPORT_C CA2dpBTHeadsetAudioInterface* CA2dpBTHeadsetAudioInterface::NewL()
66 CA2dpBTHeadsetAudioInterface* self = new(ELeave) CA2dpBTHeadsetAudioInterface();
67 CleanupStack::PushL(self);
69 CleanupStack::Pop(self);
76 EXPORT_C CA2dpBTHeadsetAudioInterface::~CA2dpBTHeadsetAudioInterface()
79 delete iGAVDPStateMachine;
81 delete iA2dpCodecConfiguration;
83 iSocketServer.Close();
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
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.
100 @param aRemoteAddress Address of the bluetooth headset we are trying to initialize
103 EXPORT_C void CA2dpBTHeadsetAudioInterface::Initialize(const TBTDevAddr& aRemoteAddress, TRequestStatus& aStatus)
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;
111 //this will cause a full initialization if the address has changed
112 iGAVDPStateMachine->SetBTAddress(aRemoteAddress);
114 TGAVDPState state(TGAVDPState::EGAVDPOpen);
115 TInt err = iGAVDPStateMachine->ChangeState(state);
118 User::RequestComplete(iInitializeRequestStatus, err);
124 Procedure to cancel a GAVDP initialization sequence on an A2DP headset
126 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelInitialize()
128 if (iInitializeRequestStatus)
130 if (*iInitializeRequestStatus == KRequestPending)//make sure there is a pending request to cancel
132 iGAVDPStateMachine->CancelChangeState();
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
143 void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeIdleToOpen(TInt aError)
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
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
157 iGAVDPStateMachine->BearerSocket().Close();
161 if (iInitializeRequestStatus)
163 if (*iInitializeRequestStatus == KRequestPending)
165 User::RequestComplete(iInitializeRequestStatus, aError);
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
178 void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeOpenToStreaming(TInt aError)
180 if (iOpenDeviceRequestStatus)
182 iOpenDeviceError = aError;
183 if (*iOpenDeviceRequestStatus == KRequestPending)
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)
191 //move GAVDP state to streaming
192 TGAVDPState state(TGAVDPState::EGAVDPStreaming);
193 iOpenDeviceError = iGAVDPStateMachine->ChangeState(state);
195 if (iOpenDeviceError)
197 SetSniffMode(ETrue); //go back to sniff mode
198 User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
200 }//if (iReconfiguring)
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)
206 __ASSERT_DEBUG((iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming),Panic(EA2dpBTHeadsetUnExpectedState));
209 TRAP(iOpenDeviceError,iRTPStreamer = CActiveRTPStreamer::NewL(iGAVDPStateMachine->BearerSocket(),*this));
210 if (!iOpenDeviceError)
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)
218 iDataType = iA2dpCodecConfiguration->HeadsetCodecDataType();
219 if (iDataType == KMMFFourCCCodeSBC)
220 {//then the audio interfacef code will be pcm16
221 iDataType = KMMFFourCCCodePCM16;
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)
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);
240 }//if (!iOpenDeviceError)
241 }//if (!iOpenDeviceError)
242 if ((iOpenDeviceError) && (iGAVDPStateMachine->State()==TGAVDPState::EGAVDPStreaming))
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
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)
260 }//else if not (iReconfiguring)
261 }// if (*iOpenRequestStatus == KRequestPending)
262 }//if (iOpenRequestStatus)
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
272 void CA2dpBTHeadsetAudioInterface::ProcessGAVDPStateChangeStreamingToOpen(TInt aError)
274 __ASSERT_DEBUG((aError||iGAVDPStateMachine->State()==TGAVDPState::EGAVDPOpen),Panic(EA2dpBTHeadsetUnExpectedState)); //if there is no error then current state should be open
276 //only have streamer and codec in streaming state
282 if (iCloseDeviceRequestStatus)
283 {//state change is in response to a close device
284 if (*iCloseDeviceRequestStatus == KRequestPending)
286 User::RequestComplete(iCloseDeviceRequestStatus, aError);
289 else if (iOpenDeviceRequestStatus)
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)
298 User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
305 Callback by the GAVDP state machine when a GAVDP state change has been completed
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.
311 void CA2dpBTHeadsetAudioInterface::GAVDPStateChangeComplete(const TGAVDPState& aInitialState, TInt aError)
313 switch(aInitialState.State())
315 case TGAVDPState::EGAVDPIdle:
316 ProcessGAVDPStateChangeIdleToOpen(aError);
318 case TGAVDPState::EGAVDPOpen:
319 ProcessGAVDPStateChangeOpenToStreaming(aError);
321 case TGAVDPState::EGAVDPStreaming:
322 ProcessGAVDPStateChangeStreamingToOpen(aError);
325 Panic(EA2dpBTHeadsetUnExpectedState);
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
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.
343 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedDataTypes(RArray<TFourCC>& aSupportedDataTypes) const
345 aSupportedDataTypes.Reset(); //clear any existing data in aSupportedDataTypes array
347 RArray<TUsableSEP>& usableSEPs = iGAVDPStateMachine->UsableSEPs();
348 TUint numberOfUsableSEPS = usableSEPs.Count();
349 if (numberOfUsableSEPS)
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++)
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))
363 err = aSupportedDataTypes.Append(SEP.iDataType);
369 if (SEP.iDataType == KMMFFourCCCodeSBC)
370 {//then we also support pcm16
371 err = aSupportedDataTypes.Append(KMMFFourCCCodePCM16);
379 else if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
380 {//no usable SEPs available so can't yet get supported data types
386 aSupportedDataTypes.Reset();
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
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.
409 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates, RArray<TRange>& aSupportedRateRanges) const
411 TInt error = KErrNone;
412 aSupportedDiscreteRates.Reset();
413 aSupportedRateRanges.Reset();
415 //get the codec capabilites from the GAVDP state machine
416 TAvdtpMediaCodecCapabilities* codecCaps = NULL;
417 error = iGAVDPStateMachine->CodecCaps(codecCaps);
421 error = TA2dpCodecCapabilityParser::GetSupportedSampleRates(*codecCaps,aSupportedDiscreteRates);
425 aSupportedDiscreteRates.Reset();
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
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.
449 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::GetSupportedChannels(RArray<TUint>& aSupportedChannels, TMMFStereoSupport& aStereoSupport) const
451 aSupportedChannels.Reset();
452 aStereoSupport = EMMFNone;
454 TInt error = KErrNone;
456 //get the codec capabilites from the GAVDP state machine
457 TAvdtpMediaCodecCapabilities* codecCaps = NULL;
458 error = iGAVDPStateMachine->CodecCaps(codecCaps);
462 error = TA2dpCodecCapabilityParser::GetSupportedChannels(*codecCaps, aSupportedChannels, aStereoSupport);
466 aSupportedChannels.Reset();
467 aStereoSupport = EMMFNone;
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()
484 The 4CC code of the data to be supplied to this class instance.
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
491 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetDataType(const TFourCC& aDataType)
493 TInt error = KErrNone;
494 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
498 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
500 return KErrInUse; //don't allow this while we're streaming audio
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();
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++)
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())
520 iA2dpCodecConfiguration->SetHeadsetCodecDataType(aDataType);
521 iAudioSettingsHaveChanged = ETrue;
525 else if ((SEP.iDataType == KMMFFourCCCodeSBC) && (aDataType == KMMFFourCCCodePCM16))
527 dataTypeSupported = ETrue;
528 iDataType = aDataType;
529 if (iA2dpCodecConfiguration->HeadsetCodecDataType()!= KMMFFourCCCodeSBC)
531 iA2dpCodecConfiguration->SetHeadsetCodecDataType(KMMFFourCCCodeSBC);
532 iAudioSettingsHaveChanged = ETrue;
537 if (!dataTypeSupported)
539 error = KErrNotSupported;
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
554 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetSampleRate(TUint aSampleRate)
556 TInt error = KErrNone;
557 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
561 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
563 //don't allow this while we're streaming audio
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)
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;
579 if (aSampleRate != iA2dpCodecConfiguration->SampleRate())
581 iA2dpCodecConfiguration->SetSampleRate(aSampleRate);
582 iAudioSettingsHaveChanged = ETrue;
585 supportedDiscreteRates.Close();
586 supportedRateRanges.Close();
592 Sets the number of channels
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
604 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport)
606 TInt error = KErrNone;
607 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPIdle)
611 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
613 return KErrInUse; //don't allow this while we're streaming audio
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)
622 error = KErrNotSupported;
624 else if (aChannels == EMMFStereo)
626 //now check stereo support
627 if ((aStereoSupport & stereoSupport) != aStereoSupport)
629 error = KErrNotSupported;
631 else if (iA2dpCodecConfiguration->StereoSupport() != aStereoSupport)
633 iA2dpCodecConfiguration->SetStereoSupport(aStereoSupport);
634 iAudioSettingsHaveChanged = ETrue;
639 if (iA2dpCodecConfiguration->Channels() != aChannels)
641 iA2dpCodecConfiguration->SetChannels(aChannels);
642 iAudioSettingsHaveChanged = ETrue;
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.
661 EXPORT_C void CA2dpBTHeadsetAudioInterface::OpenDevice(TRequestStatus& aStatus)
663 iOpenDeviceRequestStatus = &aStatus;
664 *iOpenDeviceRequestStatus = KRequestPending;
666 if (iGAVDPStateMachine->State() == TGAVDPState::EGAVDPStreaming)
668 //device is already open
669 User::RequestComplete(iOpenDeviceRequestStatus, KErrNone);
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);
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)
690 User::RequestComplete(iOpenDeviceRequestStatus, iOpenDeviceError);
694 //the Reconfigure will result in a GAVDPStateChangeComplete callback
695 iReconfiguring = ETrue;
701 Procedure to cancel a GAVDP initialization sequence on an A2DP headset
703 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelOpenDevice()
705 if (iOpenDeviceRequestStatus)
707 if (*iOpenDeviceRequestStatus == KRequestPending)//make sure there is a pending request to cancel
709 iGAVDPStateMachine->CancelChangeState();
715 Procedure to put a headset that is in the GAVDP Streaming state back into
717 The GAVDPStateChangeComplete callback is called again when the headset device
718 is in the open state.
722 EXPORT_C void CA2dpBTHeadsetAudioInterface::CloseDevice(TRequestStatus& aStatus)
724 iCloseDeviceRequestStatus = &aStatus;
725 *iCloseDeviceRequestStatus = KRequestPending;
727 if (iGAVDPStateMachine->State() != TGAVDPState::EGAVDPStreaming)
730 User::RequestComplete(iCloseDeviceRequestStatus, KErrNone);
737 iRTPStreamer->Pause();
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);
745 User::RequestComplete(iCloseDeviceRequestStatus, err);
751 Procedure to get the headset volume
753 @return volume in the range 0-255
755 EXPORT_C TUint CA2dpBTHeadsetAudioInterface::Volume() const
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
766 @param aVolume the volume in the range 0-255
768 EXPORT_C TInt CA2dpBTHeadsetAudioInterface::SetVolume(TUint /*aVolume*/)
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).
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
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().
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.
799 EXPORT_C void CA2dpBTHeadsetAudioInterface::PlayData(const TDesC8& aData, TRequestStatus& aStatus)
801 __ASSERT_DEBUG((aData.Length()), Panic(EA2dpBTHeadsetNoData));
802 __ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
804 iRTPStreamer->Send(aData, aStatus);
808 Cancels the current request for PlayData() if currently active.
809 The currently active PlayData() completes the request status immediately with KErrCancel.
811 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelPlayData()
813 __ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
815 iRTPStreamer->CancelLastSendBuffer();
820 Used to clear all internally buffered audio.
821 This function does not complete any pending TRequestStatuses.
823 EXPORT_C void CA2dpBTHeadsetAudioInterface::FlushBuffer()
825 __ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
827 iRTPStreamer->FlushPendingSendBuffers();
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().
838 @param The number of bytes played
840 EXPORT_C TUint CA2dpBTHeadsetAudioInterface::BytesPlayed() const
842 TUint bytesPlayed = 0;
843 if (iRTPStreamer)//don't ASSERT iRTPStreamer here as this API still has meaning with no streamer
845 bytesPlayed = iRTPStreamer->BytesSent();
852 Resets bytes played to 0.
854 EXPORT_C void CA2dpBTHeadsetAudioInterface::ResetBytesPlayed()
856 if (iRTPStreamer)//don't ASSERT iRTPStreamer here as this API still has meaning with no streamer
858 iRTPStreamer->ResetBytesSent();
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.
873 EXPORT_C void CA2dpBTHeadsetAudioInterface::PauseBuffer()
875 __ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
877 iRTPStreamer->Pause();
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.
889 EXPORT_C void CA2dpBTHeadsetAudioInterface::ResumePlaying()
891 __ASSERT_DEBUG((iRTPStreamer), Panic(EA2dpBTHeadsetNoRTPStreamer));
893 iRTPStreamer->Resume();
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.
912 @param aStatus TRequestStatus completed when a play error occurs.
914 EXPORT_C void CA2dpBTHeadsetAudioInterface::NotifyError(TRequestStatus& aStatus)
916 iNotifyRequestStatus= &aStatus;
917 *iNotifyRequestStatus = KRequestPending;
922 Cancels the NotifyPlayError() TRequestStatus if currently active.
923 The TRequestStatus completes immediately with KErrCancel.
925 EXPORT_C void CA2dpBTHeadsetAudioInterface::CancelNotifyError()
927 User::RequestComplete(iNotifyRequestStatus, KErrCancel);
932 Callback from the RTPStreamer when an unexpected event occurs
936 void CA2dpBTHeadsetAudioInterface::RTPStreamerEvent(TInt aError)
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
948 if (iNotifyRequestStatus)
950 if (*iNotifyRequestStatus == KRequestPending)
952 User::RequestComplete(iNotifyRequestStatus, aError);
959 Callback from the GAVDPStateMachine when an error event occurs
963 void CA2dpBTHeadsetAudioInterface::GAVDPStateMachineEvent(TInt aError)
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);
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();
982 if (iNotifyRequestStatus)
984 if (*iNotifyRequestStatus == KRequestPending)
986 User::RequestComplete(iNotifyRequestStatus, aError);
993 Callback from the GAVDPStateMachine when the headset has suspended the stream
995 void CA2dpBTHeadsetAudioInterface::GAVDPStateMachineStreamSuspendedByRemoteHeadset()
999 iRTPStreamer->Pause();
1005 Callback from the GAVDPStateMachine when the headset has resumed a suspended stream
1007 void CA2dpBTHeadsetAudioInterface::GAVDPStateMachineStreamResumedByRemoteHeadset()
1009 if ((!iPaused)&&(iRTPStreamer))
1011 iRTPStreamer->Resume();
1017 Callback from the GAVDPStateMachine when the headset has reconfigured the parameters
1018 reconfigures codec with new configuration and inform RTP streamer
1020 @return SymbianOS error code
1022 TInt CA2dpBTHeadsetAudioInterface::GAVDPStateMachineReconfigureByRemoteHeadset()
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));
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
1039 Function to set/release the BT link into low power sniff mode
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
1046 TInt CA2dpBTHeadsetAudioInterface::SetSniffMode(TBool aSniffMode)
1048 TInt err = KErrNone;
1050 if (!iGAVDPStateMachine)
1052 return KErrNotReady;
1055 if (iGAVDPStateMachine->BTAddress() == TBTDevAddr(0))
1057 return KErrNotReady;
1060 err = iBTPhysicalLinkAdapter.Open(iSocketServer, iGAVDPStateMachine->BTAddress());
1065 err = iBTPhysicalLinkAdapter.AllowLowPowerModes(ESniffMode);
1066 err = iBTPhysicalLinkAdapter.ActivateSniffRequester();
1070 err = iBTPhysicalLinkAdapter.CancelLowPowerModeRequester();
1072 iBTPhysicalLinkAdapter.Close();
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
1084 @return the GavdpState machine as a MGavdpUser mixin
1086 EXPORT_C MGavdpUser* CA2dpBTHeadsetAudioInterface::TEST_MGavdpUser()
1088 return static_cast<MGavdpUser*>(iGAVDPStateMachine);
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
1099 EXPORT_C void CA2dpBTHeadsetAudioInterface::TEST_ForceRemoteSBCCodecConfiguration(const TSBCCodecCapabilities& aRemoteCodecConfiguration)
1101 iA2dpCodecConfiguration->TEST_ForceRemoteSBCCodecConfiguration(aRemoteCodecConfiguration);