diff -r 000000000000 -r f63038272f30 bluetoothengine/btaudioman/src/basrvaccstateattached.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btaudioman/src/basrvaccstateattached.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -0,0 +1,478 @@ +/* +* Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Implementation of Connected state. +* Version : %version: 20 % +* +*/ + + +// INCLUDE FILES +#include +#include +#include "basrvaccstateattached.h" +#include "basrvaccstateattach.h" +#include "basrvaccstatedetach.h" +#include "basrvaccstatedisconnect.h" +#include "BTAccInfo.h" +#include "debug.h" + +const TInt KRequestIdOpenMonoAudio = 40; +const TInt KRequestIdOpenStereoAudio = 41; +const TInt KRequestIdCloseMonoAudio = 42; +const TInt KRequestIdCloseStereoAudio = 43; +const TInt KRequestIdTimer = 44; +const TInt KRequestIdMonoActiveModeRequest = 45; +const TInt KRequestIdStereoActiveModeRequest = 46; +const TInt KRequestIdConnectRemConTG = 47; + +const TInt KAudioCloseResponseDelay = 1200000; // 1.2 sec + +// ================= MEMBER FUNCTIONS ======================= + +CBasrvAccStateAttached* CBasrvAccStateAttached::NewL(CBasrvAcc& aParent, TBool aShowNote) + { + CBasrvAccStateAttached* self=new(ELeave) CBasrvAccStateAttached(aParent, aShowNote); + return self; + } + +CBasrvAccStateAttached::~CBasrvAccStateAttached() + { + delete iRemConTGConnector; + delete iAudioOpener; + delete iAudioCloser; + delete iTimerActive; + iTimer.Close(); + TRACE_FUNC + } + +void CBasrvAccStateAttached::EnterL() + { + StatePrint(_L("Attached")); + iTimer.CreateLocal(); + if (AccInfo().iAudioOpenedProfiles) + { + if (AccInfo().iAudioOpenedProfiles & EStereo) + HandleAccOpenedAudio(EStereo); + if (AccInfo().iAudioOpenedProfiles & EHFP) + HandleAccOpenedAudio(EHFP); + if (AccInfo().iAudioOpenedProfiles & EHSP) + HandleAccOpenedAudio(EHSP); + } + else + { + Parent().RequestSniffMode(); + } + if (iShowNote) + { + Parent().AccMan().NotifyClientNewProfile(AccInfo().iConnProfiles, AccInfo().iAddr); + TInt callState; + TInt err = RProperty::Get(KPSUidCtsyCallInformation, KCTsyCallState, callState); + if(!err && (callState == EPSCTsyCallStateNone || callState == EPSCTsyCallStateUninitialized)) + { + Parent().AccMan().ShowNote(EBTConnected, AccInfo().iAddr); + } + } + } + +CBasrvAccState* CBasrvAccStateAttached::ErrorOnEntry(TInt /*aReason*/) + { + TRACE_FUNC + CBasrvAccState* next = NULL; + TRAP_IGNORE(next = CBasrvAccStateDetach::NewL(Parent())); + return next; + } + +TBTEngConnectionStatus CBasrvAccStateAttached::ConnectionStatus() const + { + return EBTEngConnected; + } + +void CBasrvAccStateAttached::ConnectL(const TBTDevAddr& aAddr) + { + if (aAddr == AccInfo().iAddr) + { + Parent().AccMan().ConnectCompletedL(AccInfo().iAddr, KErrNone, AccInfo().iConnProfiles); + } + else + { + CBasrvAccState::ConnectL(aAddr); + } + } + +void CBasrvAccStateAttached::DisconnectL() + { + TRACE_FUNC + Parent().AccMan().RemoveAudioRequest(AccInfo().iAddr); + + if (AccInfo().iAudioOpenedProfiles) + { + TAccAudioType type = (AccInfo().iAudioOpenedProfiles & EAnyMonoAudioProfiles) + ? EAccMonoAudio : EAccStereoAudio; + Parent().AccMan().AccfwConnectionL()->NotifyAudioLinkCloseL(AccInfo().iAddr, type); + AccInfo().iAudioOpenedProfiles = EUnknownProfile; + } + + Parent().ChangeStateL(CBasrvAccStateDetach::NewL(Parent())); + } + +void CBasrvAccStateAttached::AccessoryConnected(TProfiles aProfile) + { + TRACE_FUNC + CBasrvAccState::AccessoryConnected(aProfile); + Parent().NotifyLinkChange2Rvc(); + Parent().AccMan().NotifyClientNewProfile(aProfile, AccInfo().iAddr); + } + +void CBasrvAccStateAttached::AccOpenedAudio(TProfiles aProfile) + { + TRACE_FUNC + delete iTimerActive; + iTimerActive = NULL; + HandleAccOpenedAudio(aProfile); + } + +void CBasrvAccStateAttached::AccClosedAudio(TProfiles aProfile) + { + TRACE_FUNC + UpdateAudioState(EAudioLinkClosed, (aProfile == EStereo) ? EAccStereoAudio : EAccMonoAudio); + CBasrvAccState::AccClosedAudio(aProfile); + Parent().NotifyLinkChange2Rvc(); + iCloseAudioProfile = aProfile; + if (!iTimerActive) + { + iTimerActive = CBasrvActive::New(*this, CActive::EPriorityStandard, KRequestIdTimer); + } + if (iTimerActive) + { + iTimerActive->Cancel(); + iTimer.After(iTimerActive->iStatus, KAudioCloseResponseDelay); + iTimerActive->GoActive(); + } + Parent().RequestSniffMode(); + StatePrint(_L("Attached")); + } + +void CBasrvAccStateAttached::AccessoryDisconnectedL(TProfiles aProfile) + { + TRACE_FUNC + delete iTimerActive; + iTimerActive = NULL; + TInt audiolinkcache = AccInfo().iAudioOpenedProfiles; + if ((AccInfo().iAudioOpenedProfiles & EStereo) && (aProfile & EStereo)) + { + Parent().RequestSniffMode(); + } + ProfileDisconnected(aProfile); + CBasrvAccState::AccClosedAudio(aProfile); + Parent().NotifyLinkChange2Rvc(); + Parent().AccMan().NotifyClientNoProfile(aProfile, AccInfo().iAddr); + StatePrint(_L("Attached")); + + // AudioPolicy wants to get a notification about audio link closes before + // detaches as well so here we go + if (audiolinkcache & aProfile || + iCloseAudioProfile & aProfile ) + { + TAccAudioType type = (aProfile & EAnyMonoAudioProfiles) + ? EAccMonoAudio : EAccStereoAudio; + Parent().AccMan().AccfwConnectionL()->NotifyAudioLinkCloseL(AccInfo().iAddr, type); + + // let's clear this variable here to be sure it's not used twice accidentally + iCloseAudioProfile = EUnknownProfile; + } + + if (!(AccInfo().iConnProfiles & EAnyAudioProfiles)) + { + Parent().AccMan().RemoveAudioRequest(AccInfo().iAddr); + Parent().ChangeStateL(CBasrvAccStateDetach::NewL(Parent())); + } + + } + +void CBasrvAccStateAttached::OpenAudioL(TAccAudioType aType) + { + TRACE_FUNC + TInt requestId = (aType == EAccMonoAudio) + ? KRequestIdMonoActiveModeRequest : KRequestIdStereoActiveModeRequest; + if (!iAudioOpener) + { + iAudioOpener = CBasrvActive::NewL(*this, CActive::EPriorityLow, requestId); + } + else + { + if (iAudioOpener->IsActive()) + { + LEAVE(KErrAlreadyExists); + } + iAudioOpener->SetRequestId(requestId); + } + Parent().RequestActiveMode(); + + // here we'll give time to the scheduler so that the active mode request has + // a chance to get through before the audio link open request - running + // with EPriorityLow for that + TRequestStatus* myStatus( &iAudioOpener->iStatus ); + *myStatus = KRequestPending; + iAudioOpener->GoActive(); + User::RequestComplete( myStatus, KErrNone ); + } + +void CBasrvAccStateAttached::CloseAudioL(TAccAudioType aType) + { + TRACE_FUNC + + DoCloseAudioL(aType); + } + +void CBasrvAccStateAttached::RequestCompletedL(CBasrvActive& aActive) + { + TRACE_FUNC + TInt status = aActive.iStatus.Int(); + TInt requestid = aActive.RequestId(); + switch (requestid) + { + case KRequestIdOpenMonoAudio: + { + if (!status) + { + if (AccInfo().iSuppProfiles & EHFP) + NewProfileConnection(EHFP); + else + NewProfileConnection(EHSP); + } + TInt err = Parent().AccMan().OpenAudioCompleted(AccInfo().iAddr, EAccMonoAudio, status); + if ( (err && err != KErrAlreadyExists) || (status && status != KErrInUse && status != KErrAlreadyExists)) + { + if (Parent().AccMan().DisconnectIfAudioOpenFails()) + { + Parent().AccMan().RemoveAudioRequest(AccInfo().iAddr); + Parent().ChangeStateL(CBasrvAccStateDetach::NewL(Parent())); + } + } + else + { + UpdateAudioState(EAudioLinkOpen, EAccMonoAudio); + Parent().CancelPowerModeControl(); + AccInfo().iAudioOpenedProfiles |= (AccInfo().iConnProfiles & EAnyMonoAudioProfiles); + Parent().NotifyLinkChange2Rvc(); + } + break; + } + case KRequestIdCloseMonoAudio: + { + UpdateAudioState(EAudioLinkClosed, EAccMonoAudio); + Parent().RequestSniffMode(); + (void) Parent().AccMan().CloseAudioCompleted(AccInfo().iAddr, EAccMonoAudio, status); + break; + } + case KRequestIdOpenStereoAudio: + { + if (!status) + { + NewProfileConnection(EStereo); + } + TInt err = Parent().AccMan().OpenAudioCompleted(AccInfo().iAddr, EAccStereoAudio, status); + if ((status && status != KErrInUse && status != KErrAlreadyExists)) + { + if (status == KErrDisconnected) + { + ProfileDisconnected(EStereo); + } + if (Parent().AccMan().DisconnectIfAudioOpenFails()) + { + Parent().AccMan().RemoveAudioRequest(AccInfo().iAddr); + Parent().ChangeStateL(CBasrvAccStateDetach::NewL(Parent())); + } + } + else if (!err) + { + UpdateAudioState(EAudioLinkOpen, EAccStereoAudio); + Parent().PreventLowPowerMode(); + AccInfo().iAudioOpenedProfiles |= EStereo; + Parent().NotifyLinkChange2Rvc(); + DoConnectRemConCtIfNeededL(); + } + break; + } + case KRequestIdCloseStereoAudio: + { + UpdateAudioState(EAudioLinkClosed, EAccStereoAudio); + Parent().RequestSniffMode(); + (void) Parent().AccMan().CloseAudioCompleted(AccInfo().iAddr, EAccStereoAudio, status); + break; + } + case KRequestIdTimer: + { + TAccAudioType type = (iCloseAudioProfile & EAnyMonoAudioProfiles) + ? EAccMonoAudio : EAccStereoAudio; + Parent().AccMan().AccfwConnectionL()->NotifyAudioLinkCloseL(AccInfo().iAddr, type); + + // this variable needs to be cleared here so that the AccFW isn't notified a second time + // about the same audio link close during disconnection process + iCloseAudioProfile = EUnknownProfile; + break; + } + case KRequestIdMonoActiveModeRequest: + case KRequestIdStereoActiveModeRequest: + { + // the active mode request should have been scheduled at this point and we'll continue + // with audio link open request - going back to standard priority + TProfiles profile = ( requestid == KRequestIdMonoActiveModeRequest ) ? EHFP : EStereo; + Parent().AccMan().PluginMan().Plugin(profile)->OpenAudioLink(AccInfo().iAddr, + iAudioOpener->iStatus); + + TInt requestId = ( requestid == KRequestIdMonoActiveModeRequest ) + ? KRequestIdOpenMonoAudio : KRequestIdOpenStereoAudio; + iAudioOpener->SetPriority( CActive::EPriorityStandard ); + iAudioOpener->SetRequestId( requestId ); + iAudioOpener->GoActive(); + break; + } + case KRequestIdConnectRemConTG: + { + if (!status || status == KErrAlreadyExists) + { + NewProfileConnection(ERemConTG); + Parent().NotifyLinkChange2Rvc(); + } + delete iRemConTGConnector; + iRemConTGConnector = NULL; + break; + } + default: + { + } + } + } + +void CBasrvAccStateAttached::CancelRequest(CBasrvActive& aActive) + { + TRACE_FUNC + TInt request = aActive.RequestId(); + TAccAudioType type = (request == KRequestIdOpenMonoAudio || request == KRequestIdCloseMonoAudio ) ? + EAccMonoAudio : EAccStereoAudio; + TProfiles profile = (type == EAccMonoAudio) ? EAnyMonoAudioProfiles : EStereo; + CBTAccPlugin* plugin = Parent().AccMan().PluginMan().Plugin(profile); + if (request == KRequestIdOpenMonoAudio || request == KRequestIdOpenStereoAudio) + { + plugin->CancelOpenAudioLink(AccInfo().iAddr); + Parent().AccMan().OpenAudioCompleted(AccInfo().iAddr, type, KErrCancel); + } + else if (request == KRequestIdCloseMonoAudio || request == KRequestIdCloseStereoAudio) + { + plugin->CancelCloseAudioLink(AccInfo().iAddr); + Parent().AccMan().CloseAudioCompleted(AccInfo().iAddr, type, KErrCancel); + } + else if (request == KRequestIdTimer) + { + iTimer.Cancel(); + } + else if (request == KRequestIdConnectRemConTG) + { + Parent().AccMan().PluginMan().Plugin(ERemConTG)->CancelConnectToAccessory(AccInfo().iAddr); + } + } + +CBasrvAccStateAttached::CBasrvAccStateAttached(CBasrvAcc& aParent, TBool aShowNote) + : CBasrvAccState(aParent, NULL), iShowNote(aShowNote) + { + } + +void CBasrvAccStateAttached::HandleAccOpenedAudio(TProfiles aProfile) + { + TRACE_FUNC + TAccAudioType type = (aProfile & EAnyMonoAudioProfiles) ? EAccMonoAudio : EAccStereoAudio; + TInt latency = Parent().AccMan().PluginMan().AudioLinkLatency(); + + TInt ret = Parent().AccMan().NotifyAccFwAudioOpened(AccInfo().iAddr, type, latency); + + if (ret == KErrNone) + { + UpdateAudioState(EAudioLinkOpen, (aProfile == EStereo) ? EAccStereoAudio : EAccMonoAudio); + + CBasrvAccState::AccOpenedAudio(aProfile); + Parent().NotifyLinkChange2Rvc(); + if (type == EAccStereoAudio) + { + Parent().RequestActiveMode(); + Parent().PreventLowPowerMode(); + Parent().AccMan().PluginMan().Plugin(EStereo)->StartRecording(); + TRAP_IGNORE(DoConnectRemConCtIfNeededL()); + } + else + { + Parent().CancelPowerModeControl(); + } + } + + StatePrint(_L("Attached")); + } + +void CBasrvAccStateAttached::DoCloseAudioL(TAccAudioType aType) + { + TRACE_FUNC + TAccAudioType type = (iCloseAudioProfile & EAnyMonoAudioProfiles) ? EAccMonoAudio : EAccStereoAudio; + if ( type == aType && iTimerActive && iTimerActive->IsActive()) + { + TRACE_STATE(_L("[BTAccStateAttached] Timer is cancelled")) + iTimerActive->Cancel(); + Parent().AccMan().CloseAudioCompleted(AccInfo().iAddr, type, KErrNone); + return; + } + + TInt requestId = (aType == EAccMonoAudio) ? KRequestIdCloseMonoAudio : KRequestIdCloseStereoAudio; + if (!iAudioCloser) + { + iAudioCloser = CBasrvActive::NewL(*this, CActive::EPriorityStandard, requestId); + } + else + { + if (iAudioCloser->IsActive()) + { + LEAVE(KErrAlreadyExists); + } + iAudioCloser->SetRequestId(requestId); + } + TProfiles profile = (aType == EAccMonoAudio) ? EAnyMonoAudioProfiles : EStereo; + AccInfo().iAudioOpenedProfiles &= ~profile; + Parent().NotifyLinkChange2Rvc(); + Parent().AccMan().PluginMan().Plugin(profile)->CloseAudioLink(AccInfo().iAddr, iAudioCloser->iStatus); + iAudioCloser->GoActive(); + } + +void CBasrvAccStateAttached::DoConnectRemConCtIfNeededL() + { + TRACE_FUNC + if (Parent().AccMan().IsAvrcpVolCTSupported() && + IsAvrcpTGCat2SupportedByRemote() && + !(AccInfo().iConnProfiles & ERemConTG) && + !iRemConTGConnector) + { + iRemConTGConnector = CBasrvActive::NewL(*this, CActive::EPriorityStandard, KRequestIdConnectRemConTG); + CBTAccPlugin* plugin = Parent().AccMan().PluginMan().Plugin(ERemConTG); + TRACE_ASSERT(plugin, KErrNotFound) + plugin->ConnectToAccessory(AccInfo().iAddr, iRemConTGConnector->iStatus); + iRemConTGConnector->GoActive(); + } + } + +void CBasrvAccStateAttached::UpdateAudioState(TBTAudioLinkState aState, TAccAudioType aType) + { + TBTAudioLinkInfo info; + info.iAddr = AccInfo().iAddr; + info.iProfile = (aType == EAccMonoAudio) ? 0 : 1; + info.iState = aState; + TPckgBuf pkg(info); + RProperty::Set(KPSUidBluetoothEnginePrivateCategory, KBTAudioLinkStatus, pkg); + }