sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "A2dpCodecUtilities.h" sl@0: #include "GavdpStateMachine.h" sl@0: sl@0: sl@0: /** sl@0: GAVDP State Machine Panics sl@0: **/ sl@0: enum TGavdpStateMachinePanic sl@0: { sl@0: EGavdpStateMachineBadState,//0 sl@0: EGavdpStateMachineBadConfigByRemoteHeadsetState,//1 sl@0: EGavdpStateMachineBadBTAddr,//2 sl@0: EGavdpStateMachineUnexpectedCallback,//3 sl@0: EGavdpStateMachineDataTypeMismatch//4 sl@0: }; sl@0: sl@0: sl@0: static void Panic(TGavdpStateMachinePanic aPanic) sl@0: // Panic client sl@0: { sl@0: _LIT(KGavdpStateMachinePanicName, "GAVDP State Mchn"); sl@0: User::Panic(KGavdpStateMachinePanicName, aPanic); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Utility function to map a bluetooth code to a standard SymbianOS code sl@0: Where a standard Symbian error code exists the error is mapped sl@0: to the standard code. Ideally all HCI, L2CAP, AVDTP, GAVDP errors sl@0: should be mapped to standard SymbianOS codes since bluetooth specific sl@0: error codes aren't meaningful in the multimedia domain sl@0: */ sl@0: static TInt ConvertToStandardSymbianOSError(TInt aError) sl@0: { sl@0: TInt error; sl@0: sl@0: switch (aError) sl@0: { sl@0: case KHCIErrorBase-EPageTimedOut://-6004 sl@0: error = KErrCouldNotConnect; sl@0: break; sl@0: case KHCIErrorBase-EAuthenticationFailure://-6005 sl@0: error = KErrCouldNotConnect; sl@0: break; sl@0: case KHCIErrorBase-EPairingNotAllowed: //-6024 sl@0: error = KErrCouldNotConnect; sl@0: break; sl@0: case KHCIErrorBase-ELMPResponseTimeout: //-6034 sl@0: error = KErrTimedOut; sl@0: break; sl@0: case KErrHCIConnectFailed: //-6304 sl@0: error = KErrCouldNotConnect; sl@0: break; sl@0: case KErrHCILinkDisconnection: //-6305 sl@0: error = KErrDisconnected; sl@0: break; sl@0: default: sl@0: error = aError; sl@0: break; sl@0: } sl@0: return error; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Creates CGAVDPStateMachine sl@0: sl@0: @internalComponent sl@0: @return CGAVDPStateMachine* sl@0: */ sl@0: CGAVDPStateMachine* CGAVDPStateMachine::NewL(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer) sl@0: { sl@0: CGAVDPStateMachine* self = new(ELeave) CGAVDPStateMachine(aGAVDPStateChangeObserver, aA2dpCodecSettings, aSocketServer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Constructor sl@0: [TODO] change default stereo mode to EMMFJoint when hardware has sufficient bandwidth sl@0: Note we make the AO priority one less than normal to give the AOs in GAVDP sl@0: preference sl@0: */ sl@0: CGAVDPStateMachine::CGAVDPStateMachine(MGAVDPStateChangeObserver& aGAVDPStateChangeObserver, CA2dpAudioCodecConfiguration& aA2dpCodecSettings, RSocketServ& aSocketServer) : CActive(EPriorityNormal-1), sl@0: iGAVDPStateChangeObserver(aGAVDPStateChangeObserver) ,iA2dpCodecSettings(aA2dpCodecSettings), iSocketServer(aSocketServer) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: sl@0: void CGAVDPStateMachine::ConstructL() sl@0: { sl@0: User::LeaveIfError(iGavdp.Open(*this, iSocketServer)); sl@0: User::LeaveIfError(RegisterLocalSEP()); sl@0: iSignallingTransactionTimeout = CGavdpTimeout::NewL(*this); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to register local SEPs with GAVDP sl@0: The function sets the iSymbianDeviceSEID to the TSEID sl@0: of the Symbian device sl@0: */ sl@0: TInt CGAVDPStateMachine::RegisterLocalSEP() sl@0: { sl@0: //register SEPs - currently SBC & mp3 SEPs are supported sl@0: TAvdtpSEPInfo avdtpSEPInfo; sl@0: avdtpSEPInfo.SetInUse(EFalse); sl@0: avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio); sl@0: avdtpSEPInfo.SetIsSink(EFalse); sl@0: TInt err = iGavdp.RegisterSEP(avdtpSEPInfo); sl@0: TUsableSEP sep; sl@0: sep.iSEID = avdtpSEPInfo.SEID(); sl@0: sep.iDataType = KMMFFourCCCodeSBC; sl@0: err = iSymbianDeviceSEPs.Append(sep); sl@0: sl@0: if (!err) sl@0: { sl@0: avdtpSEPInfo.SetInUse(EFalse); sl@0: avdtpSEPInfo.SetMediaType(EAvdtpMediaTypeAudio); sl@0: avdtpSEPInfo.SetIsSink(EFalse); sl@0: err = iGavdp.RegisterSEP(avdtpSEPInfo); sl@0: if (!err) sl@0: { sl@0: sep.iSEID = avdtpSEPInfo.SEID(); sl@0: sep.iDataType = KMMFFourCCCodeMP3; sl@0: err = iSymbianDeviceSEPs.Append(sep); sl@0: } sl@0: } sl@0: if (!err) sl@0: { sl@0: TBool SEPDataTypeFound(EFalse); sl@0: for(TUint i = 0; i< iSymbianDeviceSEPs.Count();i++) sl@0: { sl@0: if (iSymbianDeviceSEPs[i].iDataType == iA2dpCodecSettings.HeadsetCodecDataType()) sl@0: { sl@0: iSymbianDeviceSEID = iSymbianDeviceSEPs[i].iSEID; sl@0: SEPDataTypeFound = ETrue; sl@0: break; sl@0: } sl@0: } sl@0: if (!SEPDataTypeFound) sl@0: { sl@0: err = KErrNotFound; sl@0: } sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Standard destructor. sl@0: */ sl@0: CGAVDPStateMachine::~CGAVDPStateMachine() sl@0: { sl@0: Cancel(); sl@0: iBearerSocket.Close(); sl@0: iGavdp.Close(); sl@0: iPotentialSEPs.Close(); sl@0: iUsableSEPs.Close(); sl@0: iSymbianDeviceSEPs.Close(); sl@0: iSEPCapabilities.ResetAndDestroy(); sl@0: iSEPCapabilities.Close(); sl@0: delete iSignallingTransactionTimeout; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to set the Bluetooth address of the headset. sl@0: sl@0: @param aRemoteAddress Bluetooth address of the headset sl@0: */ sl@0: void CGAVDPStateMachine::SetBTAddress(const TBTDevAddr& aRemoteAddress) sl@0: { sl@0: if (iBTDevAddr != aRemoteAddress) sl@0: {//must be using a new headet so reset state machine sl@0: Reset(); sl@0: iBTDevAddr = aRemoteAddress; sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to returns the current state of the GAVDP state machine. sl@0: sl@0: @return the current state of the GAVDP state machine sl@0: */ sl@0: TGAVDPState CGAVDPStateMachine::State() const sl@0: { sl@0: return iCurrentState ; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to resets the GAVDP state machine to the EGAVDPIdle state sl@0: Note that if the headset is already connected Reseting sl@0: will cause a subsequent call to RGavdp.Connect, however sl@0: if we are already connected this should complete straight away sl@0: sl@0: Note we don't close the bearer socket here as we need to ensure sl@0: this is closed after the RTP streamer is deleted so this is handled by the CA2dpBTHeadsetAudioInterface sl@0: */ sl@0: void CGAVDPStateMachine::Reset() sl@0: { sl@0: iPotentialSEPs.Reset(); sl@0: iUsableSEPs.Reset(); sl@0: iSEPCapabilities.ResetAndDestroy(); sl@0: iSEPIterator = 0; sl@0: iSEPCapabilityEntry = 0; sl@0: iA2dpCodecSettings.Reset(); sl@0: iInitialState = TGAVDPState::EGAVDPIdle; sl@0: iCurrentState = TGAVDPState::EGAVDPIdle; sl@0: iNextState = TGAVDPState::EGAVDPIdle; sl@0: iTargetState = TGAVDPState::EGAVDPIdle; sl@0: iConfigurationByRemoteHeadsetState.Reset(); sl@0: iHeadsetSEID.Reset(); sl@0: iLocalSEPConfigured = EFalse; sl@0: iChangeOfSelectedHeadsetSEP = EFalse; sl@0: iGavdp.Cancel(); sl@0: iSignallingTransactionTimeout->Cancel(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to move the GAVDP state machine to the state specified in aNewState sl@0: Not all state changes are allowed, however. sl@0: Permitted state changes are anystate to ->EGAVDPIdle,EConnectedToGavdp,ESEPsDiscovered sl@0: which causes a reset. sl@0: Anything prior to EGAVDPOpen->EGAVDPOpen sl@0: EGAVDPOpen->EGAVDPStreaming sl@0: EGAVDPStreaming->EGAVDPOpen sl@0: sl@0: When the state change is completed a GAVDPStateChangeComplete callback is sl@0: made on the MGAVDPStateChangeObserver, which is the CA2dpBTHeadsetAudioInterface sl@0: sl@0: @param aNewState The state we wish to go to sl@0: @return standard SymbianOS error code sl@0: */ sl@0: TInt CGAVDPStateMachine::ChangeState(const TGAVDPState& aNewState) sl@0: { sl@0: if (iStateChangeInProgress) sl@0: {//can't change state if a state change is already in progress sl@0: return KErrNotReady; sl@0: } sl@0: if (aNewState.State()<= TGAVDPState::ESEPSelected) sl@0: { sl@0: //if the state is ESEPSelected or less then sl@0: //the assumption is we need to reselect the SEP and in sl@0: //effect redo the entire initialization prior to selecting the SEP sl@0: //therefore roll back to EGAVDPIdle and reset. sl@0: Reset(); sl@0: } sl@0: else if (aNewState == TGAVDPState::EGAVDPStreaming) sl@0: { sl@0: //must be in the EGAVDPOpen state in order to go to EGAVDPStreaming sl@0: if (iCurrentState != TGAVDPState::EGAVDPOpen) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: } sl@0: sl@0: if (aNewState == iCurrentState) sl@0: { sl@0: //then we are already in the requested state so don't move to sl@0: //next state- so just call the RunL and complete sl@0: iStateChangeInProgress = EFalse;//we're not going to change the state sl@0: TRequestStatus* stat = &iStatus; sl@0: if (!IsActive()) sl@0: { sl@0: User::RequestComplete(stat, KErrNone); sl@0: SetActive(); sl@0: } sl@0: } sl@0: else sl@0: {//need to move to the next state sl@0: iInitialState = iCurrentState; //incase we need to wind back if state change fails sl@0: iTargetState = aNewState; sl@0: NextState(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to cause a reconfiguration of the SEP. The function determines sl@0: whether a reconfiguration is required ie becuase the settings have changed. sl@0: And if so the SEP is reconfigured or a new SEP is selected if the reconfiguration sl@0: results in a change of SEP ie because the datatype has changed sl@0: This function makes a GAVDPStateChangeComplete callback on the CA2dpBTHeadsetAudioInterface sl@0: If the SEP changes because of a change in data type then the iChangeOfSelectedHeadsetSEP sl@0: flag is set which is used by the state machine to cause the media transport sl@0: caps to be added to the SEP sl@0: sl@0: @param aSettingsHaveChanged set to ETrue if the settings have changed sl@0: sl@0: @return SymbianOS error code sl@0: */ sl@0: TInt CGAVDPStateMachine::Reconfigure(TBool aSettingsHaveChanged) sl@0: { sl@0: //not allowed to reconfigure in the middle of a state change sl@0: if ((iStateChangeInProgress)||(IsActive())) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: //in order to perform a reconfigure the current state must sl@0: //be either EConfigured or EGAVDPOpen sl@0: //reconfiguration by the SymbianOs device in the streaming state is not supported sl@0: //in this implementation even though it is allowed by the GAVDP profile sl@0: if ((iCurrentState != TGAVDPState::EConfigured) && sl@0: (iCurrentState != TGAVDPState::EGAVDPOpen)) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: __ASSERT_DEBUG((iCurrentState == iTargetState), Panic(EGavdpStateMachineBadState));//this should always be true if no state change is in progress sl@0: sl@0: iChangeOfSelectedHeadsetSEP = EFalse; sl@0: if (aSettingsHaveChanged) sl@0: {//then see if we need to change SEP sl@0: //data type has changed so we need to choose a different SEP sl@0: //and configure it sl@0: //note if no match is found then we go with the exiting sl@0: //selected SEP sl@0: for (TUint i=0; iCategory()) sl@0: { sl@0: case EServiceCategoryMediaTransport: sl@0: { sl@0: TAvdtpMediaTransportCapabilities* mediaTransportCaps = static_cast(aCapability); sl@0: iConfigurationByRemoteHeadsetState.SetTransportCapsRequestedByRemoteHeadset(mediaTransportCaps); sl@0: } sl@0: break; sl@0: case EServiceCategoryMediaCodec: sl@0: { sl@0: TAvdtpMediaCodecCapabilities* codecCaps = static_cast(aCapability); sl@0: if (codecCaps->MediaType() != EAvdtpMediaTypeAudio) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec); sl@0: } sl@0: //we're only going to allow a reconfiguration for SBC sl@0: if ((codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCCodeSBC)) sl@0: { sl@0: TSBCCodecCapabilities* sbcCodecCapabilities = static_cast(codecCaps); sl@0: TSBCSamplingFrequencyBitmask samplingFreqBitMask = sbcCodecCapabilities->SamplingFrequencies(); sl@0: sl@0: //if the headset has already been configured then we don't allow a change sl@0: //of sampling frequency. This is because once the DevSound has been configured sl@0: //with a sampling frequency after the DevSound is initialized and hence sl@0: //the a2dpheadsetif is initialized, it is no longer possible to change the sample frequency sl@0: TBool headsetAlreadyConfigured(EFalse); sl@0: if ((iCurrentState.State() == TGAVDPState::EGAVDPOpen) || sl@0: (iCurrentState.State() == TGAVDPState::EGAVDPSuspended)) sl@0: { sl@0: headsetAlreadyConfigured = ETrue; sl@0: } sl@0: //only one bit of the sampling frequency mask should be set sl@0: //note we're using switch statements rather than if then else sl@0: //it makes it easier to pick up the case where we have an invalid sl@0: //value or more than one value has been set in the bit mask sl@0: switch (samplingFreqBitMask) sl@0: { sl@0: case E16kHz: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 16000)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency); sl@0: } sl@0: break; sl@0: case E32kHz: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 32000)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency); sl@0: } sl@0: break; sl@0: case E44100Hz: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 44100)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency); sl@0: } sl@0: break; sl@0: case E48kHz: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.SampleRate() != 48000)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedSamplingFrequency); sl@0: } sl@0: break; sl@0: default: sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidSamplingFrequency); sl@0: break; sl@0: } sl@0: TSBCChannelModeBitmask channelModeBitMask = sbcCodecCapabilities->ChannelModes(); sl@0: sl@0: //if the headset has already been configured then we don't allow a change sl@0: //of channels. This is because once the DevSound has been configured sl@0: //with a sampling frequency after the DevSound is initialized and hence sl@0: //the a2dpheadsetif is initialized, it is no longer possible to change the number of channels sl@0: switch (channelModeBitMask) sl@0: { sl@0: case EMono: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFMono)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode); sl@0: } sl@0: break; sl@0: case EDualChannel: //we don't support dual channel sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode); sl@0: break; sl@0: case EStereo: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode); sl@0: } sl@0: break; sl@0: case EJointStereo: sl@0: if ((headsetAlreadyConfigured) && (iA2dpCodecSettings.Channels() != EMMFStereo)) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedChannelMode); sl@0: } sl@0: break; sl@0: default: sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidChannelMode); sl@0: break; sl@0: } sl@0: sl@0: TSBCBlockLengthBitmask blockLengthBitMask = sbcCodecCapabilities->BlockLengths(); sl@0: sl@0: switch (blockLengthBitMask) sl@0: { sl@0: case EBlockLenFour: sl@0: break; sl@0: case EBlockLenEight: sl@0: break; sl@0: case EBlockLenTwelve: sl@0: break; sl@0: case EBlockLenSixteen: sl@0: break; sl@0: default: sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidBlockLength); sl@0: break; sl@0: } sl@0: sl@0: TSBCSubbandsBitmask subbandsBitMask = sbcCodecCapabilities->Subbands(); sl@0: sl@0: TUint subbands = 0; sl@0: switch (subbandsBitMask) sl@0: { sl@0: case EFourSubbands: sl@0: subbands = 4; sl@0: break; sl@0: case EEightSubbands: sl@0: subbands = 8; sl@0: break; sl@0: default: sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidSubbands); sl@0: break; sl@0: } sl@0: sl@0: TSBCAllocationMethodBitmask allocationMethodBitMask = sbcCodecCapabilities->AllocationMethods(); sl@0: sl@0: switch (allocationMethodBitMask) sl@0: { sl@0: case ELoudness: sl@0: break; sl@0: case ESNR: sl@0: break; sl@0: default: sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidAllocationMethod); sl@0: break; sl@0: } sl@0: sl@0: TInt bitPoolValue = sbcCodecCapabilities->MinBitpoolValue(); sl@0: sl@0: if (bitPoolValue < KMinBitPoolValue) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidMinimumBitPoolValue); sl@0: } sl@0: sl@0: bitPoolValue = sbcCodecCapabilities->MaxBitpoolValue(); sl@0: sl@0: //The bitpool value must be in the range of 2-250 and must not exceed sl@0: // 16*numberOfSubbands*channels sl@0: if ((bitPoolValue > KMaxBitPoolValue)||(bitPoolValue > (16*subbands*iA2dpCodecSettings.Channels()))) sl@0: { sl@0: err = ConvertToSymbianError::A2dpError(EA2dpInvalidMaximumBitPoolValue); sl@0: } sl@0: if (!err) sl@0: {//note ownership of codecCaps is transferred sl@0: iConfigurationByRemoteHeadsetState.SetCodecConfigRequestedByRemoteHeadset(codecCaps); sl@0: } sl@0: }//if (codecCaps->MediaCodecType() == EAudioCodecSBC) && (iA2dpCodecSettings.HeadsetCodecDataType() == KMMFFourCCodeSBC)) sl@0: else sl@0: {//only support SBC for now sl@0: err = ConvertToSymbianError::A2dpError(EA2dpNotSupportedCodec); sl@0: } sl@0: } sl@0: break; //case EServiceCategoryMediaCodec: sl@0: default: // switch(aCapability->Category()) sl@0: err = KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: if (err) sl@0: { sl@0: iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed; sl@0: if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle)) sl@0: {//we only abort if the remote headset has not been configured sl@0: //need to abort using SEID of remote headset - this resets config at remote headset sl@0: Cancel(); //probably not necessary - but just in case sl@0: iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset()); sl@0: } sl@0: //else sl@0: //config is a reconfig in suspend streams sl@0: //wait on a Start_Indication if the headset is ok with the existing config sl@0: //or an Abort_Indication if the headset is not sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /* sl@0: MGavdpUser callback to indicate to the SymbianOS device that all the GAVDP_ConfigurationIndications sl@0: have been sent. sl@0: This callback should only occur if there have been no errored GAVDP_ConfigurationIndications sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: TInt CGAVDPStateMachine::GAVDP_ConfigurationEndIndication() sl@0: { sl@0: //the underlying GAVDP/AVDTP code should ensure that this sl@0: //callback from GAVDP never occurs once the headset has been configured sl@0: __ASSERT_DEBUG((iCurrentState.State() != TGAVDPState::EGAVDPStreaming), Panic(EGavdpStateMachineUnexpectedCallback)); sl@0: __ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart, Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState)); sl@0: sl@0: TInt err = KErrNone; sl@0: sl@0: TAvdtpMediaCodecCapabilities* configRequestedByRemoteHeadset = iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset(); sl@0: if (configRequestedByRemoteHeadset) sl@0: { sl@0: __ASSERT_DEBUG(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset().IsValid(), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState)); sl@0: sl@0: //the headset settings have been accepted so use the headset settings sl@0: //the only usable SEP shall be the once specified by the headset sl@0: //for now this will always be SBC sl@0: TUsableSEP SEP; sl@0: SEP.iSEID = iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset(); sl@0: TFourCC dataTypeSupport; sl@0: switch (configRequestedByRemoteHeadset->MediaCodecType()) sl@0: { sl@0: case EAudioCodecSBC: sl@0: dataTypeSupport.Set(KMMFFourCCCodeSBC); sl@0: break; sl@0: case EAudioCodecMPEG12Audio: sl@0: dataTypeSupport.Set(KMMFFourCCCodeMP3); sl@0: break; sl@0: case EAudioCodecMPEG24AAC: sl@0: dataTypeSupport.Set(KMMFFourCCCodeAAC); sl@0: break; sl@0: case EAudioCodecATRAC: sl@0: dataTypeSupport.Set(KMMFFourCCCodeATRAC3); sl@0: break; sl@0: default://should never get here sl@0: Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState); sl@0: break; sl@0: } sl@0: SEP.iDataType.Set(dataTypeSupport); sl@0: iUsableSEPs.Reset(); sl@0: err = iUsableSEPs.Append(SEP); sl@0: sl@0: //the only service capabilities are codec caps provided by the headset and transport sl@0: if (!(iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*configRequestedByRemoteHeadset))) sl@0: { sl@0: err = KErrNoMemory; sl@0: } sl@0: if (!err) sl@0: { sl@0: iSEPCapabilities.ResetAndDestroy(); sl@0: err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.TransportCapsRequestedByRemoteHeadset()); sl@0: if (!err) sl@0: { sl@0: err = iSEPCapabilities.Append(iConfigurationByRemoteHeadsetState.CodecConfigRequestedByRemoteHeadset()); sl@0: } sl@0: } sl@0: }// if (codecCaps) sl@0: sl@0: if (!err) sl@0: { sl@0: if ((iStateChangeInProgress) && (iInitialState.State() == TGAVDPState::EGAVDPIdle)) sl@0: {//the headset configured us during an a2dpheadsetif Initialize() sl@0: //we're now configured so now wait for GAVDP_Bearer ready sl@0: iCurrentState == TGAVDPState::EConfigured; sl@0: } sl@0: else if (iCurrentState == TGAVDPState::EGAVDPSuspended) sl@0: { sl@0: //we have reconfigured so the SBC codec needs reconfiguring sl@0: err = iGAVDPStateChangeObserver.GAVDPStateMachineReconfigureByRemoteHeadset(); sl@0: } sl@0: } sl@0: if (err) sl@0: { sl@0: if ((iCurrentState.State() < TGAVDPState::EConfigured) && (iCurrentState.State() != TGAVDPState::EGAVDPIdle)) sl@0: {//we only abort if the remote headset has not been configured sl@0: //need to abort using SEID of remote headset - this resets config at remote headset sl@0: Cancel(); //probably not necessary - but just in case sl@0: iGavdp.AbortStream(iConfigurationByRemoteHeadsetState.SEPRequestedByRemoteHeadset()); sl@0: } sl@0: } sl@0: //else sl@0: //config is a reconfig in suspend streams sl@0: //wait on a Start_Indication if the headset is ok with the existing config sl@0: //or an Abort_Indication if the headset is not sl@0: iConfigurationByRemoteHeadsetState = TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationEnd; sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback to indicate to the SymbianOS device that it has started streaming sl@0: There are two circumstances we can get a start indication sl@0: 1) The headset can request to start the streams itself once we are in the open state sl@0: 2) The headset can request a restart after suspending the streams eg to perform a reconfiguration sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: TInt CGAVDPStateMachine::GAVDP_StartIndication(TSEID aSEID) sl@0: { sl@0: __ASSERT_DEBUG((iCurrentState.State() == TGAVDPState::EGAVDPOpen) || sl@0: (iCurrentState.State() == TGAVDPState::EGAVDPSuspended), Panic(EGavdpStateMachineUnexpectedCallback)); sl@0: __ASSERT_DEBUG((iConfigurationByRemoteHeadsetState.State() != TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationStart),Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState)); sl@0: //first check the callback is for the symbian device SEP we are using to sl@0: //send data to the a2dp headset - incase the Symbian device has more than one SEP sl@0: if (aSEID == iSymbianDeviceSEID) sl@0: { sl@0: if (iCurrentState.State() == TGAVDPState::EGAVDPOpen) sl@0: { sl@0: if (iStateChangeInProgress) sl@0: { sl@0: if (iTargetState.State() == TGAVDPState::EGAVDPStreaming) sl@0: { sl@0: //a EGAVDPOpen->Streaming transistion sl@0: //which has been completed for us by the headset sl@0: Cancel(); sl@0: iGavdp.Cancel(); sl@0: iCurrentState = TGAVDPState::EGAVDPStreaming; sl@0: StateChangeComplete(); sl@0: } sl@0: //else only other state change would be open->idle sl@0: //this is unlikely/impossible if we get a GAVDP_StartIndication sl@0: //do nothing sl@0: } sl@0: else sl@0: { sl@0: //note if no state change is in progress then the headset itself sl@0: //has put itself in the streaming state sl@0: //normally we put the headset in the streaming state sl@0: //when we call OpenDevice() on the a2dpaudioif sl@0: //but if the headset does this then it is no longer possible sl@0: //for the client to change the audio settings sl@0: iCurrentState = TGAVDPState::EGAVDPStreaming; sl@0: } sl@0: }//(iCurrentState.State() == TGAVDPState::EGAVDPOpen) sl@0: else if (iCurrentState.State() == TGAVDPState::EGAVDPSuspended) sl@0: {//most probably restarting after a reconfigure sl@0: iCurrentState = TGAVDPState::EGAVDPStreaming; sl@0: iGAVDPStateChangeObserver.GAVDPStateMachineStreamResumedByRemoteHeadset(); sl@0: } sl@0: }//if (aSEID == iSymbianDeviceSEID) sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback to indicate to the SymbianOS device that the request to abort the headset sl@0: which means it is not configured has completed sl@0: Can request an abort stream if headset configuration fails sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_AbortStreamConfirm() sl@0: { sl@0: //if abort stream was caused by aborting the headset in response sl@0: //to a headset configuration in GAVDP_ConfigurationIndication sl@0: //then restart state machine from EConnectedToGavdp sl@0: if (iConfigurationByRemoteHeadsetState.State() == TConfigurationByRemoteHeadsetState::ERemoteHeadsetConfigurationFailed) sl@0: {//then the abort was caused an aborted configuration from the headset sl@0: __ASSERT_DEBUG((iCurrentState.State() < TGAVDPState::EConfigured), Panic(EGavdpStateMachineUnexpectedCallback)); sl@0: sl@0: //since we only aborted if the headset was not yet configured sl@0: //there must be a state change in progress and since we cancelled sl@0: //the GAVDPStateMachine should not be active sl@0: __ASSERT_DEBUG((iStateChangeInProgress) && (!IsActive()), Panic(EGavdpStateMachineBadConfigByRemoteHeadsetState)); sl@0: sl@0: iConfigurationByRemoteHeadsetState.Reset(); sl@0: //just to make extra sure we'll rediscover the SEPs sl@0: iPotentialSEPs.Reset(); sl@0: iUsableSEPs.Reset(); sl@0: iSEPCapabilities.ResetAndDestroy(); sl@0: iCurrentState = TGAVDPState::EConnectedToGavdp; sl@0: iNextState = TGAVDPState::EConnectedToGavdp; sl@0: iConfigurationByRemoteHeadsetState.Reset(); sl@0: iA2dpCodecSettings.Reset(); sl@0: iHeadsetSEID.Reset(); sl@0: iBearerSocket.Close(); sl@0: iLocalSEPConfigured = EFalse; sl@0: iChangeOfSelectedHeadsetSEP = EFalse; sl@0: iSignallingTransactionTimeout->Cancel(); sl@0: NextState(); sl@0: } sl@0: iConfigurationByRemoteHeadsetState.Reset(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback to indicate to the SymbianOS device that the headset has aborted sl@0: ie it can no longer be regarded as configured sl@0: This makes a GAVDPStateMachineEvent MGAVDPStateChangeObserver callback on the CA2dpBTHeadsetAudioInterface sl@0: (which inturn will cause a Reset on the GAVDP state machine) sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_AbortIndication(TSEID aSEID) sl@0: { sl@0: //first check the callback is for the symbian device SEP we are using to sl@0: //send data to the a2dp headset - incase the Symbian device has more than one SEP sl@0: if (aSEID == iSymbianDeviceSEID) sl@0: { sl@0: if (iStateChangeInProgress) sl@0: { sl@0: CancelChangeState(KErrAbort); sl@0: } sl@0: else sl@0: { sl@0: iGAVDPStateChangeObserver.GAVDPStateMachineEvent(KErrAbort); sl@0: } sl@0: } sl@0: //else not much we can do it aSEID isn't the Symbian device ID sl@0: iConfigurationByRemoteHeadsetState.Reset(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to initiate the discovery of the headset SEPs sl@0: Note that the SEP discovery does not have a built in timeout sl@0: so the GAVDP_SEPDiscovered callback must occur withing the GAVDP callback timeout 30s sl@0: or the state change will be cancelled with KErrTimedOut sl@0: */ sl@0: void CGAVDPStateMachine::DiscoverRemoteSEPs() sl@0: { sl@0: iPotentialSEPs.Reset(); sl@0: iGavdp.DiscoverRemoteSEPs(); sl@0: iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout)); sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback in response to DiscoverRemoteSEPs sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_SEPDiscovered(const TAvdtpSEPInfo& aSEP) sl@0: { sl@0: //check whether the SEP is suitable for connection sl@0: if ((!aSEP.InUse()) && (aSEP.MediaType() == EAvdtpMediaTypeAudio) && (aSEP.IsSink())) sl@0: {//the SEP is a potentialy suitable for connection sl@0: //so add to list of potential SEPs sl@0: TInt err = iPotentialSEPs.Append(aSEP.SEID()); sl@0: if (err) sl@0: { sl@0: CancelChangeState(err); sl@0: } sl@0: } sl@0: //else SEP is not suitable so ignore it sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_SEPDiscoveryComplete() sl@0: { sl@0: iSignallingTransactionTimeout->Cancel(); sl@0: if (iPotentialSEPs.Count()) sl@0: {//we have at least one potential SEP sl@0: StateChangeComplete(); sl@0: } sl@0: else sl@0: {//no potential SEPs were found so cannot proceed any further sl@0: CancelChangeState(KErrCouldNotConnect); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to get the capability of an individual SEP sl@0: */ sl@0: void CGAVDPStateMachine::GetRemoteSEPCapability() sl@0: { sl@0: TAvdtpServiceCategories serviceCategories; sl@0: serviceCategories.SetCapability(EServiceCategoryMediaTransport); sl@0: serviceCategories.SetCapability(EServiceCategoryMediaCodec); sl@0: TSEID SEPtoGetCapabilityOf = iPotentialSEPs[iSEPIterator]; sl@0: iGavdp.GetRemoteSEPCapabilities(SEPtoGetCapabilityOf, serviceCategories); sl@0: iSignallingTransactionTimeout->StartTimer(TTimeIntervalMicroSeconds32(KGAVDPCallbackTimeout)); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to iterate through the list of potential SEPs and asking sl@0: for the capabilites of each one. sl@0: */ sl@0: void CGAVDPStateMachine::GetRemoteSEPCapabilities() sl@0: { sl@0: iSEPCapabilities.ResetAndDestroy(); //clear what's already there sl@0: iUsableSEPs.Reset(); sl@0: iSEPIterator = 0; sl@0: iSEPCapabilityEntry = 0; sl@0: //go and get the capability of the first SEP in the list of potential SEPs sl@0: //the GAVDP_SEPCapabilityComplete() callback will cause the next potential sl@0: //SEP capability to be obtained. sl@0: GetRemoteSEPCapability(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback in response to GetRemoteSEPCapabilities sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_SEPCapability(TAvdtpServiceCapability* aCapability) sl@0: { sl@0: // we own cap, stash it in the iSEPCapabilities array for owning and later use sl@0: TInt err = iSEPCapabilities.Append(aCapability); sl@0: if (err) sl@0: { sl@0: CancelChangeState(err); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback in response to GetRemoteSEPCapabilities when all the sl@0: GAVDP_SEPCapability callbacks have been made for an individual SEP sl@0: sl@0: The function iterates through the SEP capabilites looking for transport and media codec support sl@0: and if so the SEP is added to the list of usableSEPs. sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_SEPCapabilityComplete() sl@0: { sl@0: TInt err = KErrNone; sl@0: iSignallingTransactionTimeout->Cancel(); sl@0: //iterate through the capabilities sl@0: TAvdtpServiceCapability* avdtpServiceCapability; sl@0: TBool mediaTransport(EFalse); sl@0: TBool audioSupport(EFalse); sl@0: TFourCC dataTypeSupport; //note we are assuming here that each SEP only has one codec capability sl@0: TUint i = 0; sl@0: //iterate through the capabilities sl@0: //looking for media transport and codec support sl@0: for (;iSEPCapabilityEntry < iSEPCapabilities.Count() ; iSEPCapabilityEntry++) sl@0: { sl@0: avdtpServiceCapability = iSEPCapabilities[iSEPCapabilityEntry]; sl@0: switch (avdtpServiceCapability->Category()) sl@0: { sl@0: case EServiceCategoryMediaTransport: sl@0: mediaTransport = ETrue; sl@0: break; sl@0: case EServiceCategoryMediaCodec: sl@0: { sl@0: TAvdtpMediaCodecCapabilities* codecCaps = static_cast(avdtpServiceCapability); sl@0: if (codecCaps->MediaType() == EAvdtpMediaTypeAudio) sl@0: { sl@0: audioSupport = ETrue; sl@0: } sl@0: switch (codecCaps->MediaCodecType()) sl@0: { sl@0: case EAudioCodecSBC: sl@0: dataTypeSupport.Set(KMMFFourCCCodeSBC); sl@0: break; sl@0: case EAudioCodecMPEG12Audio: sl@0: dataTypeSupport.Set(KMMFFourCCCodeMP3); sl@0: break; sl@0: case EAudioCodecMPEG24AAC: sl@0: dataTypeSupport.Set(KMMFFourCCCodeAAC); sl@0: break; sl@0: case EAudioCodecATRAC: sl@0: dataTypeSupport.Set(KMMFFourCCCodeATRAC3); sl@0: break; sl@0: default: sl@0: //the datatype is an unsupported datatype sl@0: //so set to NULL to show we can't use it sl@0: dataTypeSupport.Set(KMMFFourCCCodeNULL); sl@0: break; sl@0: } sl@0: } sl@0: }//switch (avdtpServiceCapability->Category()) sl@0: }// for (TUint i=0; i++; i= iPotentialSEPs.Count()) sl@0: {//then we have finished getting all the capabilities sl@0: //so lets choose a SEP by iterating through the sl@0: //usable SEPs and stopping at the first one that supports the sl@0: //required data type sl@0: TUsableSEP SEP; sl@0: TBool SEPFound(EFalse); sl@0: for (i=0; i= iSEPIterator) sl@0: else sl@0: {//get the capability of the next SEP sl@0: GetRemoteSEPCapability(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function used to return a TAvdtpMediaCodecCapabilities structure sl@0: that can be used to configure the SEP at the remote end ie on the headset sl@0: The capabilities are used to determine the configuration sl@0: need to return by pointer rather than by ref as TAvdtpMediaCodecCapabilities is abstract sl@0: */ sl@0: TAvdtpMediaCodecCapabilities* CGAVDPStateMachine::RemoteCodecConfiguration() sl@0: { sl@0: TAvdtpMediaCodecCapabilities* codecCaps = NULL; sl@0: TAvdtpMediaCodecCapabilities* codecConfiguration = NULL; sl@0: sl@0: //first get the capabilities of the codec sl@0: TInt error = CodecCaps(codecCaps); sl@0: if (!error) sl@0: {//and use the capabilities to get a valid remote codec configuration sl@0: codecConfiguration = iA2dpCodecSettings.UpdateRemoteCodecConfiguration(*codecCaps); sl@0: } sl@0: sl@0: return codecConfiguration; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to configure the local SEP sl@0: */ sl@0: TInt CGAVDPStateMachine::ConfigureLocalSEP() sl@0: { sl@0: TInt err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID); sl@0: if (err == KErrNotFound) sl@0: { sl@0: //could be a problem with the local SEP no longer being registered sl@0: //so register and try again sl@0: err = RegisterLocalSEP(); sl@0: if (!err) sl@0: { sl@0: err = iGavdp.BeginConfiguringLocalSEP(iSymbianDeviceSEID); sl@0: } sl@0: } sl@0: if (!err) sl@0: {//configure local SEP - we only advertise one local SEP with SBC support sl@0: //in future when capability structures are defined for mp3,AAC,ATRAC3 sl@0: //then these can also be advertised as local SEPs sl@0: TAvdtpMediaTransportCapabilities media; sl@0: err = iGavdp.AddSEPCapability(media); sl@0: sl@0: if (!err) sl@0: { sl@0: CA2dpLocalCodecCapabilities* localCodecCapabilities = NULL; sl@0: TRAP(err, localCodecCapabilities = CA2dpLocalCodecCapabilities::NewL()) sl@0: if (!err) sl@0: { sl@0: TAvdtpMediaCodecCapabilities* localSEPCapability = localCodecCapabilities->LocalCodecCapabilities(iA2dpCodecSettings.HeadsetCodecDataType()); sl@0: if (localSEPCapability) sl@0: { sl@0: err = iGavdp.AddSEPCapability(*localSEPCapability); sl@0: } sl@0: else sl@0: { sl@0: err = KErrNoMemory; sl@0: } sl@0: delete localCodecCapabilities; sl@0: localCodecCapabilities = NULL; sl@0: } sl@0: } sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to configure the remote SEP ie the headset sl@0: sl@0: If the SEP has never been configured before then the transport caps are added sl@0: If we are doing a reconfigure of the remote SEP then just the codec caps are added sl@0: */ sl@0: TInt CGAVDPStateMachine::ConfigureRemoteSEP() sl@0: { sl@0: TInt err = iGavdp.BeginConfiguringRemoteSEP(iHeadsetSEID, iSymbianDeviceSEID); sl@0: if (!err) sl@0: { sl@0: if ((iInitialState.State() < TGAVDPState::EConfigured)||(iChangeOfSelectedHeadsetSEP)) sl@0: {//then this SEP has never been configured before sl@0: //in which case we need to configure it with transport capabilities sl@0: //note that if the SEP has been configured before ie the above condition sl@0: //is false then we are performing a reconfiguration and are not allowed sl@0: //to reconfigure the media transport capabilities sl@0: TAvdtpMediaTransportCapabilities avdtpMediaTransportCapabilities; sl@0: err = iGavdp.AddSEPCapability(avdtpMediaTransportCapabilities); sl@0: iChangeOfSelectedHeadsetSEP = EFalse;//reset sl@0: } sl@0: if (!err) sl@0: { sl@0: TAvdtpMediaCodecCapabilities* codecConfiguration = RemoteCodecConfiguration(); sl@0: //note we are setting a configuration here not a capability sl@0: if (codecConfiguration) sl@0: { sl@0: err = iGavdp.AddSEPCapability(*codecConfiguration); sl@0: } sl@0: else sl@0: {//we were not able to get a valid configuration sl@0: //so abort configuration sl@0: err = KErrAbort; sl@0: } sl@0: }// if (!err) sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to initiate SEP configuration of both the local and remote SEPs sl@0: */ sl@0: void CGAVDPStateMachine::ConfigureSEP() sl@0: { sl@0: if (iHeadsetSEID.IsValid()) sl@0: { sl@0: TInt err; sl@0: if (!iLocalSEPConfigured) sl@0: {//the local SEP must be configured first before configuring the remote SEP sl@0: err = ConfigureLocalSEP(); sl@0: } sl@0: else sl@0: {//local SEP is already configured so configure remote SEP sl@0: err = ConfigureRemoteSEP(); sl@0: } sl@0: if (err) sl@0: { sl@0: CancelChangeState(err); sl@0: } sl@0: else sl@0: { sl@0: iGavdp.CommitSEPConfiguration(); sl@0: } sl@0: } sl@0: else sl@0: {//we've requested to configure a SEP before we have sl@0: //a valid SEP to configure sl@0: CancelChangeState(KErrNotReady); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback to confirm that the SEP configuration has been acepted sl@0: This callback should occur for both the local SEP and the remote SEP sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_ConfigurationConfirm() sl@0: { sl@0: TInt err = KErrNone; sl@0: if (!iLocalSEPConfigured) sl@0: {//the local SEP is configured first so this call back must be from sl@0: //a local SEP configuration sl@0: iLocalSEPConfigured = ETrue; sl@0: //now configure the remote SEP sl@0: err = ConfigureRemoteSEP(); sl@0: if (!err) sl@0: { sl@0: iGavdp.CommitSEPConfiguration(); sl@0: } sl@0: else sl@0: { sl@0: CancelChangeState(err); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: //local and remote SEPs now configured sl@0: TInt err = iGavdp.Listen(); sl@0: //note that if there is an error above sl@0: // there is not much we can do so ignore it sl@0: StateChangeComplete(); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to request a bearer RSocket in order to stream audio to the headset sl@0: */ sl@0: void CGAVDPStateMachine::CreateBearerSocket() sl@0: { sl@0: //then we need to request for one from the remote SEP sl@0: //this reference code does not support reporting and recovery channels sl@0: sl@0: if (!iBearerSocket.SubSessionHandle()) sl@0: {//we don't already have a bearer socket, create one - note no reporting and recovery implementation sl@0: TInt err = iGavdp.CreateBearerSockets(iHeadsetSEID, EFalse, EFalse); sl@0: if (err) sl@0: { sl@0: CancelChangeState(err); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: //we already have a bearer socket so no need to create a new one sl@0: //just complete the state change sl@0: StateChangeComplete(); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: MGavdpUser callback to supply the RSocket used to stream audio to the headset sl@0: sl@0: This callback can occur either via a direct request from the headset or in response sl@0: to a CreateBearerSocket sl@0: sl@0: @see MGavdpUser sl@0: */ sl@0: void CGAVDPStateMachine::GAVDP_BearerReady(RSocket aSocket, const TAvdtpSockAddr& /*aAddress*/) sl@0: { sl@0: //This call back can occur without a prior call to CreateBearerSocket sl@0: iBearerSocket = aSocket; sl@0: if ((iCurrentState == TGAVDPState::EConfigured)&&(iStateChangeInProgress)) sl@0: {//we've completed the state sl@0: StateChangeComplete(); sl@0: } sl@0: // else this came from the headset without a call to RGavdp::CreateBearerSockets sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to return an array of usable SEPs on the headset. sl@0: By 'usable' we mean the SEP supports audio, has media transport caps, is not in use, sl@0: has a supported audio codec and the audio codec is supported by the symbianOS device sl@0: @return array of usable SEPs sl@0: */ sl@0: RArray& CGAVDPStateMachine::UsableSEPs() const sl@0: { sl@0: return const_cast&>(iUsableSEPs); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to return the bearer socket used to stream audio to the headset sl@0: @return socket sl@0: */ sl@0: RSocket& CGAVDPStateMachine::BearerSocket() const sl@0: { sl@0: return const_cast(iBearerSocket); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to return the headset BT address sl@0: @return headset BT address sl@0: */ sl@0: TBTDevAddr& CGAVDPStateMachine::BTAddress() const sl@0: { sl@0: return const_cast(iBTDevAddr); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Function to return the SEPCapability for the codec settings sl@0: used by CA2dpBTHeadsetAudioInterface to determine the audio settings sl@0: ie sample rate / stereo support. sl@0: aCodecCaps is set with the TAvdtpMediaCodecCapabilities of the codec in use sl@0: if no codec has been specified via the Reconfigure() function then sl@0: the codec defaults to SBC sl@0: returns KErrNotReady if no SEP capablities have been obtained from the SEP sl@0: return KErrNotSupported if the codec type is not known sl@0: aCodecCaps Note that ownership is not transferred to the calling class. sl@0: sl@0: @param aCodecCaps The pointer points to a codec capabilities structure sl@0: sl@0: @return SymbianOS error code sl@0: */ sl@0: TInt CGAVDPStateMachine::CodecCaps(TAvdtpMediaCodecCapabilities*& aCodecCaps) const sl@0: { sl@0: TInt err = KErrNotReady; sl@0: TAvdtpServiceCapability* avdtpServiceCapability; sl@0: TFourCC dataType; sl@0: for (TUint i=0; iCategory() == EServiceCategoryMediaCodec) sl@0: { sl@0: TAvdtpMediaCodecCapabilities* codecCaps = static_cast(avdtpServiceCapability); sl@0: switch (codecCaps->MediaCodecType()) sl@0: { sl@0: case EAudioCodecSBC: sl@0: dataType.Set(KMMFFourCCCodeSBC); sl@0: break; sl@0: case EAudioCodecMPEG12Audio: sl@0: dataType.Set(KMMFFourCCCodeMP3); sl@0: break; sl@0: case EAudioCodecMPEG24AAC: sl@0: dataType.Set(KMMFFourCCCodeAAC); sl@0: break; sl@0: case EAudioCodecATRAC: sl@0: dataType.Set(KMMFFourCCCodeATRAC3); sl@0: break; sl@0: default: sl@0: err = KErrNotSupported; sl@0: break; sl@0: } sl@0: if (dataType == iA2dpCodecSettings.HeadsetCodecDataType()) sl@0: {//then we have the capabilities for the selected datatype sl@0: aCodecCaps = codecCaps; sl@0: err = KErrNone; sl@0: break; sl@0: } sl@0: } sl@0: } //for (TUint i=0; iConstructL(aGAVDPStateMachine); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: void CGavdpTimeout::ConstructL(CGAVDPStateMachine& aGAVDPStateMachine) sl@0: { sl@0: CTimer::ConstructL(); sl@0: CActiveScheduler::Add(this); sl@0: iGAVDPStateMachine = &aGAVDPStateMachine; sl@0: } sl@0: sl@0: sl@0: CGavdpTimeout::CGavdpTimeout() : CTimer(EPriorityLow) sl@0: { sl@0: } sl@0: sl@0: sl@0: void CGavdpTimeout::StartTimer(TTimeIntervalMicroSeconds32 aTimeInterval) sl@0: { sl@0: Cancel(); //just in case sl@0: After(aTimeInterval); sl@0: } sl@0: sl@0: sl@0: void CGavdpTimeout::RunL() sl@0: { sl@0: //the GAVDP callback has timed out - check the GAVDP state machine sl@0: //is in the connected state to cover ourselves in the event of a race sl@0: //condition sl@0: if ((iGAVDPStateMachine->State() == TGAVDPState::EConnectedToGavdp)|| sl@0: (iGAVDPStateMachine->State() == TGAVDPState::ESEPsDiscovered)) sl@0: { sl@0: iGAVDPStateMachine->CancelChangeState(KErrTimedOut); sl@0: } sl@0: } sl@0: sl@0: sl@0: