bluetoothengine/btaudioman/src/btaudiomanplugin.cpp
changeset 15 00f9ee97d895
parent 0 f63038272f30
equal deleted inserted replaced
2:0b192a3a05a4 15:00f9ee97d895
     1 /*
     1 /*
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
     2 * Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     4 * This component and the accompanying materials are made available
     5 * under the terms of "Eclipse Public License v1.0"
     5 * under the terms of "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
    68     }
    68     }
    69 
    69 
    70 TInt CBtAudioManPlugin::Connect( const TBTDevAddr& aAddr )
    70 TInt CBtAudioManPlugin::Connect( const TBTDevAddr& aAddr )
    71     {
    71     {
    72     TRACE_FUNC
    72     TRACE_FUNC
    73     return HandleAsyncRequest(aAddr, ERequestConnect);    
    73     TInt err = PrepareAsyncRequest(aAddr, ERequestConnect);
       
    74     if(!err)
       
    75         {
       
    76         iDiagnostic.Zero();
       
    77         iClient.ConnectToAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
       
    78         iActive4ClientReq->GoActive();
       
    79         }
       
    80     return err;
    74     }
    81     }
    75 
    82 
    76 void CBtAudioManPlugin::CancelConnect( const TBTDevAddr& aAddr )
    83 void CBtAudioManPlugin::CancelConnect( const TBTDevAddr& aAddr )
    77     {
    84     {
    78     if (iBTDevAddrPckgBuf() == aAddr &&
    85     if (iBTDevAddrPckgBuf() == aAddr &&
    79         iActive4ClientReq &&
       
    80         iActive4ClientReq->IsActive() &&
    86         iActive4ClientReq->IsActive() &&
    81         iActive4ClientReq->RequestId() == ERequestConnect )
    87         iActive4ClientReq->RequestId() == ERequestConnect )
    82         {
    88         {
    83         TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrCancel"))
    89         TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrCancel"))
    84         delete iActive4ClientReq;
    90         iActive4ClientReq->Cancel();
    85         iActive4ClientReq = NULL;
       
    86         if (iObserver)
    91         if (iObserver)
    87             {
    92             {
    88             iObserver->ConnectComplete(iBTDevAddrPckgBuf(), 
    93             iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrCancel);
    89                 EBTProfileHFP, KErrCancel);
       
    90             }
    94             }
    91         }
    95         }
    92     else
    96     else
    93         {
    97         {
    94         TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrNotFound"))
    98         TRACE_INFO(_L("CBtAudioManPlugin::CancelConnect KErrNotFound"))
    95         if (iObserver)
    99         if (iObserver)
    96             {
   100             {
    97             iObserver->ConnectComplete(aAddr , 
   101             iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrNotFound);
    98                 EBTProfileHFP, KErrNotFound);
       
    99             }
   102             }
   100         }
   103         }
   101 
   104 
   102     }
   105     }
   103 
   106 
   105     {
   108     {
   106     TInt req = ERequestDisconnect;
   109     TInt req = ERequestDisconnect;
   107     if (aAddr == TBTDevAddr())
   110     if (aAddr == TBTDevAddr())
   108         {
   111         {
   109         req = ERequestDisconnectAll;
   112         req = ERequestDisconnectAll;
   110         }    
   113         }
   111     return HandleAsyncRequest(aAddr, req);
   114     TInt err = PrepareAsyncRequest(aAddr, req);
       
   115     if (!err)
       
   116         {
       
   117         if (req == ERequestDisconnect)
       
   118             {
       
   119             iClient.DisconnectAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
       
   120             }
       
   121         else // if (req == ERequestDisconnectAll)
       
   122             {
       
   123             iClient.DisconnectAllGracefully(iActive4ClientReq->iStatus);
       
   124             }
       
   125         iActive4ClientReq->GoActive();
       
   126         }
       
   127     return err;
   112     }
   128     }
   113 
   129 
   114 void CBtAudioManPlugin::GetConnections( RBTDevAddrArray& aAddrArray, TBTProfile aConnectedProfile )
   130 void CBtAudioManPlugin::GetConnections( RBTDevAddrArray& aAddrArray, TBTProfile aConnectedProfile )
   115     {
   131     {
       
   132     TRACE_FUNC
   116     aAddrArray.Reset();
   133     aAddrArray.Reset();
   117     TProfiles profile = EUnknownProfile;
   134     TProfiles profile = EUnknownProfile;
   118     
   135     
   119     if (aConnectedProfile == EBTProfileHSP || aConnectedProfile == EBTProfileHFP)
   136     if (aConnectedProfile == EBTProfileHSP || aConnectedProfile == EBTProfileHFP)
   120         {
   137         {
   131     
   148     
   132     //guess there are 2 addresses as a 'best guess'
   149     //guess there are 2 addresses as a 'best guess'
   133     TInt numAddresses = 2;
   150     TInt numAddresses = 2;
   134     TInt count = numAddresses;
   151     TInt count = numAddresses;
   135     RBuf8 addrbuf;
   152     RBuf8 addrbuf;
   136     TPtrC8 ptr(addrbuf);
       
   137     
   153     
   138     do
   154     do
   139         {
   155         {
   140         //if this is > 1st time round, the buffer must be deleted and the
   156         //if this is > 1st time round, the buffer must be deleted and the
   141         //count might have changed
   157         //count might have changed
   169         }
   185         }
   170     //iterate if the number of connections is greater than our 'best guess' or
   186     //iterate if the number of connections is greater than our 'best guess' or
   171     //maybe another connection was established while this was taking place
   187     //maybe another connection was established while this was taking place
   172     while (count > numAddresses);
   188     while (count > numAddresses);
   173     
   189     
       
   190     TPtrC8 ptr(addrbuf);
       
   191     
   174     //iterate through the addresses buffer
   192     //iterate through the addresses buffer
   175     while (ptr.Length() >= KBTDevAddrSize)
   193     while (ptr.Length() >= KBTDevAddrSize)
   176         {
   194         {
   177         //append each address to the device address array
   195         //append each address to the device address array
   178         TInt err = aAddrArray.Append(TBTDevAddr(ptr.Left(KBTDevAddrSize)));
   196         TInt err = aAddrArray.Append(TBTDevAddr(ptr.Left(KBTDevAddrSize)));
   205     }
   223     }
   206 
   224 
   207 void CBtAudioManPlugin::RequestCompletedL(CBasrvActive& aActive)
   225 void CBtAudioManPlugin::RequestCompletedL(CBasrvActive& aActive)
   208     {
   226     {
   209     TRACE_FUNC
   227     TRACE_FUNC
       
   228     TInt result = aActive.iStatus.Int();
   210     switch (aActive.RequestId())
   229     switch (aActive.RequestId())
   211         {
   230         {
   212         case ENotifyProfileStatusChange:
   231         case ENotifyProfileStatusChange:
   213             {
   232             {
   214             if (aActive.iStatus == KErrNone && iObserver)
   233             // Notify any observer if one is present, and we got valid data (i.e. no error)
   215                 {
   234             if (result == KErrNone && iObserver)
   216                 ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles,
   235                 {
   217                     iProfileStatus.iConnected);
   236                 ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles, iProfileStatus.iConnected);
   218                 iClient.NotifyConnectionStatus(iProfileStatusPckg, aActive.iStatus);
   237                 }
   219                 aActive.GoActive();
   238             // Handle resubscribing for future notifications
       
   239             static const TInt KMaxFailedNotifyConnectionStatusAttempts = 3;
       
   240             if (result == KErrNone)
       
   241                 {
       
   242                 iNotifyConnectionStatusFailure = 0; // reset failure count
       
   243                 NotifyConnectionStatus();
       
   244                 }
       
   245             else if (result != KErrServerTerminated && iNotifyConnectionStatusFailure < KMaxFailedNotifyConnectionStatusAttempts)
       
   246                 {
       
   247                 TRACE_ERROR((_L8("Connection Status Notification failed (transiently): %d"), result))
       
   248                 ++iNotifyConnectionStatusFailure;
       
   249                 NotifyConnectionStatus();
       
   250                 }
       
   251             else
       
   252                 {
       
   253                 // The server has died unexpectedly, or we've failed a number of times in succession so we cannot re-subscribe. 
       
   254                 // The lack of state here makes it diffcult to know how to report (handle?) this.  However, we are in
       
   255                 // no worse situation than before, plus the issue is now logged.
       
   256                 TRACE_ERROR((_L8("Connection Status Notification failed (terminally): %d"), result))
       
   257                 iClient.Close(); // clean the handle, this might kill outstanding disconnect/connect requests
       
   258                                  // but it looks like the server is hosed anyway...
       
   259                 // In keeping with the existing logic we don't attempt to re-start the server.  That will only happen when an
       
   260                 // active request is made.
   220                 }
   261                 }
   221             break;
   262             break;
   222             }
   263             }
   223         case ERequestConnect:
   264         case ERequestConnect:
   224             {
   265             {
   225             if (iActive4ClientReq->iStatus.Int() != KErrNone) // might have conflicts, decode iDiagnostic
   266             if (result != KErrNone) // might have conflicts, decode iDiagnostic
   226                 {
   267                 {
   227                 if (iDiagnostic.Length() >= KBTDevAddrSize)
   268                 if (iDiagnostic.Length() >= KBTDevAddrSize)
   228                     {
   269                     {
   229                     RBTDevAddrArray array;
   270                     RBTDevAddrArray array;
   230                     CleanupClosePushL(array);
   271                     CleanupClosePushL(array);
   236                         const TPtrC8 myPtr(array[array.Count() - 1].Des());
   277                         const TPtrC8 myPtr(array[array.Count() - 1].Des());
   237                         #endif
   278                         #endif
   238                         TRACE_INFO((_L8("conflict <%S>"), &myPtr))
   279                         TRACE_INFO((_L8("conflict <%S>"), &myPtr))
   239                         ptr.Set(ptr.Mid(KBTDevAddrSize));
   280                         ptr.Set(ptr.Mid(KBTDevAddrSize));
   240                         }
   281                         }
   241                     iObserver->ConnectComplete(iBTDevAddrPckgBuf(), 
   282                     iObserver->ConnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result, &array);
   242                         EBTProfileHFP, iActive4ClientReq->iStatus.Int(), &array);
       
   243                     CleanupStack::PopAndDestroy(&array);
   283                     CleanupStack::PopAndDestroy(&array);
   244                     }
   284                     }
   245                 else
   285                 else
   246                     {
   286                     {
   247                     iObserver->ConnectComplete(iBTDevAddrPckgBuf(), 
   287                     iObserver->ConnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result);
   248                         EBTProfileHFP, iActive4ClientReq->iStatus.Int());
       
   249                     }
   288                     }
   250                 }
   289                 }
   251             else
   290             else
   252                 {
   291                 {
   253                 TInt profile = 0;
   292                 TInt profile = 0;
   256                     TPckg<TInt> pckg(profile);
   295                     TPckg<TInt> pckg(profile);
   257                     pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); 
   296                     pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); 
   258                     }
   297                     }
   259                 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, ETrue);
   298                 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, ETrue);
   260                 }
   299                 }
   261             delete iActive4ClientReq;
       
   262             iActive4ClientReq = NULL;
       
   263             break;
   300             break;
   264             }
   301             }
   265         case ERequestDisconnect:
   302         case ERequestDisconnect:
   266             {
   303             {
   267             if (iActive4ClientReq->iStatus.Int() != KErrNone)
   304             if (result != KErrNone)
   268                 {
   305                 {
   269                 iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), 
   306                 iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result);
   270                         EBTProfileHFP, iActive4ClientReq->iStatus.Int());
       
   271                 }
   307                 }
   272             else
   308             else
   273                 {
   309                 {
   274                 TInt profile = 0;
   310                 TInt profile = 0;
   275                 if (iDiagnostic.Length() >= sizeof(TInt))
   311                 if (iDiagnostic.Length() >= sizeof(TInt))
   276                     {
   312                     {
   277                     TPckg<TInt> pckg(profile);
   313                     TPckg<TInt> pckg(profile);
   278                     pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); 
   314                     pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); 
   279                     }
   315                     }
   280                 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, EFalse);
   316                 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, EFalse);
   281                 }            
   317                 }
   282             delete iActive4ClientReq;
       
   283             iActive4ClientReq = NULL;
       
   284             break;
   318             break;
   285             }
   319             }
   286         case ERequestDisconnectAll:
   320         case ERequestDisconnectAll:
   287             {
   321             {
   288             iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), 
   322             iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result);
   289                         EBTProfileHFP, iActive4ClientReq->iStatus.Int());
   323             break;
   290 			break;
       
   291             }
   324             }
   292         }
   325         }
   293     }
   326     }
   294     
   327     
   295 void CBtAudioManPlugin::CancelRequest(CBasrvActive& aActive)
   328 void CBtAudioManPlugin::CancelRequest(CBasrvActive& aActive)
   296     {
   329     {
   297     if (aActive.RequestId() == ENotifyProfileStatusChange )
   330     if (aActive.RequestId() == ENotifyProfileStatusChange)
   298         {
   331         {
   299         iClient.CancelNotifyConnectionStatus();
   332         iClient.CancelNotifyConnectionStatus();
   300         }
   333         }
   301     else if (aActive.RequestId() == ERequestConnect )
   334     else if (aActive.RequestId() == ERequestConnect)
   302         {
   335         {
   303         iClient.CancelConnectToAccessory();
   336         iClient.CancelConnectToAccessory();
   304         }
   337         }
   305     }
   338     }
   306 
   339 
   310     }
   343     }
   311 
   344 
   312 void CBtAudioManPlugin::ConstructL()
   345 void CBtAudioManPlugin::ConstructL()
   313     {
   346     {
   314     LEAVE_IF_ERROR(iClient.Connect());
   347     LEAVE_IF_ERROR(iClient.Connect());
       
   348     // Create the handler for profile notifications
   315     iActive4ProfileStatus = CBasrvActive::NewL(*this, CActive::EPriorityStandard, ENotifyProfileStatusChange);
   349     iActive4ProfileStatus = CBasrvActive::NewL(*this, CActive::EPriorityStandard, ENotifyProfileStatusChange);
       
   350     NotifyConnectionStatus();
       
   351     // Create the handler for active requests (connect, disconnect, etc.)
       
   352     iActive4ClientReq = CBasrvActive::New(*this, CActive::EPriorityStandard, ERequestConnect);
       
   353     }
       
   354 
       
   355 void CBtAudioManPlugin::NotifyConnectionStatus()
       
   356     {
   316     iClient.NotifyConnectionStatus(iProfileStatusPckg, iActive4ProfileStatus->iStatus);
   357     iClient.NotifyConnectionStatus(iProfileStatusPckg, iActive4ProfileStatus->iStatus);
   317     iActive4ProfileStatus->GoActive();
   358     iActive4ProfileStatus->GoActive();
   318     }
   359     }
   319 
   360 
   320 TInt CBtAudioManPlugin::HandleAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId)
   361 TInt CBtAudioManPlugin::ReconnectIfNeccessary()
   321     {
   362     {
   322     TInt err = KErrNone;
   363     TInt err = KErrNone;
   323     if (! iClient.Handle() )
   364     if (iClient.Handle() == KNullHandle)
   324         {
   365         {
       
   366         TRACE_INFO((_L8("Handle to Audio Man Server is not valid, connecting again...")))
   325         err = iClient.Connect();
   367         err = iClient.Connect();
   326         }
   368         TRACE_INFO((_L8("... reconnection result = %d"), err))
   327     if ( err )
   369         if(!err)
   328         {
   370             {
   329         return err;
   371             // Now reconnected, we should start status notifications again...
   330         }
   372             NotifyConnectionStatus();
   331     if ( iActive4ClientReq )
   373             }
   332         {
   374         }
       
   375     return err;
       
   376     }
       
   377 
       
   378 TInt CBtAudioManPlugin::PrepareAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId)
       
   379     {
       
   380     TInt err = KErrNone;
       
   381     err = ReconnectIfNeccessary();
       
   382     if (!err && iActive4ClientReq->IsActive())
       
   383         {
       
   384         // I would normally expect KErrInUse, so as to distinguish this failure from running out of message slots
   333         err = KErrServerBusy;
   385         err = KErrServerBusy;
   334         }
   386         }
   335     if (!err)
   387     if (!err)
   336         {
   388         {
   337         iActive4ClientReq = CBasrvActive::New(*this, CActive::EPriorityStandard, aRequestId);
   389         iBTDevAddrPckgBuf() = aAddr;
   338         if (iActive4ClientReq)
   390         iActive4ClientReq->SetRequestId(aRequestId);
   339             {
   391         }
   340             iBTDevAddrPckgBuf() = aAddr;
   392     return err;    
   341             if (aRequestId == ERequestConnect)
   393     }
   342                 {
   394 
   343                 iDiagnostic.Zero();
   395 void CBtAudioManPlugin::ReportProfileConnectionEvents(const TBTDevAddr& aAddr, const TInt aProfiles, TBool aConnected)
   344                 iClient.ConnectToAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
   396     {
   345                 }
   397     TRACE_FUNC
   346             else if (aRequestId == ERequestDisconnect)
   398     TRACE_INFO((_L("status %d profiles 0x%04X"), aConnected, aProfiles))
   347                 {
   399     TBTEngConnectionStatus status = IsConnected(aAddr);
   348                 iClient.DisconnectAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic);
   400     if (iObserver)
   349                 }
   401         {
   350             else // if (aRequestId == ERequestDisconnectAll)
   402         if (aConnected)
   351             	{
   403             {
   352             	iClient.DisconnectAllGracefully(iActive4ClientReq->iStatus);
   404             if (aProfiles & EHFP)
   353             	}
   405                 {
   354             iActive4ClientReq->GoActive();
   406                 iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrNone);
       
   407                 }
       
   408             if (aProfiles & EHSP)
       
   409                 {
       
   410                 iObserver->ConnectComplete(aAddr, EBTProfileHSP, KErrNone);
       
   411                 }
       
   412             if (aProfiles & EStereo)
       
   413                 {
       
   414                 iObserver->ConnectComplete(aAddr, EBTProfileA2DP, KErrNone);
       
   415                 }
   355             }
   416             }
   356         else
   417         else
   357             {
   418             {
   358             err = KErrNoMemory;
   419             if (status != EBTEngConnected)
   359             }
   420                 {
   360         }
   421                 if (aProfiles & EHFP)
   361     return err;    
   422                     {
   362     }
   423                     iObserver->DisconnectComplete(aAddr, EBTProfileHFP, KErrNone);
   363 
   424                     }
   364 void CBtAudioManPlugin::ReportProfileConnectionEvents(const TBTDevAddr& aAddr, const TInt aProfiles, TBool aConnected)
   425                 if (aProfiles & EHSP)
   365     {
   426                     {
   366     TRACE_FUNC
   427                     iObserver->DisconnectComplete(aAddr, EBTProfileHSP, KErrNone);
   367     TRACE_INFO((_L("status %d profiles 0x%04X"), aConnected, aProfiles))
   428                     }
   368 	TBTEngConnectionStatus status = IsConnected(aAddr);
   429                 if (aProfiles & EStereo)
   369     if (iObserver)
   430                     {
   370         {
   431                     iObserver->DisconnectComplete(aAddr, EBTProfileA2DP, KErrNone);
   371         if (aConnected)
   432                     }
   372             {
   433                 }
   373             if (aProfiles & EHFP)
       
   374                 {
       
   375                 iObserver->ConnectComplete(aAddr, EBTProfileHFP, KErrNone);
       
   376                 }
       
   377             if (aProfiles & EHSP)
       
   378                 {
       
   379                 iObserver->ConnectComplete(aAddr, EBTProfileHSP, KErrNone);
       
   380                 }
       
   381             if (aProfiles & EStereo)
       
   382                 {
       
   383                 iObserver->ConnectComplete(aAddr, EBTProfileA2DP, KErrNone);
       
   384                 }
       
   385             }
       
   386         else
       
   387             {
       
   388 			if(	status != EBTEngConnected )
       
   389 				{
       
   390 	            if (aProfiles & EHFP)
       
   391 	                {
       
   392 	                iObserver->DisconnectComplete(aAddr, EBTProfileHFP, KErrNone);
       
   393 	                }
       
   394 	            if (aProfiles & EHSP)
       
   395 	                {
       
   396 	                iObserver->DisconnectComplete(aAddr, EBTProfileHSP, KErrNone);
       
   397 	                }
       
   398 	            if (aProfiles & EStereo)
       
   399 	                {
       
   400 	                iObserver->DisconnectComplete(aAddr, EBTProfileA2DP, KErrNone);
       
   401 	                }
       
   402 				}
       
   403             }
   434             }
   404         }
   435         }
   405     }
   436     }
   406 
   437 
   407 //
   438 //