diff -r 000000000000 -r f63038272f30 bluetoothengine/btaudioman/src/btaudiomanplugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetoothengine/btaudioman/src/btaudiomanplugin.cpp Mon Jan 18 20:28:57 2010 +0200 @@ -0,0 +1,407 @@ +/* +* Copyright (c) 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: Bluetooth Audio Manager ECom plug-in class definition. +* +*/ + + +#include +#include +#include "btaudiomanplugin.h" +#include "btaccTypes.h" +#include "debug.h" + +enum TRequestId + { + ERequestConnect = 1, + ERequestDisconnect = 2, + ENotifyProfileStatusChange = 3, + ERequestDisconnectAll, + }; + +CBtAudioManPlugin* CBtAudioManPlugin::NewL() + { + CBtAudioManPlugin* self = new (ELeave) CBtAudioManPlugin(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +CBtAudioManPlugin::~CBtAudioManPlugin() + { + delete iActive4ClientReq; + delete iActive4ProfileStatus; + iClient.Close(); + TRACE_FUNC + } + +void CBtAudioManPlugin::SetObserver( MBTEngPluginObserver* aObserver ) + { + iObserver = aObserver; + } + +void CBtAudioManPlugin::GetSupportedProfiles( RProfileArray& aProfiles ) + { + aProfiles.Reset(); + aProfiles.Append(EBTProfileHSP); + aProfiles.Append(EBTProfileHFP); + aProfiles.Append(EBTProfileA2DP); + } + +TBool CBtAudioManPlugin::IsProfileSupported(const TBTProfile aProfile ) const + { + return (aProfile == EBTProfileHSP || + aProfile == EBTProfileHFP || + aProfile == EBTProfileA2DP); + } + +TInt CBtAudioManPlugin::Connect( const TBTDevAddr& aAddr ) + { + TRACE_FUNC + return HandleAsyncRequest(aAddr, ERequestConnect); + } + +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; + if (iObserver) + { + iObserver->ConnectComplete(iBTDevAddrPckgBuf(), + EBTProfileHFP, KErrCancel); + } + } + else + { + TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrNotFound")) + if (iObserver) + { + iObserver->ConnectComplete(aAddr , + EBTProfileHFP, KErrNotFound); + } + } + + } + +TInt CBtAudioManPlugin::Disconnect( const TBTDevAddr& aAddr, TBTDisconnectType /*aDiscType*/ ) + { + TInt req = ERequestDisconnect; + if (aAddr == TBTDevAddr()) + { + req = ERequestDisconnectAll; + } + return HandleAsyncRequest(aAddr, req); + } + +void CBtAudioManPlugin::GetConnections( RBTDevAddrArray& aAddrArray, TBTProfile aConnectedProfile ) + { + aAddrArray.Reset(); + TProfiles profile = EUnknownProfile; + + if (aConnectedProfile == EBTProfileHSP || aConnectedProfile == EBTProfileHFP) + { + profile = EAnyMonoAudioProfiles; + } + else if (aConnectedProfile == EBTProfileA2DP) + { + profile = EStereo; + } + else + { + return; + } + + //guess there are 2 addresses as a 'best guess' + TInt numAddresses = 2; + TInt count = numAddresses; + RBuf8 addrbuf; + TPtrC8 ptr(addrbuf); + + do + { + //if this is > 1st time round, the buffer must be deleted and the + //count might have changed + addrbuf.Close(); + numAddresses = count; + + //create a buffer using the 'best guess' size + TInt err = addrbuf.Create(KBTDevAddrSize * numAddresses); + + if (err != KErrNone) + { + //we can't do anything if the buffer fails to create, just return + //and ignore the error as there is no error path (maybe this will + //change in the future) + return; + } + + //get the number of connections and the addresses. count can be either + //the number of connections or a system-wide error code + count = iClient.GetConnections(addrbuf, profile); + + if (count < KErrNone) + { + //error occurred so we're finished with the buffer + addrbuf.Close(); + + //ignore the error as there is no error path (maybe this will + //change in the future) + return; + } + } + //iterate if the number of connections is greater than our 'best guess' or + //maybe another connection was established while this was taking place + while (count > numAddresses); + + //iterate through the addresses buffer + while (ptr.Length() >= KBTDevAddrSize) + { + //append each address to the device address array + TInt err = aAddrArray.Append(TBTDevAddr(ptr.Left(KBTDevAddrSize))); + + if (err == KErrNone) + { + //shift the pointer along to the next address + ptr.Set(ptr.Mid(KBTDevAddrSize)); + } + else + { + //error occurred so we're finished with the buffer + addrbuf.Close(); + + //ignore the error as there is no error path (maybe this will + //change in the future) + return; + } + } + + //now finished with the address buffer + addrbuf.Close(); + } + +TBTEngConnectionStatus CBtAudioManPlugin::IsConnected( const TBTDevAddr& aAddr ) + { + TBTEngConnectionStatus stat = (TBTEngConnectionStatus) iClient.IsConnected(aAddr); + TRACE_INFO((_L("IsConnected %d"), stat)) + return stat; + } + +void CBtAudioManPlugin::RequestCompletedL(CBasrvActive& aActive) + { + TRACE_FUNC + switch (aActive.RequestId()) + { + case ENotifyProfileStatusChange: + { + if (aActive.iStatus == KErrNone && iObserver) + { + ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles, + iProfileStatus.iConnected); + iClient.NotifyConnectionStatus(iProfileStatusPckg, aActive.iStatus); + aActive.GoActive(); + } + break; + } + case ERequestConnect: + { + if (iActive4ClientReq->iStatus.Int() != KErrNone) // might have conflicts, decode iDiagnostic + { + if (iDiagnostic.Length() >= KBTDevAddrSize) + { + RBTDevAddrArray array; + CleanupClosePushL(array); + TPtrC8 ptr(iDiagnostic); + while (ptr.Length() >= KBTDevAddrSize) + { + array.AppendL(TBTDevAddr(ptr.Left(KBTDevAddrSize))); + #ifdef _DEBUG + const TPtrC8 myPtr(array[array.Count() - 1].Des()); + #endif + TRACE_INFO((_L8("conflict <%S>"), &myPtr)) + ptr.Set(ptr.Mid(KBTDevAddrSize)); + } + iObserver->ConnectComplete(iBTDevAddrPckgBuf(), + EBTProfileHFP, iActive4ClientReq->iStatus.Int(), &array); + CleanupStack::PopAndDestroy(&array); + } + else + { + iObserver->ConnectComplete(iBTDevAddrPckgBuf(), + EBTProfileHFP, iActive4ClientReq->iStatus.Int()); + } + } + else + { + TInt profile = 0; + if (iDiagnostic.Length() >= sizeof(TInt)) + { + TPckg pckg(profile); + pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); + } + ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, ETrue); + } + delete iActive4ClientReq; + iActive4ClientReq = NULL; + break; + } + case ERequestDisconnect: + { + if (iActive4ClientReq->iStatus.Int() != KErrNone) + { + iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), + EBTProfileHFP, iActive4ClientReq->iStatus.Int()); + } + else + { + TInt profile = 0; + if (iDiagnostic.Length() >= sizeof(TInt)) + { + TPckg pckg(profile); + 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; + } + } + } + +void CBtAudioManPlugin::CancelRequest(CBasrvActive& aActive) + { + if (aActive.RequestId() == ENotifyProfileStatusChange ) + { + iClient.CancelNotifyConnectionStatus(); + } + else if (aActive.RequestId() == ERequestConnect ) + { + iClient.CancelConnectToAccessory(); + } + } + +CBtAudioManPlugin::CBtAudioManPlugin() : iProfileStatusPckg(iProfileStatus) + { + TRACE_FUNC + } + +void CBtAudioManPlugin::ConstructL() + { + LEAVE_IF_ERROR(iClient.Connect()); + iActive4ProfileStatus = CBasrvActive::NewL(*this, CActive::EPriorityStandard, ENotifyProfileStatusChange); + iClient.NotifyConnectionStatus(iProfileStatusPckg, iActive4ProfileStatus->iStatus); + iActive4ProfileStatus->GoActive(); + } + +TInt CBtAudioManPlugin::HandleAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId) + { + TInt err = KErrNone; + if (! iClient.Handle() ) + { + err = iClient.Connect(); + } + if ( err ) + { + return err; + } + if ( iActive4ClientReq ) + { + 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; + } + } + return err; + } + +void CBtAudioManPlugin::ReportProfileConnectionEvents(const TBTDevAddr& aAddr, const TInt aProfiles, TBool aConnected) + { + TRACE_FUNC + TRACE_INFO((_L("status %d profiles 0x%04X"), aConnected, aProfiles)) + TBTEngConnectionStatus status = IsConnected(aAddr); + if (iObserver) + { + if (aConnected) + { + if (aProfiles & EHFP) + { + iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrNone); + } + if (aProfiles & EHSP) + { + iObserver->ConnectComplete(aAddr, EBTProfileHSP, KErrNone); + } + if (aProfiles & EStereo) + { + iObserver->ConnectComplete(aAddr, EBTProfileA2DP, KErrNone); + } + } + 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); + } + } + } + } + } + +//