bluetoothengine/btaudioman/src/basrvaccstateattached.cpp
changeset 0 f63038272f30
child 6 6a29d5ad0713
--- /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 <e32property.h>
+#include <ctsydomainpskeys.h>
+#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<TBTAudioLinkInfo> pkg(info);
+	RProperty::Set(KPSUidBluetoothEnginePrivateCategory, KBTAudioLinkStatus, pkg);
+	}