bluetoothengine/btaudioman/src/btaudiomanplugin.cpp
branchRCL_3
changeset 6 6a29d5ad0713
parent 0 f63038272f30
child 11 a42ed326b458
--- a/bluetoothengine/btaudioman/src/btaudiomanplugin.cpp	Tue Feb 02 00:20:42 2010 +0200
+++ b/bluetoothengine/btaudioman/src/btaudiomanplugin.cpp	Fri Feb 19 22:59:18 2010 +0200
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2006-2010 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"
@@ -70,23 +70,27 @@
 TInt CBtAudioManPlugin::Connect( const TBTDevAddr& aAddr )
     {
     TRACE_FUNC
-    return HandleAsyncRequest(aAddr, ERequestConnect);    
+    TInt err = PrepareAsyncRequest(aAddr, ERequestConnect);
+    if(!err)
+        {
+        iDiagnostic.Zero();
+        iClient.ConnectToAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
+        iActive4ClientReq->GoActive();
+        }
+    return err;
     }
 
 void CBtAudioManPlugin::CancelConnect( const TBTDevAddr& aAddr )
     {
     if (iBTDevAddrPckgBuf() == aAddr &&
-        iActive4ClientReq &&
         iActive4ClientReq->IsActive() &&
         iActive4ClientReq->RequestId() == ERequestConnect )
         {
         TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrCancel"))
-        delete iActive4ClientReq;
-        iActive4ClientReq = NULL;
+        iActive4ClientReq->Cancel();
         if (iObserver)
             {
-            iObserver->ConnectComplete(iBTDevAddrPckgBuf(), 
-                EBTProfileHFP, KErrCancel);
+            iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrCancel);
             }
         }
     else
@@ -94,8 +98,7 @@
         TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrNotFound"))
         if (iObserver)
             {
-            iObserver->ConnectComplete(aAddr , 
-                EBTProfileHFP, KErrNotFound);
+            iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrNotFound);
             }
         }
 
@@ -107,8 +110,21 @@
     if (aAddr == TBTDevAddr())
         {
         req = ERequestDisconnectAll;
-        }    
-    return HandleAsyncRequest(aAddr, req);
+        }
+    TInt err = PrepareAsyncRequest(aAddr, req);
+    if (!err)
+        {
+        if (req == ERequestDisconnect)
+            {
+            iClient.DisconnectAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
+            }
+        else // if (req == ERequestDisconnectAll)
+            {
+            iClient.DisconnectAllGracefully(iActive4ClientReq->iStatus);
+            }
+        iActive4ClientReq->GoActive();
+        }
+    return err;
     }
 
 void CBtAudioManPlugin::GetConnections( RBTDevAddrArray& aAddrArray, TBTProfile aConnectedProfile )
