diff -r 0b192a3a05a4 -r 6a29d5ad0713 bluetoothengine/btaudioman/src/btaudiomanplugin.cpp --- 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); + } + } } } }