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 { |
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); |
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 // |