@@ -207,22 +223,45 @@
 void CBtAudioManPlugin::RequestCompletedL(CBasrvActive& aActive)
     {
     TRACE_FUNC
+    TInt result = aActive.iStatus.Int();
     switch (aActive.RequestId())
         {
         case ENotifyProfileStatusChange:
             {
-            if (aActive.iStatus == KErrNone && iObserver)
+            // Notify any observer if one is present, and we got valid data (i.e. no error)
+            if (result == KErrNone && iObserver)
+                {
+                ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles, iProfileStatus.iConnected);
+                }
+            // Handle resubscribing for future notifications
+            static const TInt KMaxFailedNotifyConnectionStatusAttempts = 3;
+            if (result == KErrNone)
+                {
+                iNotifyConnectionStatusFailure = 0; // reset failure count
+                NotifyConnectionStatus();
+                }
+            else if (result != KErrServerTerminated && iNotifyConnectionStatusFailure < KMaxFailedNotifyConnectionStatusAttempts)
                 {
-                ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles,
-                    iProfileStatus.iConnected);
-                iClient.NotifyConnectionStatus(iProfileStatusPckg, aActive.iStatus);
-                aActive.GoActive();
+                TRACE_ERROR((_L8("Connection Status Notification failed (transiently): %d"), result))
+                ++iNotifyConnectionStatusFailure;
+                NotifyConnectionStatus();
+                }
+            else
+                {
+                // The server has died unexpectedly, or we've failed a number of times in succession so we cannot re-subscribe. 
+                // The lack of state here makes it diffcult to know how to report (handle?) this.  However, we are in
+                // no worse situation than before, plus the issue is now logged.
+                TRACE_ERROR((_L8("Connection Status Notification failed (terminally): %d"), result))
+                iClient.Close(); // clean the handle, this might kill outstanding disconnect/connect requests
+                                 // but it looks like the server is hosed anyway...
+                // In keeping with the existing logic we don't attempt to re-start the server.  That will only happen when an
+                // active request is made.
                 }
             break;
             }
         case ERequestConnect:
             {
-            if (iActive4ClientReq->iStatus.Int() != KErrNone) // might have conflicts, decode iDiagnostic
+            if (result != KErrNone) // might have conflicts, decode iDiagnostic
                 {
                 if (iDiagnostic.Length() >= KBTDevAddrSize)
                     {
@@ -238,14 +277,12 @@
                         TRACE_INFO((_L8("conflict <%S>"), &myPtr))
                         ptr.Set(ptr.Mid(KBTDevAddrSize));
                         }
-                    iObserver->ConnectComplete(iBTDevAddrPckgBuf(), 
-                        EBTProfileHFP, iActive4ClientReq->iStatus.Int(), &array);
+                    iObserver->ConnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result, &array);
                     CleanupStack::PopAndDestroy(&array);
                     }
                 else
                     {
-                    iObserver->ConnectComplete(iBTDevAddrPckgBuf(), 
-                        EBTProfileHFP, iActive4ClientReq->iStatus.Int());
+                    iObserver->ConnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result);
                     }
                 }
             else
@@ -258,16 +295,13 @@
                     }
                 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, ETrue);
                 }
-            delete iActive4ClientReq;
-            iActive4ClientReq = NULL;
             break;
             }
         case ERequestDisconnect:
             {
-            if (iActive4ClientReq->iStatus.Int() != KErrNone)
+            if (result != KErrNone)
                 {
-                iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), 
-                        EBTProfileHFP, iActive4ClientReq->iStatus.Int());
+                iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result);
                 }
             else
                 {
@@ -278,27 +312,24 @@
                     pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); 
                     }
                 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, EFalse);
