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 { |
116 aAddrArray.Reset(); |
132 aAddrArray.Reset(); |
205 } |
221 } |
206 |
222 |
207 void CBtAudioManPlugin::RequestCompletedL(CBasrvActive& aActive) |
223 void CBtAudioManPlugin::RequestCompletedL(CBasrvActive& aActive) |
208 { |
224 { |
209 TRACE_FUNC |
225 TRACE_FUNC |
|
226 TInt result = aActive.iStatus.Int(); |
210 switch (aActive.RequestId()) |
227 switch (aActive.RequestId()) |
211 { |
228 { |
212 case ENotifyProfileStatusChange: |
229 case ENotifyProfileStatusChange: |
213 { |
230 { |
214 if (aActive.iStatus == KErrNone && iObserver) |
231 // Notify any observer if one is present, and we got valid data (i.e. no error) |
215 { |
232 if (result == KErrNone && iObserver) |
216 ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles, |
233 { |
217 iProfileStatus.iConnected); |
234 ReportProfileConnectionEvents(iProfileStatus.iAddr, iProfileStatus.iProfiles, iProfileStatus.iConnected); |
218 iClient.NotifyConnectionStatus(iProfileStatusPckg, aActive.iStatus); |
235 } |
219 aActive.GoActive(); |
236 // Handle resubscribing for future notifications |
|
237 static const TInt KMaxFailedNotifyConnectionStatusAttempts = 3; |
|
238 if (result == KErrNone) |
|
239 { |
|
240 iNotifyConnectionStatusFailure = 0; // reset failure count |
|
241 NotifyConnectionStatus(); |
|
242 } |
|
243 else if (result != KErrServerTerminated && iNotifyConnectionStatusFailure < KMaxFailedNotifyConnectionStatusAttempts) |
|
244 { |
|
245 TRACE_ERROR((_L8("Connection Status Notification failed (transiently): %d"), result)) |
|
246 ++iNotifyConnectionStatusFailure; |
|
247 NotifyConnectionStatus(); |
|
248 } |
|
249 else |
|
250 { |
|
251 // The server has died unexpectedly, or we've failed a number of times in succession so we cannot re-subscribe. |
|
252 // The lack of state here makes it diffcult to know how to report (handle?) this. However, we are in |
|
253 // no worse situation than before, plus the issue is now logged. |
|
254 TRACE_ERROR((_L8("Connection Status Notification failed (terminally): %d"), result)) |
|
255 iClient.Close(); // clean the handle, this might kill outstanding disconnect/connect requests |
|
256 // but it looks like the server is hosed anyway... |
|
257 // In keeping with the existing logic we don't attempt to re-start the server. That will only happen when an |
|
258 // active request is made. |
220 } |
259 } |
221 break; |
260 break; |
222 } |
261 } |
223 case ERequestConnect: |
262 case ERequestConnect: |
224 { |
263 { |
225 if (iActive4ClientReq->iStatus.Int() != KErrNone) // might have conflicts, decode iDiagnostic |
264 if (result != KErrNone) // might have conflicts, decode iDiagnostic |
226 { |
265 { |
227 if (iDiagnostic.Length() >= KBTDevAddrSize) |
266 if (iDiagnostic.Length() >= KBTDevAddrSize) |
228 { |
267 { |
229 RBTDevAddrArray array; |
268 RBTDevAddrArray array; |
230 CleanupClosePushL(array); |
269 CleanupClosePushL(array); |
236 const TPtrC8 myPtr(array[array.Count() - 1].Des()); |
275 const TPtrC8 myPtr(array[array.Count() - 1].Des()); |
237 #endif |
276 #endif |
238 TRACE_INFO((_L8("conflict <%S>"), &myPtr)) |
277 TRACE_INFO((_L8("conflict <%S>"), &myPtr)) |
239 ptr.Set(ptr.Mid(KBTDevAddrSize)); |
278 ptr.Set(ptr.Mid(KBTDevAddrSize)); |
240 } |
279 } |
241 iObserver->ConnectComplete(iBTDevAddrPckgBuf(), |
280 iObserver->ConnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result, &array); |
242 EBTProfileHFP, iActive4ClientReq->iStatus.Int(), &array); |
|
243 CleanupStack::PopAndDestroy(&array); |
281 CleanupStack::PopAndDestroy(&array); |
244 } |
282 } |
245 else |
283 else |
246 { |
284 { |
247 iObserver->ConnectComplete(iBTDevAddrPckgBuf(), |
285 iObserver->ConnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result); |
248 EBTProfileHFP, iActive4ClientReq->iStatus.Int()); |
|
249 } |
286 } |
250 } |
287 } |
251 else |
288 else |
252 { |
289 { |
253 TInt profile = 0; |
290 TInt profile = 0; |
256 TPckg<TInt> pckg(profile); |
293 TPckg<TInt> pckg(profile); |
257 pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); |
294 pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); |
258 } |
295 } |
259 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, ETrue); |
296 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, ETrue); |
260 } |
297 } |
261 delete iActive4ClientReq; |
|
262 iActive4ClientReq = NULL; |
|
263 break; |
298 break; |
264 } |
299 } |
265 case ERequestDisconnect: |
300 case ERequestDisconnect: |
266 { |
301 { |
267 if (iActive4ClientReq->iStatus.Int() != KErrNone) |
302 if (result != KErrNone) |
268 { |
303 { |
269 iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), |
304 iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result); |
270 EBTProfileHFP, iActive4ClientReq->iStatus.Int()); |
|
271 } |
305 } |
272 else |
306 else |
273 { |
307 { |
274 TInt profile = 0; |
308 TInt profile = 0; |
275 if (iDiagnostic.Length() >= sizeof(TInt)) |
309 if (iDiagnostic.Length() >= sizeof(TInt)) |
276 { |
310 { |
277 TPckg<TInt> pckg(profile); |
311 TPckg<TInt> pckg(profile); |
278 pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); |
312 pckg.Copy(iDiagnostic.Mid(0, sizeof(TInt))); |
279 } |
313 } |
280 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, EFalse); |
314 ReportProfileConnectionEvents(iBTDevAddrPckgBuf(), profile, EFalse); |
281 } |
315 } |
282 delete iActive4ClientReq; |
|
283 iActive4ClientReq = NULL; |
|
284 break; |
316 break; |
285 } |
317 } |
286 case ERequestDisconnectAll: |
318 case ERequestDisconnectAll: |
287 { |
319 { |
288 iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), |
320 iObserver->DisconnectComplete(iBTDevAddrPckgBuf(), EBTProfileHFP, result); |
289 EBTProfileHFP, iActive4ClientReq->iStatus.Int()); |
321 break; |
290 break; |
|
291 } |
322 } |
292 } |
323 } |
293 } |
324 } |
294 |
325 |
295 void CBtAudioManPlugin::CancelRequest(CBasrvActive& aActive) |
326 void CBtAudioManPlugin::CancelRequest(CBasrvActive& aActive) |
296 { |
327 { |
297 if (aActive.RequestId() == ENotifyProfileStatusChange ) |
328 if (aActive.RequestId() == ENotifyProfileStatusChange) |
298 { |
329 { |
299 iClient.CancelNotifyConnectionStatus(); |
330 iClient.CancelNotifyConnectionStatus(); |
300 } |
331 } |
301 else if (aActive.RequestId() == ERequestConnect ) |
332 else if (aActive.RequestId() == ERequestConnect) |
302 { |
333 { |
303 iClient.CancelConnectToAccessory(); |
334 iClient.CancelConnectToAccessory(); |
304 } |
335 } |
305 } |
336 } |
306 |
337 |
310 } |
341 } |
311 |
342 |
312 void CBtAudioManPlugin::ConstructL() |
343 void CBtAudioManPlugin::ConstructL() |
313 { |
344 { |
314 LEAVE_IF_ERROR(iClient.Connect()); |
345 LEAVE_IF_ERROR(iClient.Connect()); |
|
346 // Create the handler for profile notifications |
315 iActive4ProfileStatus = CBasrvActive::NewL(*this, CActive::EPriorityStandard, ENotifyProfileStatusChange); |
347 iActive4ProfileStatus = CBasrvActive::NewL(*this, CActive::EPriorityStandard, ENotifyProfileStatusChange); |
|
348 NotifyConnectionStatus(); |
|
349 // Create the handler for active requests (connect, disconnect, etc.) |
|
350 iActive4ClientReq = CBasrvActive::New(*this, CActive::EPriorityStandard, ERequestConnect); |
|
351 } |
|
352 |
|
353 void CBtAudioManPlugin::NotifyConnectionStatus() |
|
354 { |
316 iClient.NotifyConnectionStatus(iProfileStatusPckg, iActive4ProfileStatus->iStatus); |
355 iClient.NotifyConnectionStatus(iProfileStatusPckg, iActive4ProfileStatus->iStatus); |
317 iActive4ProfileStatus->GoActive(); |
356 iActive4ProfileStatus->GoActive(); |
318 } |
357 } |
319 |
358 |
320 TInt CBtAudioManPlugin::HandleAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId) |
359 TInt CBtAudioManPlugin::ReconnectIfNeccessary() |
321 { |
360 { |
322 TInt err = KErrNone; |
361 TInt err = KErrNone; |
323 if (! iClient.Handle() ) |
362 if (iClient.Handle() == KNullHandle) |
324 { |
363 { |
|
364 TRACE_INFO((_L8("Handle to Audio Man Server is not valid, connecting again..."))) |
325 err = iClient.Connect(); |
365 err = iClient.Connect(); |
326 } |
366 TRACE_INFO((_L8("... reconnection result = %d"), err)) |
327 if ( err ) |
367 if(!err) |
328 { |
368 { |
329 return err; |
369 // Now reconnected, we should start status notifications again... |
330 } |
370 NotifyConnectionStatus(); |
331 if ( iActive4ClientReq ) |
371 } |
332 { |
372 } |
|
373 return err; |
|
374 } |
|
375 |
|
376 TInt CBtAudioManPlugin::PrepareAsyncRequest(const TBTDevAddr& aAddr, TInt aRequestId) |
|
377 { |
|
378 TInt err = KErrNone; |
|
379 err = ReconnectIfNeccessary(); |
|
380 if (!err && iActive4ClientReq->IsActive()) |
|
381 { |
|
382 // I would normally expect KErrInUse, so as to distinguish this failure from running out of message slots |
333 err = KErrServerBusy; |
383 err = KErrServerBusy; |
334 } |
384 } |
335 if (!err) |
385 if (!err) |
336 { |
386 { |
337 iActive4ClientReq = CBasrvActive::New(*this, CActive::EPriorityStandard, aRequestId); |
387 iBTDevAddrPckgBuf() = aAddr; |
338 if (iActive4ClientReq) |
388 iActive4ClientReq->SetRequestId(aRequestId); |
339 { |
|
340 iBTDevAddrPckgBuf() = aAddr; |
|
341 if (aRequestId == ERequestConnect) |
|
342 { |
|
343 iDiagnostic.Zero(); |
|
344 iClient.ConnectToAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic); |
|
345 } |
|
346 else if (aRequestId == ERequestDisconnect) |
|
347 { |
|
348 iClient.DisconnectAccessory(iActive4ClientReq->iStatus, iBTDevAddrPckgBuf, iDiagnostic); |
|
349 } |
|
350 else // if (aRequestId == ERequestDisconnectAll) |
|
351 { |
|
352 iClient.DisconnectAllGracefully(iActive4ClientReq->iStatus); |
|
353 } |
|
354 iActive4ClientReq->GoActive(); |
|
355 } |
|
356 else |
|
357 { |
|
358 err = KErrNoMemory; |
|
359 } |
|
360 } |
389 } |
361 return err; |
390 return err; |
362 } |
391 } |
363 |
392 |
364 void CBtAudioManPlugin::ReportProfileConnectionEvents(const TBTDevAddr& aAddr, const TInt aProfiles, TBool aConnected) |
393 void CBtAudioManPlugin::ReportProfileConnectionEvents(const TBTDevAddr& aAddr, const TInt aProfiles, TBool aConnected) |
365 { |
394 { |
366 TRACE_FUNC |
395 TRACE_FUNC |
367 TRACE_INFO((_L("status %d profiles 0x%04X"), aConnected, aProfiles)) |
396 TRACE_INFO((_L("status %d profiles 0x%04X"), aConnected, aProfiles)) |
368 TBTEngConnectionStatus status = IsConnected(aAddr); |
397 TBTEngConnectionStatus status = IsConnected(aAddr); |
369 if (iObserver) |
398 if (iObserver) |
370 { |
399 { |
371 if (aConnected) |
400 if (aConnected) |
372 { |
401 { |
373 if (aProfiles & EHFP) |
402 if (aProfiles & EHFP) |
383 iObserver->ConnectComplete(aAddr, EBTProfileA2DP, KErrNone); |
412 iObserver->ConnectComplete(aAddr, EBTProfileA2DP, KErrNone); |
384 } |
413 } |
385 } |
414 } |
386 else |
415 else |
387 { |
416 { |
388 if( status != EBTEngConnected ) |
417 if (status != EBTEngConnected) |
389 { |
418 { |
390 if (aProfiles & EHFP) |
419 if (aProfiles & EHFP) |
391 { |
420 { |
392 iObserver->DisconnectComplete(aAddr, EBTProfileHFP, KErrNone); |
421 iObserver->DisconnectComplete(aAddr, EBTProfileHFP, KErrNone); |
393 } |
422 } |
394 if (aProfiles & EHSP) |
423 if (aProfiles & EHSP) |
395 { |
424 { |
396 iObserver->DisconnectComplete(aAddr, EBTProfileHSP, KErrNone); |
425 iObserver->DisconnectComplete(aAddr, EBTProfileHSP, KErrNone); |
397 } |
426 } |
398 if (aProfiles & EStereo) |
427 if (aProfiles & EStereo) |
399 { |
428 { |
400 iObserver->DisconnectComplete(aAddr, EBTProfileA2DP, KErrNone); |
429 iObserver->DisconnectComplete(aAddr, EBTProfileA2DP, KErrNone); |
401 } |
430 } |
402 } |
431 } |
403 } |
432 } |
404 } |
433 } |
405 } |
434 } |
406 |
435 |
407 // |
436 // |