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 "A2dpCodecUtilities.h"
17 #include "GavdpStateMachine.h"
21 GAVDP State Machine Panics
23 enum TGavdpStateMachinePanic
25 EGavdpStateMachineBadState,//0
26 EGavdpStateMachineBadConfigByRemoteHeadsetState,//1
27 EGavdpStateMachineBadBTAddr,//2
28 EGavdpStateMachineUnexpectedCallback,//3
29 EGavdpStateMachineDataTypeMismatch//4
33 static void Panic(TGavdpStateMachinePanic aPanic)
36 _LIT(KGavdpStateMachinePanicName, "GAVDP State Mchn");
37 User::Panic(KGavdpStateMachinePanicName, aPanic);
42 Utility function to map a bluetooth code to a standard SymbianOS code
43 Where a standard Symbian error code exists the error is mapped
44 to the standard code. Ideally all HCI, L2CAP, AVDTP, GAVDP errors
45 should be mapped to standard SymbianOS codes since bluetooth specific
46 error codes aren't meaningful in the multimedia domain
48 static TInt ConvertToStandardSymbianOSError(TInt aError)
54 case KHCIErrorBase-EPageTimedOut://-6004
55 error = KErrCouldNotConnect;
57 case KHCIErrorBase-EAuthenticationFailure://-6005
58 error = KErrCouldNotConnect;
60 case KHCIErrorBase-EPairingNotAllowed: //-6024
61 error = KErrCouldNotConnect;
63 case KHCIErrorBase-ELMPResponseTimeout: //-6034
66 case KErrHCIConnectFailed: //-6304
67 error = KErrCouldNotConnect;
69 case KErrHCILinkDisconnection: //-6305
70 error = KErrDisconnected;
81 Creates CGAVDPStateMachine
84 @return CGAVDPStateMachine*
86 CGAVDPStateMachine* CGAVDPStateMachine::NewL(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer)
88 CGAVDPStateMachine* self = new(ELeave) CGAVDPStateMachine(aGAVDPStateChangeObserver, aA2dpCodecSettings, aSocketServer);
89 CleanupStack::PushL(self);
91 CleanupStack::Pop(self);
98 [TODO] change default stereo mode to EMMFJoint when hardware has sufficient bandwidth
99 Note we make the AO priority one less than normal to give the AOs in GAVDP
102 CGAVDPStateMachine::CGAVDPStateMachine(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer) : CActive(EPriorityNormal-1),
103 iGAVDPStateChangeObserver(aGAVDPStateChangeObserver) ,iA2dpCodecSettings(aA2dpCodecSettings), iSocketServer(aSocketServer)
105 CActiveScheduler::Add(this);
109 void CGAVDPStateMachine::ConstructL()
111 User::LeaveIfError(iGavdp.Open(*this, iSocketServer));
112 User::LeaveIfError(RegisterLocalSEP());
113 iSignallingTransactionTimeout = CGavdpTimeout::NewL(*this);
118 Internal function to register local SEPs with GAVDP
119 The function sets the iSymbianDeviceSEID to the TSEID
120 of the Symbian device
122 TInt CGAVDPStateMachine::RegisterLocalSEP()
124 //register SEPs - currently SBC & mp3 SEPs are supported
125 TAvdtpSEPInfo avdtpSEPInfo;
126 avdtpSEPInfo.SetInUse(EFalse);
127 avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio);
128 avdtpSEPInfo.SetIsSink(EFalse);
129 TInt err = iGavdp.RegisterSEP(avdtpSEPInfo);
131 sep.iSEID = avdtpSEPInfo.SEID();
132 sep.iDataType = KMMFFourCCCodeSBC;
133 err = iSymbianDeviceSEPs.Append(sep);
137 avdtpSEPInfo.SetInUse(EFalse);
138 avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio);
139 avdtpSEPInfo.SetIsSink(EFalse);
140 err = iGavdp.RegisterSEP(avdtpSEPInfo);
143 sep.iSEID = avdtpSEPInfo.SEID();
144 sep.iDataType = KMMFFourCCCodeMP3;
145 err = iSymbianDeviceSEPs.Append(sep);
150 TBool SEPDataTypeFound(EFalse);
151 for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
153 if (iSymbianDeviceSEPs[i].iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
155 iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID;
156 SEPDataTypeFound = ETrue;
160 if (!SEPDataTypeFound)
172 CGAVDPStateMachine::~CGAVDPStateMachine()
175 iBearerSocket.Close();
177 iPotentialSEPs.Close();
179 iSymbianDeviceSEPs.Close();
180 iSEPCapabilities.ResetAndDestroy();
181 iSEPCapabilities.Close();
182 delete iSignallingTransactionTimeout;
187 Function to set the Bluetooth address of the headset.
189 @param aRemoteAddress Bluetooth address of the headset
191 void CGAVDPStateMachine::SetBTAddress(const TBTDevAddr& aRemoteAddress)
193 if (iBTDevAddr != aRemoteAddress)
194 {//must be using a new headet so reset state machine
196 iBTDevAddr = aRemoteAddress;
202 Function to returns the current state of the GAVDP state machine.
204 @return the current state of the GAVDP state machine
206 TGAVDPState CGAVDPStateMachine::State() const
208 return iCurrentState ;
213 Internal function to resets the GAVDP state machine to the EGAVDPIdle state
214 Note that if the headset is already connected Reseting
215 will cause a subsequent call to RGavdp.Connect, however
216 if we are already connected this should complete straight away
218 Note we don't close the bearer socket here as we need to ensure
219 this is closed after the RTP streamer is deleted so this is handled by the CA2dpBTHeadsetAudioInterface
221 void CGAVDPStateMachine::Reset()
223 iPotentialSEPs.Reset();
225 iSEPCapabilities.ResetAndDestroy();
227 iSEPCapabilityEntry = 0;
228 iA2dpCodecSettings.Reset();
229 iInitialState = TGAVDPState::EGAVDPIdle;
230 iCurrentState = TGAVDPState::EGAVDPIdle;
231 iNextState = TGAVDPState::EGAVDPIdle;
232 iTargetState = TGAVDPState::EGAVDPIdle;
233 iConfigurationByRemoteHeadsetState.Reset();
234 iHeadsetSEID.Reset();
235 iLocalSEPConfigured = EFalse;
236 iChangeOfSelectedHeadsetSEP = EFalse;
238 iSignallingTransactionTimeout->Cancel();
243 Function to move the GAVDP state machine to the state specified in aNewState
244 Not all state changes are allowed, however.
245 Permitted state changes are anystate to ->EGAVDPIdle,EConnectedToGavdp,ESEPsDiscovered
246 which causes a reset.
247 Anything prior to EGAVDPOpen->EGAVDPOpen
248 EGAVDPOpen->EGAVDPStreaming
249 EGAVDPStreaming->EGAVDPOpen
251 When the state change is completed a GAVDPStateChangeComplete callback is
252 made on the MGAVDPStateChangeObserver, which is the CA2dpBTHeadsetAudioInterface
254 @param aNewState The state we wish to go to
255 @return standard SymbianOS error code
257 TInt CGAVDPStateMachine::ChangeState(const TGAVDPState& aNewState)
259 if (iStateChangeInProgress)
260 {//can't change state if a state change is already in progress
263 if (aNewState.State()<= TGAVDPState::ESEPSelected)
265 //if the state is ESEPSelected or less then
266 //the assumption is we need to reselect the SEP and in
267 //effect redo the entire initialization prior to selecting the SEP
268 //therefore roll back to EGAVDPIdle and reset.
271 else if (aNewState == TGAVDPState::EGAVDPStreaming)
273 //must be in the EGAVDPOpen state in order to go to EGAVDPStreaming
274 if (iCurrentState != TGAVDPState::EGAVDPOpen)
280 if (aNewState == iCurrentState)
282 //then we are already in the requested state so don't move to
283 //next state- so just call the RunL and complete
284 iStateChangeInProgress = EFalse;//we're not going to change the state
285 TRequestStatus* stat = &iStatus;
288 User::RequestComplete(stat, KErrNone);
293 {//need to move to the next state
294 iInitialState = iCurrentState; //incase we need to wind back if state change fails
295 iTargetState = aNewState;
303 Function to cause a reconfiguration of the SEP. The function determines
304 whether a reconfiguration is required ie becuase the settings have changed.
305 And if so the SEP is reconfigured or a new SEP is selected if the reconfiguration
306 results in a change of SEP ie because the datatype has changed
307 This function makes a GAVDPStateChangeComplete callback on the CA2dpBTHeadsetAudioInterface
308 If the SEP changes because of a change in data type then the iChangeOfSelectedHeadsetSEP
309 flag is set which is used by the state machine to cause the media transport
310 caps to be added to the SEP
312 @param aSettingsHaveChanged set to ETrue if the settings have changed
314 @return SymbianOS error code
316 TInt CGAVDPStateMachine::Reconfigure(TBool aSettingsHaveChanged)
318 //not allowed to reconfigure in the middle of a state change
319 if ((iStateChangeInProgress)||(IsActive()))
324 //in order to perform a reconfigure the current state must
325 //be either EConfigured or EGAVDPOpen
326 //reconfiguration by the SymbianOs device in the streaming state is not supported
327 //in this implementation even though it is allowed by the GAVDP profile
328 if ((iCurrentState != TGAVDPState::EConfigured) &&
329 (iCurrentState != TGAVDPState::EGAVDPOpen))
334 __ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));//this should always be true if no state change is in progress
336 iChangeOfSelectedHeadsetSEP = EFalse;
337 if (aSettingsHaveChanged)
338 {//then see if we need to change SEP
339 //data type has changed so we need to choose a different SEP
341 //note if no match is found then we go with the exiting
343 for (TUint i=0; i<iUsableSEPs.Count() ; i++)
345 TUsableSEP sep = iUsableSEPs[i];
346 if (sep.iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
347 {//then we have a match so use this SEP
348 if (sep.iSEID != iHeadsetSEID)
349 {//then this is a different SEP to the one we were already using
350 iHeadsetSEID = sep.iSEID;
351 iLocalSEPConfigured = EFalse;
352 iChangeOfSelectedHeadsetSEP = ETrue;//need to config transport capabilites again if change of SEP
353 //need to change the symbian device SEP as well
354 TBool symbianDeviceSupportsNewSEPDataType(EFalse);
355 for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
357 if (iSymbianDeviceSEPs[i].iDataType == sep.iDataType)
359 iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID;
360 symbianDeviceSupportsNewSEPDataType = ETrue;
364 __ASSERT_DEBUG(symbianDeviceSupportsNewSEPDataType, Panic(EGavdpStateMachineDataTypeMismatch));
366 //the if condition below is totaly unnecesaary since we have already
367 //ASSERTed symbianDeviceSupportsNewSEPDataType, however the ARM 5 compiler
368 //does not seem to recognize code in ASSERT statements so the if statement
369 //supresses an ARM v5 compiler warning
370 if (symbianDeviceSupportsNewSEPDataType)
372 iBearerSocket.Close(); //if we change headset SEP then the old bearer is no longer valid
381 //if a reconfigure is required then we need to reset the current state
382 //to ESEPSelected and reconfigure
383 iInitialState = iCurrentState; //incase we need to wind back if state change fails
385 if ((aSettingsHaveChanged)||(iChangeOfSelectedHeadsetSEP))
387 iTargetState = iCurrentState; //need to end up in the same state we started at
388 iCurrentState = TGAVDPState::ESEPSelected; //roll back the state machine to ESEPSelected
389 iNextState = iCurrentState;
390 NextState(); //make sure the NextState is EConfigured
393 {//go to RunL to make GAVDPStateChangeComplete callback
396 TRequestStatus* stat = &iStatus;
397 User::RequestComplete(stat, KErrNone);
406 Advance to Next state
408 void CGAVDPStateMachine::NextState()
410 iStateChangeInProgress = ETrue;
411 TRequestStatus* stat = &iStatus;
415 User::RequestComplete(stat, KErrNone);
422 Internal function to complete the state change
424 void CGAVDPStateMachine::StateChangeComplete()
426 iCurrentState = iNextState;
427 if (iCurrentState == iTargetState)
429 iStateChangeInProgress = EFalse;
430 iGAVDPStateChangeObserver.GAVDPStateChangeComplete(iInitialState, KErrNone);
433 {//we've completed the internal state change but have not reached the target state
440 Function to cancel a state change initialited by the ChangeState function
441 This function is called when the change state is explicitly cancelled by the client
443 void CGAVDPStateMachine::CancelChangeState()
445 //if we call this externally then the reason is KErrCancel
446 //as the state change has been explicitely cancelled
447 CancelChangeState(KErrCancel);
452 Internal function to cancel a state change initiated by the ChangeState function
453 Usually called when an error occurs that would prevent the state change
456 void CGAVDPStateMachine::CancelChangeState(TInt aReason)
458 if (iStateChangeInProgress)
459 {//unwind the request as far as possible
460 switch (iInitialState.State())
462 case TGAVDPState::EGAVDPIdle:
465 case TGAVDPState::EGAVDPOpen:
467 iCurrentState = TGAVDPState::EGAVDPOpen;
468 iNextState = TGAVDPState::EGAVDPOpen;
469 iTargetState = TGAVDPState::EGAVDPOpen;
471 case TGAVDPState::EGAVDPStreaming:
473 iNextState = TGAVDPState::EGAVDPStreaming;
474 iTargetState = TGAVDPState::EGAVDPStreaming;
477 Panic(EGavdpStateMachineBadState);
485 iStateChangeInProgress = EFalse;
486 iGAVDPStateChangeObserver.GAVDPStateChangeComplete(iInitialState, aReason);
491 Internal function to initiate the connection to the headset
493 void CGAVDPStateMachine::ConnectToGAVDP()
495 iGavdp.Connect(iBTDevAddr);
500 MGavdpUser callback to indicate the headset is connected
504 void CGAVDPStateMachine::GAVDP_ConnectConfirm(const TBTDevAddr& aDevice)
506 if (!iStateChangeInProgress)
507 {//connect initiated by remote headset so we'll accept the address
508 iBTDevAddr = aDevice;
509 iCurrentState == TGAVDPState::EConnectedToGavdp;
511 else if (iBTDevAddr == aDevice)
512 {//if a state change is in progress then we have already set the bt
513 //address so the above should be true
514 //if its not we'll treat the connect as a spurious connect and ignore
515 if (iCurrentState.State() == TGAVDPState::EGAVDPIdle)
516 {//if the above isn't true then must be a spurious connect from the headset
517 //now connected to the device in question
518 StateChangeComplete();
525 MGavdpUser callback to indicate the headset has suspended streaming
526 Makes a GAVDPStateMachineStreamSuspendedByRemoteHeadset MGAVDPStateChangeObserver
527 callback on the CA2dpBTHeadsetAudioInterface
531 TInt CGAVDPStateMachine::GAVDP_SuspendIndication(TSEID aSEID)
534 //first check the callback is for the symbian device SEP we are using to
535 //send data to the a2dp headset - incase the Symbian device has more than one SEP
536 if (aSEID == iSymbianDeviceSEID)
538 __ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
540 //need to stop the RTP streamer from sending more packets to the headset
541 iGAVDPStateChangeObserver.GAVDPStateMachineStreamSuspendedByRemoteHeadset();
543 iCurrentState = TGAVDPState::EGAVDPSuspended;
547 err = ConvertToSymbianError::AvdtpError(EAvdtpBadACPSEID);
554 MGavdpUser callback to indicate the headset wished to configure the SymbianDevice
558 void CGAVDPStateMachine::GAVDP_ConfigurationStartIndication(TSEID aLocalSEID, TSEID aRemoteSEID)
560 //first check the callback is for the symbian device SEP we are using to
561 //send data to the a2dp headset - incase the Symbian device has more than one SEP
562 if (aLocalSEID == iSymbianDeviceSEID)
564 __ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
565 __ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ENotBeingConfiguredByRemoteHeadset, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
567 //cancel any current state changes - config is being driven by headset
570 //no timeouts are required as if the headset goes down ie does not
571 //result in the expected GAVDP_ConfigurationIndication callbacks a GAVDP_Error
574 iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart;
576 //we just store the remote SEP for now
577 iConfigurationByRemoteHeadsetState.SetSEPRequestedByRemoteHeadset(aRemoteSEID);
579 // else we can't return an error if the aLocalSEID is not for the SymbianOS device
584 MGavdpUser callback to request the SymbianOS device to take the configuration passed in aCapability
585 Only SBC reconfigurations by the remote headset are supported, sample rate changes
586 are not supported, changes in the number of channels are not suported
587 if the capability is TSBCCodecCapabilities then the function checks that the values
588 requested can be accepted.
592 TInt CGAVDPStateMachine::GAVDP_ConfigurationIndication(TAvdtpServiceCapability* aCapability)
594 //the underlying GAVDP/AVDTP code should ensure that this
595 //callback from GAVDP never occurs once the headset has been configured
596 __ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
597 __ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
601 switch(aCapability->Category())
603 case EServiceCategoryMediaTransport:
605 TAvdtpMediaTransportCapabilities* mediaTransportCaps = static_cast<TAvdtpMediaTransportCapabilities*>(aCapability);
606 iConfigurationByRemoteHeadsetState.SetTransportCapsRequestedByRemoteHeadset(mediaTransportCaps);
609 case EServiceCategoryMediaCodec:
611 TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(aCapability);
612 if (codecCaps->MediaType() != EAvdtpMediaTypeAudio)
614 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec);
616 //we're only going to allow a reconfiguration for SBC
617 if ((codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCCodeSBC))
619 TSBCCodecCapabilities* sbcCodecCapabilities = static_cast<TSBCCodecCapabilities*>(codecCaps);
620 TSBCSamplingFrequencyBitmask samplingFreqBitMask = sbcCodecCapabilities->SamplingFrequencies();
622 //if the headset has already been configured then we don't allow a change
623 //of sampling frequency. This is because once the DevSound has been configured
624 //with a sampling frequency after the DevSound is initialized and hence
625 //the a2dpheadsetif is initialized, it is no longer possible to change the sample frequency
626 TBool headsetAlreadyConfigured(EFalse);
627 if ((iCurrentState.State() == TGAVDPState::EGAVDPOpen) ||
628 (iCurrentState.State() == TGAVDPState::EGAVDPSuspended))
630 headsetAlreadyConfigured = ETrue;
632 //only one bit of the sampling frequency mask should be set
633 //note we're using switch statements rather than if then else
634 //it makes it easier to pick up the case where we have an invalid
635 //value or more than one value has been set in the bit mask
636 switch (samplingFreqBitMask)
639 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 16000))
641 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
645 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 32000))
647 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
651 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 44100))
653 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
657 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 48000))
659 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency);
663 err = ConvertToSymbianError::A2dpError(EA2dpInvalidSamplingFrequency);
666 TSBCChannelModeBitmask channelModeBitMask = sbcCodecCapabilities->ChannelModes();
668 //if the headset has already been configured then we don't allow a change
669 //of channels. This is because once the DevSound has been configured
670 //with a sampling frequency after the DevSound is initialized and hence
671 //the a2dpheadsetif is initialized, it is no longer possible to change the number of channels
672 switch (channelModeBitMask)
675 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFMono))
677 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
680 case EDualChannel: //we don't support dual channel
681 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
684 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo))
686 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
690 if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo))
692 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode);
696 err = ConvertToSymbianError::A2dpError(EA2dpInvalidChannelMode);
700 TSBCBlockLengthBitmask blockLengthBitMask = sbcCodecCapabilities->BlockLengths();
702 switch (blockLengthBitMask)
708 case EBlockLenTwelve:
710 case EBlockLenSixteen:
713 err = ConvertToSymbianError::A2dpError(EA2dpInvalidBlockLength);
717 TSBCSubbandsBitmask subbandsBitMask = sbcCodecCapabilities->Subbands();
720 switch (subbandsBitMask)
729 err = ConvertToSymbianError::A2dpError(EA2dpInvalidSubbands);
733 TSBCAllocationMethodBitmask allocationMethodBitMask = sbcCodecCapabilities->AllocationMethods();
735 switch (allocationMethodBitMask)
742 err = ConvertToSymbianError::A2dpError(EA2dpInvalidAllocationMethod);
746 TInt bitPoolValue = sbcCodecCapabilities->MinBitpoolValue();
748 if (bitPoolValue < KMinBitPoolValue)
750 err = ConvertToSymbianError::A2dpError(EA2dpInvalidMinimumBitPoolValue);
753 bitPoolValue = sbcCodecCapabilities->MaxBitpoolValue();
755 //The bitpool value must be in the range of 2-250 and must not exceed
756 // 16*numberOfSubbands*channels
757 if ((bitPoolValue > KMaxBitPoolValue)||(bitPoolValue > (16*subbands*iA2dpCodecSettings.Channels())))
759 err = ConvertToSymbianError::A2dpError(EA2dpInvalidMaximumBitPoolValue);
762 {//note ownership of codecCaps is transferred
763 iConfigurationByRemoteHeadsetState.SetCodecConfigRequestedByRemoteHeadset(codecCaps);
765 }//if (codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCodeSBC))
767 {//only support SBC for now
768 err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec);
771 break; //case EServiceCategoryMediaCodec:
772 default: // switch(aCapability->Category())
773 err = KErrNotSupported;
779 iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed;
780 if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle))
781 {//we only abort if the remote headset has not been configured
782 //need to abort using SEID of remote headset - this resets config at remote headset
783 Cancel(); //probably not necessary - but just in case
784 iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset());
787 //config is a reconfig in suspend streams
788 //wait on a Start_Indication if the headset is ok with the existing config
789 //or an Abort_Indication if the headset is not
797 MGavdpUser callback to indicate to the SymbianOS device that all the GAVDP_ConfigurationIndications
799 This callback should only occur if there have been no errored GAVDP_ConfigurationIndications
803 TInt CGAVDPStateMachine::GAVDP_ConfigurationEndIndication()
805 //the underlying GAVDP/AVDTP code should ensure that this
806 //callback from GAVDP never occurs once the headset has been configured
807 __ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback));
808 __ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
812 TAvdtpMediaCodecCapabilities* configRequestedByRemoteHeadset = iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset();
813 if (configRequestedByRemoteHeadset)
815 __ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset().IsValid(), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
817 //the headset settings have been accepted so use the headset settings
818 //the only usable SEP shall be the once specified by the headset
819 //for now this will always be SBC
821 SEP.iSEID = iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset();
822 TFourCC dataTypeSupport;
823 switch (configRequestedByRemoteHeadset->MediaCodecType())
826 dataTypeSupport.Set(KMMFFourCCCodeSBC);
828 case EAudioCodecMPEG12Audio:
829 dataTypeSupport.Set(KMMFFourCCCodeMP3);
831 case EAudioCodecMPEG24AAC:
832 dataTypeSupport.Set(KMMFFourCCCodeAAC);
834 case EAudioCodecATRAC:
835 dataTypeSupport.Set(KMMFFourCCCodeATRAC3);
837 default://should never get here
838 Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState);
841 SEP.iDataType.Set(dataTypeSupport);
843 err = iUsableSEPs.Append(SEP);
845 //the only service capabilities are codec caps provided by the headset and transport
846 if (!(iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*configRequestedByRemoteHeadset)))
852 iSEPCapabilities.ResetAndDestroy();
853 err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.TransportCapsRequestedByRemoteHeadset());
856 err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset());
863 if ((iStateChangeInProgress) && (iInitialState.State() == TGAVDPState::EGAVDPIdle))
864 {//the headset configured us during an a2dpheadsetif Initialize()
865 //we're now configured so now wait for GAVDP_Bearer ready
866 iCurrentState == TGAVDPState::EConfigured;
868 else if (iCurrentState == TGAVDPState::EGAVDPSuspended)
870 //we have reconfigured so the SBC codec needs reconfiguring
871 err = iGAVDPStateChangeObserver.GAVDPStateMachineReconfigureByRemoteHeadset();
876 if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle))
877 {//we only abort if the remote headset has not been configured
878 //need to abort using SEID of remote headset - this resets config at remote headset
879 Cancel(); //probably not necessary - but just in case
880 iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset());
884 //config is a reconfig in suspend streams
885 //wait on a Start_Indication if the headset is ok with the existing config
886 //or an Abort_Indication if the headset is not
887 iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationEnd;
893 MGavdpUser callback to indicate to the SymbianOS device that it has started streaming
894 There are two circumstances we can get a start indication
895 1) The headset can request to start the streams itself once we are in the open state
896 2) The headset can request a restart after suspending the streams eg to perform a reconfiguration
900 TInt CGAVDPStateMachine::GAVDP_StartIndication(TSEID aSEID)
902 __ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPOpen) ||
903 (iCurrentState.State() == TGAVDPState::EGAVDPSuspended), Panic(EGavdpStateMachineUnexpectedCallback));
904 __ASSERT_DEBUG((iConfigurationByRemoteHeadsetState.State() != TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart),Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
905 //first check the callback is for the symbian device SEP we are using to
906 //send data to the a2dp headset - incase the Symbian device has more than one SEP
907 if (aSEID == iSymbianDeviceSEID)
909 if (iCurrentState.State() == TGAVDPState::EGAVDPOpen)
911 if (iStateChangeInProgress)
913 if (iTargetState.State() == TGAVDPState::EGAVDPStreaming)
915 //a EGAVDPOpen->Streaming transistion
916 //which has been completed for us by the headset
919 iCurrentState = TGAVDPState::EGAVDPStreaming;
920 StateChangeComplete();
922 //else only other state change would be open->idle
923 //this is unlikely/impossible if we get a GAVDP_StartIndication
928 //note if no state change is in progress then the headset itself
929 //has put itself in the streaming state
930 //normally we put the headset in the streaming state
931 //when we call OpenDevice() on the a2dpaudioif
932 //but if the headset does this then it is no longer possible
933 //for the client to change the audio settings
934 iCurrentState = TGAVDPState::EGAVDPStreaming;
936 }//(iCurrentState.State() == TGAVDPState::EGAVDPOpen)
937 else if (iCurrentState.State() == TGAVDPState::EGAVDPSuspended)
938 {//most probably restarting after a reconfigure
939 iCurrentState = TGAVDPState::EGAVDPStreaming;
940 iGAVDPStateChangeObserver.GAVDPStateMachineStreamResumedByRemoteHeadset();
942 }//if (aSEID == iSymbianDeviceSEID)
948 MGavdpUser callback to indicate to the SymbianOS device that the request to abort the headset
949 which means it is not configured has completed
950 Can request an abort stream if headset configuration fails
954 void CGAVDPStateMachine::GAVDP_AbortStreamConfirm()
956 //if abort stream was caused by aborting the headset in response
957 //to a headset configuration in GAVDP_ConfigurationIndication
958 //then restart state machine from EConnectedToGavdp
959 if (iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed)
960 {//then the abort was caused an aborted configuration from the headset
961 __ASSERT_DEBUG((iCurrentState.State() < TGAVDPState::EConfigured), Panic(EGavdpStateMachineUnexpectedCallback));
963 //since we only aborted if the headset was not yet configured
964 //there must be a state change in progress and since we cancelled
965 //the GAVDPStateMachine should not be active
966 __ASSERT_DEBUG((iStateChangeInProgress) && (!IsActive()), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState));
968 iConfigurationByRemoteHeadsetState.Reset();
969 //just to make extra sure we'll rediscover the SEPs
970 iPotentialSEPs.Reset();
972 iSEPCapabilities.ResetAndDestroy();
973 iCurrentState = TGAVDPState::EConnectedToGavdp;
974 iNextState = TGAVDPState::EConnectedToGavdp;
975 iConfigurationByRemoteHeadsetState.Reset();
976 iA2dpCodecSettings.Reset();
977 iHeadsetSEID.Reset();
978 iBearerSocket.Close();
979 iLocalSEPConfigured = EFalse;
980 iChangeOfSelectedHeadsetSEP = EFalse;
981 iSignallingTransactionTimeout->Cancel();
984 iConfigurationByRemoteHeadsetState.Reset();
989 MGavdpUser callback to indicate to the SymbianOS device that the headset has aborted
990 ie it can no longer be regarded as configured
991 This makes a GAVDPStateMachineEvent MGAVDPStateChangeObserver callback on the CA2dpBTHeadsetAudioInterface
992 (which inturn will cause a Reset on the GAVDP state machine)
996 void CGAVDPStateMachine::GAVDP_AbortIndication(TSEID aSEID)
998 //first check the callback is for the symbian device SEP we are using to
999 //send data to the a2dp headset - incase the Symbian device has more than one SEP
1000 if (aSEID == iSymbianDeviceSEID)
1002 if (iStateChangeInProgress)
1004 CancelChangeState(KErrAbort);
1008 iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrAbort);
1011 //else not much we can do it aSEID isn't the Symbian device ID
1012 iConfigurationByRemoteHeadsetState.Reset();
1017 Internal function to initiate the discovery of the headset SEPs
1018 Note that the SEP discovery does not have a built in timeout
1019 so the GAVDP_SEPDiscovered callback must occur withing the GAVDP callback timeout 30s
1020 or the state change will be cancelled with KErrTimedOut
1022 void CGAVDPStateMachine::DiscoverRemoteSEPs()
1024 iPotentialSEPs.Reset();
1025 iGavdp.DiscoverRemoteSEPs();
1026 iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout));
1031 MGavdpUser callback in response to DiscoverRemoteSEPs
1035 void CGAVDPStateMachine::GAVDP_SEPDiscovered(const TAvdtpSEPInfo& aSEP)
1037 //check whether the SEP is suitable for connection
1038 if ((!aSEP.InUse()) && (aSEP.MediaType() == EAvdtpMediaTypeAudio) && (aSEP.IsSink()))
1039 {//the SEP is a potentialy suitable for connection
1040 //so add to list of potential SEPs
1041 TInt err = iPotentialSEPs.Append(aSEP.SEID());
1044 CancelChangeState(err);
1047 //else SEP is not suitable so ignore it
1056 void CGAVDPStateMachine::GAVDP_SEPDiscoveryComplete()
1058 iSignallingTransactionTimeout->Cancel();
1059 if (iPotentialSEPs.Count())
1060 {//we have at least one potential SEP
1061 StateChangeComplete();
1064 {//no potential SEPs were found so cannot proceed any further
1065 CancelChangeState(KErrCouldNotConnect);
1071 Internal function to get the capability of an individual SEP
1073 void CGAVDPStateMachine::GetRemoteSEPCapability()
1075 TAvdtpServiceCategories serviceCategories;
1076 serviceCategories.SetCapability(EServiceCategoryMediaTransport);
1077 serviceCategories.SetCapability(EServiceCategoryMediaCodec);
1078 TSEID SEPtoGetCapabilityOf = iPotentialSEPs[iSEPIterator];
1079 iGavdp.GetRemoteSEPCapabilities(SEPtoGetCapabilityOf, serviceCategories);
1080 iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout));
1085 Internal function to iterate through the list of potential SEPs and asking
1086 for the capabilites of each one.
1088 void CGAVDPStateMachine::GetRemoteSEPCapabilities()
1090 iSEPCapabilities.ResetAndDestroy(); //clear what's already there
1091 iUsableSEPs.Reset();
1093 iSEPCapabilityEntry = 0;
1094 //go and get the capability of the first SEP in the list of potential SEPs
1095 //the GAVDP_SEPCapabilityComplete() callback will cause the next potential
1096 //SEP capability to be obtained.
1097 GetRemoteSEPCapability();
1102 MGavdpUser callback in response to GetRemoteSEPCapabilities
1106 void CGAVDPStateMachine::GAVDP_SEPCapability(TAvdtpServiceCapability* aCapability)
1108 // we own cap, stash it in the iSEPCapabilities array for owning and later use
1109 TInt err = iSEPCapabilities.Append(aCapability);
1112 CancelChangeState(err);
1118 MGavdpUser callback in response to GetRemoteSEPCapabilities when all the
1119 GAVDP_SEPCapability callbacks have been made for an individual SEP
1121 The function iterates through the SEP capabilites looking for transport and media codec support
1122 and if so the SEP is added to the list of usableSEPs.
1126 void CGAVDPStateMachine::GAVDP_SEPCapabilityComplete()
1128 TInt err = KErrNone;
1129 iSignallingTransactionTimeout->Cancel();
1130 //iterate through the capabilities
1131 TAvdtpServiceCapability* avdtpServiceCapability;
1132 TBool mediaTransport(EFalse);
1133 TBool audioSupport(EFalse);
1134 TFourCC dataTypeSupport; //note we are assuming here that each SEP only has one codec capability
1136 //iterate through the capabilities
1137 //looking for media transport and codec support
1138 for (;iSEPCapabilityEntry < iSEPCapabilities.Count() ; iSEPCapabilityEntry++)
1140 avdtpServiceCapability = iSEPCapabilities[iSEPCapabilityEntry];
1141 switch (avdtpServiceCapability->Category())
1143 case EServiceCategoryMediaTransport:
1144 mediaTransport = ETrue;
1146 case EServiceCategoryMediaCodec:
1148 TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(avdtpServiceCapability);
1149 if (codecCaps->MediaType() == EAvdtpMediaTypeAudio)
1151 audioSupport = ETrue;
1153 switch (codecCaps->MediaCodecType())
1155 case EAudioCodecSBC:
1156 dataTypeSupport.Set(KMMFFourCCCodeSBC);
1158 case EAudioCodecMPEG12Audio:
1159 dataTypeSupport.Set(KMMFFourCCCodeMP3);
1161 case EAudioCodecMPEG24AAC:
1162 dataTypeSupport.Set(KMMFFourCCCodeAAC);
1164 case EAudioCodecATRAC:
1165 dataTypeSupport.Set(KMMFFourCCCodeATRAC3);
1168 //the datatype is an unsupported datatype
1169 //so set to NULL to show we can't use it
1170 dataTypeSupport.Set(KMMFFourCCCodeNULL);
1174 }//switch (avdtpServiceCapability->Category())
1175 }// for (TUint i=0; i++; i<iSEPCapabilities.Count())
1176 //check if the capabilities indicate that the SEP is usable
1177 //for audio transport
1178 if ((mediaTransport) && (audioSupport) &&
1179 (dataTypeSupport != KMMFFourCCCodeNULL))
1180 {//then we can use this SEP to stream audio to the headset
1181 // however we ie the Symbian device must
1182 //also be able to support the data type
1183 //before we can add it to the list of usable SEPs
1184 TBool symbianDeviceSupportsDataType(EFalse);
1185 for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++)
1187 if (iSymbianDeviceSEPs[i].iDataType == dataTypeSupport)
1189 symbianDeviceSupportsDataType = ETrue;
1193 if (symbianDeviceSupportsDataType)
1195 TUsableSEP usableSEP;
1196 usableSEP.iSEID = iPotentialSEPs[iSEPIterator];
1197 usableSEP.iDataType.Set(dataTypeSupport);
1198 err = iUsableSEPs.Append(usableSEP);
1201 CancelChangeState(err);
1207 //check if we have finished going through our list of potential SEPs
1208 //that we need to find the capabilities of
1210 if (iSEPIterator >= iPotentialSEPs.Count())
1211 {//then we have finished getting all the capabilities
1212 //so lets choose a SEP by iterating through the
1213 //usable SEPs and stopping at the first one that supports the
1214 //required data type
1216 TBool SEPFound(EFalse);
1217 for (i=0; i<iUsableSEPs.Count(); i++)
1219 SEP = iUsableSEPs[i];
1220 if (SEP.iDataType == iA2dpCodecSettings.HeadsetCodecDataType())
1221 {//one of the usable SEPs supports the requested data type
1223 iHeadsetSEID = SEP.iSEID; //we'll use this SEID for now
1228 iSEPCapabilityEntry = 0;
1231 //we've selected a SEP
1232 StateChangeComplete(); //so move on to the next state
1236 //then non of the SEPs have SBC codec capabilites
1237 //or no usable SEPs have been found or SEP may be in use
1238 //since SBC support is mandatory we do not have a suitable SEP
1239 CancelChangeState(KErrCouldNotConnect);
1241 }// if (iPotentialSEPs.Count() >= iSEPIterator)
1243 {//get the capability of the next SEP
1244 GetRemoteSEPCapability();
1251 Function used to return a TAvdtpMediaCodecCapabilities structure
1252 that can be used to configure the SEP at the remote end ie on the headset
1253 The capabilities are used to determine the configuration
1254 need to return by pointer rather than by ref as TAvdtpMediaCodecCapabilities is abstract
1256 TAvdtpMediaCodecCapabilities* CGAVDPStateMachine::RemoteCodecConfiguration()
1258 TAvdtpMediaCodecCapabilities* codecCaps = NULL;
1259 TAvdtpMediaCodecCapabilities* codecConfiguration = NULL;
1261 //first get the capabilities of the codec
1262 TInt error = CodecCaps(codecCaps);
1264 {//and use the capabilities to get a valid remote codec configuration
1265 codecConfiguration = iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*codecCaps);
1268 return codecConfiguration;
1273 Internal function to configure the local SEP
1275 TInt CGAVDPStateMachine::ConfigureLocalSEP()
1277 TInt err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID);
1278 if (err == KErrNotFound)
1280 //could be a problem with the local SEP no longer being registered
1281 //so register and try again
1282 err = RegisterLocalSEP();
1285 err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID);
1289 {//configure local SEP - we only advertise one local SEP with SBC support
1290 //in future when capability structures are defined for mp3,AAC,ATRAC3
1291 //then these can also be advertised as local SEPs
1292 TAvdtpMediaTransportCapabilities media;
1293 err = iGavdp.AddSEPCapability(media);
1297 CA2dpLocalCodecCapabilities* localCodecCapabilities = NULL;
1298 TRAP(err, localCodecCapabilities = CA2dpLocalCodecCapabilities::NewL())
1301 TAvdtpMediaCodecCapabilities* localSEPCapability = localCodecCapabilities->LocalCodecCapabilities(iA2dpCodecSettings.HeadsetCodecDataType());
1302 if (localSEPCapability)
1304 err = iGavdp.AddSEPCapability(*localSEPCapability);
1310 delete localCodecCapabilities;
1311 localCodecCapabilities = NULL;
1320 Internal function to configure the remote SEP ie the headset
1322 If the SEP has never been configured before then the transport caps are added
1323 If we are doing a reconfigure of the remote SEP then just the codec caps are added
1325 TInt CGAVDPStateMachine::ConfigureRemoteSEP()
1327 TInt err = iGavdp.BeginConfiguringRemoteSEP(iHeadsetSEID, iSymbianDeviceSEID);
1330 if ((iInitialState.State() < TGAVDPState::EConfigured)||(iChangeOfSelectedHeadsetSEP))
1331 {//then this SEP has never been configured before
1332 //in which case we need to configure it with transport capabilities
1333 //note that if the SEP has been configured before ie the above condition
1334 //is false then we are performing a reconfiguration and are not allowed
1335 //to reconfigure the media transport capabilities
1336 TAvdtpMediaTransportCapabilities avdtpMediaTransportCapabilities;
1337 err = iGavdp.AddSEPCapability(avdtpMediaTransportCapabilities);
1338 iChangeOfSelectedHeadsetSEP = EFalse;//reset
1342 TAvdtpMediaCodecCapabilities* codecConfiguration = RemoteCodecConfiguration();
1343 //note we are setting a configuration here not a capability
1344 if (codecConfiguration)
1346 err = iGavdp.AddSEPCapability(*codecConfiguration);
1349 {//we were not able to get a valid configuration
1350 //so abort configuration
1360 Internal function to initiate SEP configuration of both the local and remote SEPs
1362 void CGAVDPStateMachine::ConfigureSEP()
1364 if (iHeadsetSEID.IsValid())
1367 if (!iLocalSEPConfigured)
1368 {//the local SEP must be configured first before configuring the remote SEP
1369 err = ConfigureLocalSEP();
1372 {//local SEP is already configured so configure remote SEP
1373 err = ConfigureRemoteSEP();
1377 CancelChangeState(err);
1381 iGavdp.CommitSEPConfiguration();
1385 {//we've requested to configure a SEP before we have
1386 //a valid SEP to configure
1387 CancelChangeState(KErrNotReady);
1393 MGavdpUser callback to confirm that the SEP configuration has been acepted
1394 This callback should occur for both the local SEP and the remote SEP
1396 void CGAVDPStateMachine::GAVDP_ConfigurationConfirm()
1398 TInt err = KErrNone;
1399 if (!iLocalSEPConfigured)
1400 {//the local SEP is configured first so this call back must be from
1401 //a local SEP configuration
1402 iLocalSEPConfigured = ETrue;
1403 //now configure the remote SEP
1404 err = ConfigureRemoteSEP();
1407 iGavdp.CommitSEPConfiguration();
1411 CancelChangeState(err);
1416 //local and remote SEPs now configured
1417 TInt err = iGavdp.Listen();
1418 //note that if there is an error above
1419 // there is not much we can do so ignore it
1420 StateChangeComplete();
1426 Internal function to request a bearer RSocket in order to stream audio to the headset
1428 void CGAVDPStateMachine::CreateBearerSocket()
1430 //then we need to request for one from the remote SEP
1431 //this reference code does not support reporting and recovery channels
1433 if (!iBearerSocket.SubSessionHandle())
1434 {//we don't already have a bearer socket, create one - note no reporting and recovery implementation
1435 TInt err = iGavdp.CreateBearerSockets(iHeadsetSEID, EFalse, EFalse);
1438 CancelChangeState(err);
1443 //we already have a bearer socket so no need to create a new one
1444 //just complete the state change
1445 StateChangeComplete();
1451 MGavdpUser callback to supply the RSocket used to stream audio to the headset
1453 This callback can occur either via a direct request from the headset or in response
1454 to a CreateBearerSocket
1458 void CGAVDPStateMachine::GAVDP_BearerReady(RSocket aSocket, const TAvdtpSockAddr& /*aAddress*/)
1460 //This call back can occur without a prior call to CreateBearerSocket
1461 iBearerSocket = aSocket;
1462 if ((iCurrentState == TGAVDPState::EConfigured)&&(iStateChangeInProgress))
1463 {//we've completed the state
1464 StateChangeComplete();
1466 // else this came from the headset without a call to RGavdp::CreateBearerSockets
1471 Function to return an array of usable SEPs on the headset.
1472 By 'usable' we mean the SEP supports audio, has media transport caps, is not in use,
1473 has a supported audio codec and the audio codec is supported by the symbianOS device
1474 @return array of usable SEPs
1476 RArray<TUsableSEP>& CGAVDPStateMachine::UsableSEPs() const
1478 return const_cast<RArray<TUsableSEP>&>(iUsableSEPs);
1483 Function to return the bearer socket used to stream audio to the headset
1486 RSocket& CGAVDPStateMachine::BearerSocket() const
1488 return const_cast<RSocket&>(iBearerSocket);
1493 Function to return the headset BT address
1494 @return headset BT address
1496 TBTDevAddr& CGAVDPStateMachine::BTAddress() const
1498 return const_cast<TBTDevAddr&>(iBTDevAddr);
1503 Function to return the SEPCapability for the codec settings
1504 used by CA2dpBTHeadsetAudioInterface to determine the audio settings
1505 ie sample rate / stereo support.
1506 aCodecCaps is set with the TAvdtpMediaCodecCapabilities of the codec in use
1507 if no codec has been specified via the Reconfigure() function then
1508 the codec defaults to SBC
1509 returns KErrNotReady if no SEP capablities have been obtained from the SEP
1510 return KErrNotSupported if the codec type is not known
1511 aCodecCaps Note that ownership is not transferred to the calling class.
1513 @param aCodecCaps The pointer points to a codec capabilities structure
1515 @return SymbianOS error code
1517 TInt CGAVDPStateMachine::CodecCaps(TAvdtpMediaCodecCapabilities*& aCodecCaps) const
1519 TInt err = KErrNotReady;
1520 TAvdtpServiceCapability* avdtpServiceCapability;
1522 for (TUint i=0; i<iSEPCapabilities.Count(); i++)
1524 avdtpServiceCapability = iSEPCapabilities[i];
1525 if (avdtpServiceCapability->Category() == EServiceCategoryMediaCodec)
1527 TAvdtpMediaCodecCapabilities* codecCaps = static_cast<TAvdtpMediaCodecCapabilities*>(avdtpServiceCapability);
1528 switch (codecCaps->MediaCodecType())
1530 case EAudioCodecSBC:
1531 dataType.Set(KMMFFourCCCodeSBC);
1533 case EAudioCodecMPEG12Audio:
1534 dataType.Set(KMMFFourCCCodeMP3);
1536 case EAudioCodecMPEG24AAC:
1537 dataType.Set(KMMFFourCCCodeAAC);
1539 case EAudioCodecATRAC:
1540 dataType.Set(KMMFFourCCCodeATRAC3);
1543 err = KErrNotSupported;
1546 if (dataType == iA2dpCodecSettings.HeadsetCodecDataType())
1547 {//then we have the capabilities for the selected datatype
1548 aCodecCaps = codecCaps;
1553 } //for (TUint i=0; i<iSEPCapabilities.Count(); i++)
1559 MGavdpUser callback when headset releases stream
1563 void CGAVDPStateMachine::GAVDP_ReleaseIndication(TSEID aSEID)
1565 if (aSEID == iSymbianDeviceSEID)
1567 if (iStateChangeInProgress)
1569 CancelChangeState(KErrDisconnected);
1573 iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrDisconnected);
1575 TInt err = iGavdp.Listen();//can't do much if this errors
1581 MGavdpUser error callback
1585 void CGAVDPStateMachine::GAVDP_Error(TInt aError, const TDesC8& /*aErrorData*/)
1587 TInt error = ConvertToStandardSymbianOSError(aError);
1588 if (iStateChangeInProgress)
1590 CancelChangeState(error);
1594 //error must have occured while no state change was in progress
1595 //this could be due to a problem on the headset eg no longer in range
1596 //Make callback on a2dpBTHeadsetIf so it can reset back to the idle state
1597 iGAVDPStateChangeObserver.GAVDPStateMachineEvent(error);
1599 //start listening for connect event from headset
1600 TInt err = iGavdp.Listen();//can't do much if this errors
1605 Internal function to put the headset in the streaming state
1607 void CGAVDPStateMachine::StartStream()
1609 //we're only going to start one transport stream
1610 iGavdp.StartStream(iHeadsetSEID);
1615 MGavdpUser callback in response to StartStream
1619 void CGAVDPStateMachine::GAVDP_StartStreamsConfirm()
1621 StateChangeComplete();
1626 Internal function to tell the headset we are suspending the stream
1628 void CGAVDPStateMachine::SuspendStream()
1630 //we're only going to suspend one transport stream
1631 iGavdp.SuspendStream(iHeadsetSEID);
1636 MGavdpUser callback in response to SuspendStream
1640 void CGAVDPStateMachine::GAVDP_SuspendStreamsConfirm()
1642 StateChangeComplete();
1647 RunsL for GAVDP state machine
1649 void CGAVDPStateMachine::RunL()
1651 if (iStateChangeInProgress)
1653 switch (iCurrentState.State())
1655 case TGAVDPState::EGAVDPIdle:
1658 case TGAVDPState::EConnectedToGavdp:
1659 DiscoverRemoteSEPs();
1661 case TGAVDPState::ESEPsDiscovered:
1662 GetRemoteSEPCapabilities();
1664 case TGAVDPState::ESEPSelected:
1667 case TGAVDPState::EConfigured:
1668 CreateBearerSocket();
1670 case TGAVDPState::EGAVDPOpen:
1673 case TGAVDPState::EGAVDPStreaming:
1677 Panic(EGavdpStateMachineBadState);
1683 //if RunL should get called when no state
1684 //change is in progress eg during a reconfiguration
1685 //then the current state should always be identical to the target state
1686 __ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));
1687 StateChangeComplete();
1695 void CGAVDPStateMachine::DoCancel()
1697 TRequestStatus* stat = &iStatus;
1698 User::RequestComplete(stat, KErrCancel);
1704 CGavdpTimeout* CGavdpTimeout::NewL(CGAVDPStateMachine& aGAVDPStateMachine)
1706 CGavdpTimeout* self = new(ELeave)CGavdpTimeout();
1707 CleanupStack::PushL(self);
1708 self->ConstructL(aGAVDPStateMachine);
1709 CleanupStack::Pop();
1714 void CGavdpTimeout::ConstructL(CGAVDPStateMachine& aGAVDPStateMachine)
1716 CTimer::ConstructL();
1717 CActiveScheduler::Add(this);
1718 iGAVDPStateMachine = &aGAVDPStateMachine;
1722 CGavdpTimeout::CGavdpTimeout() : CTimer(EPriorityLow)
1727 void CGavdpTimeout::StartTimer(TTimeIntervalMicroSeconds32 aTimeInterval)
1729 Cancel(); //just in case
1730 After(aTimeInterval);
1734 void CGavdpTimeout::RunL()
1736 //the GAVDP callback has timed out - check the GAVDP state machine
1737 //is in the connected state to cover ourselves in the event of a race
1739 if ((iGAVDPStateMachine->State() == TGAVDPState::EConnectedToGavdp)||
1740 (iGAVDPStateMachine->State() == TGAVDPState::ESEPsDiscovered))
1742 iGAVDPStateMachine->CancelChangeState(KErrTimedOut);