-                }            
-            delete iActive4ClientReq;
-            iActive4ClientReq = NULL;
+                }
             break;
             }
         case ERequestDisconnectAll:
             {
-            iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), 
-                        EBTProfileHFP, iActive4ClientReq->iStatus.Int());
-			break;
+            iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result);
+            break;
             }
         }
     }
     
 void CBtAudioManPlugin::CancelRequest(CBasrvActive& aActive)
     {
-    if (aActive.RequestId() == ENotifyProfileStatusChange )
+    if (aActive.RequestId() == ENotifyProfileStatusChange)
         {
         iClient.CancelNotifyConnectionStatus();
         }
-    else if (aActive.RequestId() == ERequestConnect )
+    else if (aActive.RequestId() == ERequestConnect)
         {
         iClient.CancelConnectToAccessory();
         }
@@ -312,51 +343,49 @@
 void CBtAudioManPlugin::ConstructL()
     {
     LEAVE_IF_ERROR(iClient.Connect());
+    // Create the handler for profile notifications
     iActive4ProfileStatus = CBasrvActive::NewL(*this, CActive::EPriorityStandard, ENotifyProfileStatusChange);
+    NotifyConnectionStatus();
+    // Create the handler for active requests (connect, disconnect, etc.)
+    iActive4ClientReq = CBasrvActive::New(*this, CActive::EPriorityStandard, ERequestConnect);
+    }
+
+void CBtAudioManPlugin::NotifyConnectionStatus()
+    {
     iClient.NotifyConnectionStatus(iProfileStatusPckg, iActive4ProfileStatus->iStatus);
     iActive4ProfileStatus->GoActive();
     }
 
-TInt CBtAudioManPlugin::HandleAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId)
+TInt CBtAudioManPlugin::ReconnectIfNeccessary()
     {
     TInt err = KErrNone;
-    if (! iClient.Handle() )
+    if (iClient.Handle() == KNullHandle)
         {
+        TRACE_INFO((_L8("Handle to Audio Man Server is not valid, connecting again...")))
         err = iClient.Connect();
+        TRACE_INFO((_L8("... reconnection result = %d"), err))
+        if(!err)
+            {
+            // Now reconnected, we should start status notifications again...
+            NotifyConnectionStatus();
+            }
         }
-    if ( err )
+    return err;
+    }
+
+TInt CBtAudioManPlugin::PrepareAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId)
+    {
+    TInt err = KErrNone;
+    err = ReconnectIfNeccessary();
+    if (!err && iActive4ClientReq->IsActive())
         {
-        return err;
-        }
-    if ( iActive4ClientReq )
-        {
+        // I would normally expect KErrInUse, so as to distinguish this failure from running out of message slots
         err = KErrServerBusy;
         }
     if (!err)
         {
-        iActive4ClientReq = CBasrvActive::New(*this, CActive::EPriorityStandard, aRequestId);
-        if (iActive4ClientReq)
-            {
-            iBTDevAddrPckgBuf() = aAddr;
-            if (aRequestId == ERequestConnect)
-                {
-                iDiagnostic.Zero();
-                iClient.ConnectToAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
-                }
-            else if (aRequestId == ERequestDisconnect)
-                {
-                iClient.DisconnectAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
-                }
-            else // if (aRequestId == ERequestDisconnectAll)
-            	{
-            	iClient.DisconnectAllGracefully(iActive4ClientReq->iStatus);
-            	}
-            iActive4ClientReq->GoActive();
-            }
-        else
-            {
-            err = KErrNoMemory;
-            }
+        iBTDevAddrPckgBuf() = aAddr;
+        iActive4ClientReq->SetRequestId(aRequestId);
         }
     return err;    
     }
@@ -365,7 +394,7 @@
     {
     TRACE_FUNC
     TRACE_INFO((_L("status %d profiles 0x%04X"), aConnected, aProfiles))
-	TBTEngConnectionStatus status = IsConnected(aAddr);
+    TBTEngConnectionStatus status = IsConnected(aAddr);
     if (iObserver)
         {
         if (aConnected)
@@ -385,21 +414,21 @@
             }
         else
             {
-			if(	status != EBTEngConnected )
-				{
-	            if (aProfiles & EHFP)
-	                {
-	                iObserver->DisconnectComplete(aAddr, EBTProfileHFP, KErrNone);
-	                }
-	            if (aProfiles & EHSP)
-	                {
-	                iObserver->DisconnectComplete(aAddr, EBTProfileHSP, KErrNone);
-	                }
-	            if (aProfiles & EStereo)
-	                {
-	                iObserver->DisconnectComplete(aAddr, EBTProfileA2DP, KErrNone);
-	                }
-				}
+            if (status != EBTEngConnected)
+                {
+                if (aProfiles & EHFP)
+                    {
+                    iObserver->DisconnectComplete(aAddr, EBTProfileHFP, KErrNone);
+                    }
+                if (aProfiles & EHSP)
+                    {
+                    iObserver->DisconnectComplete(aAddr, EBTProfileHSP, KErrNone);
+                    }
+                if (aProfiles & EStereo)
+                    {
+                    iObserver->DisconnectComplete(aAddr, EBTProfileA2DP, KErrNone);
+                    }
+                }
             }
         }
     }