dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:b307165ddcba
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "base/basictypes.h"
8
9 #include "BluetoothHfpManager.h"
10 #include "BluetoothProfileController.h"
11 #include "BluetoothUtils.h"
12
13 #include "jsapi.h"
14 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
15 #include "mozilla/Services.h"
16 #include "mozilla/StaticPtr.h"
17 #include "nsContentUtils.h"
18 #include "nsIAudioManager.h"
19 #include "nsIDOMIccInfo.h"
20 #include "nsIDOMMobileConnection.h"
21 #include "nsIIccProvider.h"
22 #include "nsIMobileConnectionProvider.h"
23 #include "nsIObserverService.h"
24 #include "nsISettingsService.h"
25 #include "nsITelephonyProvider.h"
26 #include "nsRadioInterfaceLayer.h"
27 #include "nsServiceManagerUtils.h"
28 #include "nsThreadUtils.h"
29
30 #define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
31 #define AUDIO_VOLUME_BT_SCO_ID "audio.volume.bt_sco"
32
33 /**
34 * Dispatch task with arguments to main thread.
35 */
36 #define BT_HF_DISPATCH_MAIN(args...) \
37 NS_DispatchToMainThread(new MainThreadTask(args))
38
39 /**
40 * Process bluedroid callbacks with corresponding handlers.
41 */
42 #define BT_HF_PROCESS_CB(func, args...) \
43 do { \
44 NS_ENSURE_TRUE_VOID(sBluetoothHfpManager); \
45 sBluetoothHfpManager->func(args); \
46 } while(0)
47
48 using namespace mozilla;
49 using namespace mozilla::ipc;
50 USING_BLUETOOTH_NAMESPACE
51
52 namespace {
53 StaticRefPtr<BluetoothHfpManager> sBluetoothHfpManager;
54 static const bthf_interface_t* sBluetoothHfpInterface = nullptr;
55
56 bool sInShutdown = false;
57
58 // Wait for 2 seconds for Dialer processing event 'BLDN'. '2' seconds is a
59 // magic number. The mechanism should be revised once we can get call history.
60 static int sWaitingForDialingInterval = 2000; //unit: ms
61
62 // Wait 3.7 seconds until Dialer stops playing busy tone. '3' seconds is the
63 // time window set in Dialer and the extra '0.7' second is a magic number.
64 // The mechanism should be revised once we know the exact time at which
65 // Dialer stops playing.
66 static int sBusyToneInterval = 3700; //unit: ms
67 } // anonymous namespace
68
69 // Main thread task commands
70 enum MainThreadTaskCmd {
71 NOTIFY_CONN_STATE_CHANGED,
72 NOTIFY_DIALER,
73 NOTIFY_SCO_VOLUME_CHANGED,
74 POST_TASK_RESPOND_TO_BLDN,
75 POST_TASK_CLOSE_SCO
76 };
77
78 static void
79 ConnectionStateCallback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr)
80 {
81 BT_HF_PROCESS_CB(ProcessConnectionState, state, bd_addr);
82 }
83
84 static void
85 AudioStateCallback(bthf_audio_state_t state, bt_bdaddr_t* bd_addr)
86 {
87 BT_HF_PROCESS_CB(ProcessAudioState, state, bd_addr);
88 }
89
90 static void
91 VoiceRecognitionCallback(bthf_vr_state_t state)
92 {
93 // No support
94 }
95
96 static void
97 AnswerCallCallback()
98 {
99 BT_HF_PROCESS_CB(ProcessAnswerCall);
100 }
101
102 static void
103 HangupCallCallback()
104 {
105 BT_HF_PROCESS_CB(ProcessHangupCall);
106 }
107
108 static void
109 VolumeControlCallback(bthf_volume_type_t type, int volume)
110 {
111 BT_HF_PROCESS_CB(ProcessVolumeControl, type, volume);
112 }
113
114 static void
115 DialCallCallback(char *number)
116 {
117 BT_HF_PROCESS_CB(ProcessDialCall, number);
118 }
119
120 static void
121 DtmfCmdCallback(char dtmf)
122 {
123 BT_HF_PROCESS_CB(ProcessDtmfCmd, dtmf);
124 }
125
126 static void
127 NoiceReductionCallback(bthf_nrec_t nrec)
128 {
129 // No support
130 }
131
132 static void
133 AtChldCallback(bthf_chld_type_t chld)
134 {
135 BT_HF_PROCESS_CB(ProcessAtChld, chld);
136 }
137
138 static void
139 AtCnumCallback()
140 {
141 BT_HF_PROCESS_CB(ProcessAtCnum);
142 }
143
144 static void
145 AtCindCallback()
146 {
147 BT_HF_PROCESS_CB(ProcessAtCind);
148 }
149
150 static void
151 AtCopsCallback()
152 {
153 BT_HF_PROCESS_CB(ProcessAtCops);
154 }
155
156 static void
157 AtClccCallback()
158 {
159 BT_HF_PROCESS_CB(ProcessAtClcc);
160 }
161
162 static void
163 UnknownAtCallback(char *at_string)
164 {
165 BT_HF_PROCESS_CB(ProcessUnknownAt, at_string);
166 }
167
168 static void
169 KeyPressedCallback()
170 {
171 BT_HF_PROCESS_CB(ProcessKeyPressed);
172 }
173
174 static bthf_callbacks_t sBluetoothHfpCallbacks = {
175 sizeof(sBluetoothHfpCallbacks),
176 ConnectionStateCallback,
177 AudioStateCallback,
178 VoiceRecognitionCallback,
179 AnswerCallCallback,
180 HangupCallCallback,
181 VolumeControlCallback,
182 DialCallCallback,
183 DtmfCmdCallback,
184 NoiceReductionCallback,
185 AtChldCallback,
186 AtCnumCallback,
187 AtCindCallback,
188 AtCopsCallback,
189 AtClccCallback,
190 UnknownAtCallback,
191 KeyPressedCallback
192 };
193
194 static bool
195 IsValidDtmf(const char aChar) {
196 // Valid DTMF: [*#0-9ABCD]
197 return (aChar == '*' || aChar == '#') ||
198 (aChar >= '0' && aChar <= '9') ||
199 (aChar >= 'A' && aChar <= 'D');
200 }
201
202 class BluetoothHfpManager::GetVolumeTask : public nsISettingsServiceCallback
203 {
204 public:
205 NS_DECL_ISUPPORTS
206
207 NS_IMETHOD
208 Handle(const nsAString& aName, JS::Handle<JS::Value> aResult)
209 {
210 MOZ_ASSERT(NS_IsMainThread());
211
212 JSContext *cx = nsContentUtils::GetCurrentJSContext();
213 NS_ENSURE_TRUE(cx, NS_OK);
214
215 if (!aResult.isNumber()) {
216 BT_WARNING("'" AUDIO_VOLUME_BT_SCO_ID "' is not a number!");
217 return NS_OK;
218 }
219
220 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
221 hfp->mCurrentVgs = aResult.toNumber();
222
223 return NS_OK;
224 }
225
226 NS_IMETHOD
227 HandleError(const nsAString& aName)
228 {
229 BT_WARNING("Unable to get value for '" AUDIO_VOLUME_BT_SCO_ID "'");
230 return NS_OK;
231 }
232 };
233
234 class BluetoothHfpManager::CloseScoTask : public Task
235 {
236 private:
237 void Run() MOZ_OVERRIDE
238 {
239 MOZ_ASSERT(sBluetoothHfpManager);
240 sBluetoothHfpManager->DisconnectSco();
241 }
242 };
243
244 class BluetoothHfpManager::RespondToBLDNTask : public Task
245 {
246 private:
247 void Run() MOZ_OVERRIDE
248 {
249 MOZ_ASSERT(sBluetoothHfpManager);
250
251 if (!sBluetoothHfpManager->mDialingRequestProcessed) {
252 sBluetoothHfpManager->mDialingRequestProcessed = true;
253 sBluetoothHfpManager->SendResponse(BTHF_AT_RESPONSE_ERROR);
254 }
255 }
256 };
257
258 class BluetoothHfpManager::MainThreadTask : public nsRunnable
259 {
260 public:
261 MainThreadTask(const int aCommand,
262 const nsAString& aParameter = EmptyString())
263 : mCommand(aCommand), mParameter(aParameter)
264 {
265 }
266
267 nsresult Run()
268 {
269 MOZ_ASSERT(NS_IsMainThread());
270 MOZ_ASSERT(sBluetoothHfpManager);
271
272 switch (mCommand) {
273 case MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED:
274 sBluetoothHfpManager->NotifyConnectionStateChanged(mParameter);
275 break;
276 case MainThreadTaskCmd::NOTIFY_DIALER:
277 sBluetoothHfpManager->NotifyDialer(mParameter);
278 break;
279 case MainThreadTaskCmd::NOTIFY_SCO_VOLUME_CHANGED:
280 {
281 nsCOMPtr<nsIObserverService> os =
282 mozilla::services::GetObserverService();
283 NS_ENSURE_TRUE(os, NS_OK);
284
285 os->NotifyObservers(nullptr, "bluetooth-volume-change",
286 mParameter.get());
287 }
288 break;
289 case MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN:
290 MessageLoop::current()->
291 PostDelayedTask(FROM_HERE, new RespondToBLDNTask(),
292 sWaitingForDialingInterval);
293 break;
294 case MainThreadTaskCmd::POST_TASK_CLOSE_SCO:
295 MessageLoop::current()->
296 PostDelayedTask(FROM_HERE, new CloseScoTask(),
297 sBusyToneInterval);
298 break;
299 default:
300 BT_WARNING("MainThreadTask: Unknown command %d", mCommand);
301 break;
302 }
303
304 return NS_OK;
305 }
306
307 private:
308 int mCommand;
309 nsString mParameter;
310 };
311
312 NS_IMPL_ISUPPORTS(BluetoothHfpManager::GetVolumeTask,
313 nsISettingsServiceCallback);
314
315 /**
316 * Call
317 */
318 Call::Call()
319 {
320 Reset();
321 }
322
323 void
324 Call::Set(const nsAString& aNumber, const bool aIsOutgoing)
325 {
326 mNumber = aNumber;
327 mDirection = (aIsOutgoing) ? BTHF_CALL_DIRECTION_OUTGOING :
328 BTHF_CALL_DIRECTION_INCOMING;
329 // Same logic as implementation in ril_worker.js
330 if (aNumber.Length() && aNumber[0] == '+') {
331 mType = BTHF_CALL_ADDRTYPE_INTERNATIONAL;
332 }
333 }
334
335 void
336 Call::Reset()
337 {
338 mState = nsITelephonyProvider::CALL_STATE_DISCONNECTED;
339 mDirection = BTHF_CALL_DIRECTION_OUTGOING;
340 mNumber.Truncate();
341 mType = BTHF_CALL_ADDRTYPE_UNKNOWN;
342 }
343
344 bool
345 Call::IsActive()
346 {
347 return (mState == nsITelephonyProvider::CALL_STATE_CONNECTED);
348 }
349
350 /**
351 * BluetoothHfpManager
352 */
353 BluetoothHfpManager::BluetoothHfpManager() : mPhoneType(PhoneType::NONE)
354 {
355 Reset();
356 }
357
358 void
359 BluetoothHfpManager::ResetCallArray()
360 {
361 mCurrentCallArray.Clear();
362 // Append a call object at the beginning of mCurrentCallArray since call
363 // index from RIL starts at 1.
364 Call call;
365 mCurrentCallArray.AppendElement(call);
366
367 if (mPhoneType == PhoneType::CDMA) {
368 mCdmaSecondCall.Reset();
369 }
370 }
371
372 void
373 BluetoothHfpManager::Reset()
374 {
375 mReceiveVgsFlag = false;
376 mDialingRequestProcessed = true;
377
378 mConnectionState = BTHF_CONNECTION_STATE_DISCONNECTED;
379 mPrevConnectionState = BTHF_CONNECTION_STATE_DISCONNECTED;
380 mAudioState = BTHF_AUDIO_STATE_DISCONNECTED;
381
382 // Phone & Device CIND
383 ResetCallArray();
384 mBattChg = 5;
385 mService = 0;
386 mRoam = 0;
387 mSignal = 0;
388
389 mController = nullptr;
390 }
391
392 bool
393 BluetoothHfpManager::Init()
394 {
395 MOZ_ASSERT(NS_IsMainThread());
396
397 NS_ENSURE_TRUE(InitHfpInterface(), false);
398
399 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
400 NS_ENSURE_TRUE(obs, false);
401
402 if (NS_FAILED(obs->AddObserver(this, MOZSETTINGS_CHANGED_ID, false)) ||
403 NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
404 BT_WARNING("Failed to add observers!");
405 return false;
406 }
407
408 hal::RegisterBatteryObserver(this);
409
410 mListener = new BluetoothRilListener();
411 NS_ENSURE_TRUE(mListener->Listen(true), false);
412
413 nsCOMPtr<nsISettingsService> settings =
414 do_GetService("@mozilla.org/settingsService;1");
415 NS_ENSURE_TRUE(settings, false);
416
417 nsCOMPtr<nsISettingsServiceLock> settingsLock;
418 nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock));
419 NS_ENSURE_SUCCESS(rv, false);
420
421 nsRefPtr<GetVolumeTask> callback = new GetVolumeTask();
422 rv = settingsLock->Get(AUDIO_VOLUME_BT_SCO_ID, callback);
423 NS_ENSURE_SUCCESS(rv, false);
424
425 return true;
426 }
427
428 bool
429 BluetoothHfpManager::InitHfpInterface()
430 {
431 const bt_interface_t* btInf = GetBluetoothInterface();
432 NS_ENSURE_TRUE(btInf, false);
433
434 if (sBluetoothHfpInterface) {
435 sBluetoothHfpInterface->cleanup();
436 sBluetoothHfpInterface = nullptr;
437 }
438
439 bthf_interface_t *interface = (bthf_interface_t *)
440 btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID);
441 NS_ENSURE_TRUE(interface, false);
442
443 NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
444 interface->init(&sBluetoothHfpCallbacks), false);
445 sBluetoothHfpInterface = interface;
446
447 return true;
448 }
449
450 BluetoothHfpManager::~BluetoothHfpManager()
451 {
452 if (!mListener->Listen(false)) {
453 BT_WARNING("Failed to stop listening RIL");
454 }
455 mListener = nullptr;
456
457 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
458 NS_ENSURE_TRUE_VOID(obs);
459
460 if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
461 NS_FAILED(obs->RemoveObserver(this, MOZSETTINGS_CHANGED_ID))) {
462 BT_WARNING("Failed to remove observers!");
463 }
464
465 hal::UnregisterBatteryObserver(this);
466 DeinitHfpInterface();
467 }
468
469 void
470 BluetoothHfpManager::DeinitHfpInterface()
471 {
472 NS_ENSURE_TRUE_VOID(GetBluetoothInterface());
473
474 if (sBluetoothHfpInterface) {
475 sBluetoothHfpInterface->cleanup();
476 sBluetoothHfpInterface = nullptr;
477 }
478 }
479
480 //static
481 BluetoothHfpManager*
482 BluetoothHfpManager::Get()
483 {
484 MOZ_ASSERT(NS_IsMainThread());
485
486 // If sBluetoothHfpManager already exists, exit early
487 if (sBluetoothHfpManager) {
488 return sBluetoothHfpManager;
489 }
490
491 // If we're in shutdown, don't create a new instance
492 NS_ENSURE_FALSE(sInShutdown, nullptr);
493
494 // Create a new instance, register, and return
495 BluetoothHfpManager* manager = new BluetoothHfpManager();
496 NS_ENSURE_TRUE(manager->Init(), nullptr);
497
498 sBluetoothHfpManager = manager;
499 return sBluetoothHfpManager;
500 }
501
502 NS_IMETHODIMP
503 BluetoothHfpManager::Observe(nsISupports* aSubject,
504 const char* aTopic,
505 const char16_t* aData)
506 {
507 if (!strcmp(aTopic, MOZSETTINGS_CHANGED_ID)) {
508 HandleVolumeChanged(nsDependentString(aData));
509 } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
510 HandleShutdown();
511 } else {
512 MOZ_ASSERT(false, "BluetoothHfpManager got unexpected topic!");
513 return NS_ERROR_UNEXPECTED;
514 }
515
516 return NS_OK;
517 }
518
519 void
520 BluetoothHfpManager::Notify(const hal::BatteryInformation& aBatteryInfo)
521 {
522 // Range of battery level: [0, 1], double
523 // Range of CIND::BATTCHG: [0, 5], int
524 mBattChg = (int) ceil(aBatteryInfo.level() * 5.0);
525 UpdateDeviceCIND();
526 }
527
528 void
529 BluetoothHfpManager::ProcessConnectionState(bthf_connection_state_t aState,
530 bt_bdaddr_t* aBdAddress)
531 {
532 BT_LOGR("state %d", aState);
533
534 mPrevConnectionState = mConnectionState;
535 mConnectionState = aState;
536
537 if (aState == BTHF_CONNECTION_STATE_SLC_CONNECTED) {
538 BdAddressTypeToString(aBdAddress, mDeviceAddress);
539 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED,
540 NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
541 } else if (aState == BTHF_CONNECTION_STATE_DISCONNECTED) {
542 DisconnectSco();
543 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED,
544 NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
545 }
546 }
547
548 void
549 BluetoothHfpManager::ProcessAudioState(bthf_audio_state_t aState,
550 bt_bdaddr_t* aBdAddress)
551 {
552 BT_LOGR("state %d", aState);
553
554 mAudioState = aState;
555
556 if (aState == BTHF_AUDIO_STATE_CONNECTED ||
557 aState == BTHF_AUDIO_STATE_DISCONNECTED) {
558 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_CONN_STATE_CHANGED,
559 NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
560 }
561 }
562
563 void
564 BluetoothHfpManager::ProcessAnswerCall()
565 {
566 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
567 NS_LITERAL_STRING("ATA"));
568 }
569
570 void
571 BluetoothHfpManager::ProcessHangupCall()
572 {
573 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
574 NS_LITERAL_STRING("CHUP"));
575 }
576
577 void
578 BluetoothHfpManager::ProcessVolumeControl(bthf_volume_type_t aType,
579 int aVolume)
580 {
581 NS_ENSURE_TRUE_VOID(aVolume >= 0 && aVolume <= 15);
582
583 if (aType == BTHF_VOLUME_TYPE_MIC) {
584 mCurrentVgm = aVolume;
585 } else if (aType == BTHF_VOLUME_TYPE_SPK) {
586 mReceiveVgsFlag = true;
587
588 if (aVolume == mCurrentVgs) {
589 // Keep current volume
590 return;
591 }
592
593 nsString data;
594 data.AppendInt(aVolume);
595 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_SCO_VOLUME_CHANGED, data);
596 }
597 }
598
599 void
600 BluetoothHfpManager::ProcessDtmfCmd(char aDtmf)
601 {
602 NS_ENSURE_TRUE_VOID(IsValidDtmf(aDtmf));
603
604 nsAutoCString message("VTS=");
605 message += aDtmf;
606 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
607 NS_ConvertUTF8toUTF16(message));
608 }
609
610 void
611 BluetoothHfpManager::ProcessAtChld(bthf_chld_type_t aChld)
612 {
613 nsAutoCString message("CHLD=");
614 message.AppendInt((int)aChld);
615 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
616 NS_ConvertUTF8toUTF16(message));
617
618 SendResponse(BTHF_AT_RESPONSE_OK);
619 }
620
621 void BluetoothHfpManager::ProcessDialCall(char *aNumber)
622 {
623 nsAutoCString message(aNumber);
624
625 // There are three cases based on aNumber,
626 // 1) Empty value: Redial, BLDN
627 // 2) >xxx: Memory dial, ATD>xxx
628 // 3) xxx: Normal dial, ATDxxx
629 // We need to respond OK/Error for dial requests for every case listed above,
630 // 1) and 2): Respond in either RespondToBLDNTask or
631 // HandleCallStateChanged()
632 // 3): Respond here
633 if (message.IsEmpty()) {
634 mDialingRequestProcessed = false;
635 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
636 NS_LITERAL_STRING("BLDN"));
637 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN);
638 } else if (message[0] == '>') {
639 mDialingRequestProcessed = false;
640 nsAutoCString newMsg("ATD");
641 newMsg += StringHead(message, message.Length() - 1);
642 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
643 NS_ConvertUTF8toUTF16(newMsg));
644 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN);
645 } else {
646 nsAutoCString newMsg("ATD");
647 newMsg += StringHead(message, message.Length() - 1);
648 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
649 NS_ConvertUTF8toUTF16(newMsg));
650 SendResponse(BTHF_AT_RESPONSE_OK);
651 }
652 }
653
654 void
655 BluetoothHfpManager::ProcessAtCnum()
656 {
657 if (!mMsisdn.IsEmpty()) {
658 nsAutoCString message("+CNUM: ,\"");
659 message.Append(NS_ConvertUTF16toUTF8(mMsisdn).get());
660 message.AppendLiteral("\",");
661 message.AppendInt(BTHF_CALL_ADDRTYPE_UNKNOWN);
662 message.AppendLiteral(",,4");
663
664 SendLine(message.get());
665 }
666
667 SendResponse(BTHF_AT_RESPONSE_OK);
668 }
669
670 void
671 BluetoothHfpManager::ProcessAtCind()
672 {
673 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
674
675 int numActive = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_CONNECTED);
676 int numHeld = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_HELD);
677
678 bt_status_t status = sBluetoothHfpInterface->cind_response(
679 mService,
680 numActive,
681 numHeld,
682 ConvertToBthfCallState(GetCallSetupState()),
683 mSignal,
684 mRoam,
685 mBattChg);
686 NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS);
687 }
688
689 void
690 BluetoothHfpManager::ProcessAtCops()
691 {
692 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
693 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
694 sBluetoothHfpInterface->cops_response(
695 NS_ConvertUTF16toUTF8(mOperatorName).get()));
696 }
697
698 void
699 BluetoothHfpManager::ProcessAtClcc()
700 {
701 uint32_t callNumbers = mCurrentCallArray.Length();
702 uint32_t i;
703 for (i = 1; i < callNumbers; i++) {
704 SendCLCC(mCurrentCallArray[i], i);
705 }
706
707 if (!mCdmaSecondCall.mNumber.IsEmpty()) {
708 MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
709 MOZ_ASSERT(i == 2);
710
711 SendCLCC(mCdmaSecondCall, 2);
712 }
713
714 SendResponse(BTHF_AT_RESPONSE_OK);
715 }
716
717 void
718 BluetoothHfpManager::ProcessUnknownAt(char *aAtString)
719 {
720 BT_LOGR("[%s]", aAtString);
721
722 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
723 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
724 sBluetoothHfpInterface->at_response(BTHF_AT_RESPONSE_ERROR, 0));
725 }
726
727 void
728 BluetoothHfpManager::ProcessKeyPressed()
729 {
730 bool hasActiveCall =
731 (FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED) > 0);
732
733 // Refer to AOSP HeadsetStateMachine.processKeyPressed
734 if (FindFirstCall(nsITelephonyProvider::CALL_STATE_INCOMING)
735 && !hasActiveCall) {
736 /**
737 * Bluetooth HSP spec 4.2.2
738 * There is an incoming call, notify Dialer to pick up the phone call
739 * and SCO will be established after we get the CallStateChanged event
740 * indicating the call is answered successfully.
741 */
742 ProcessAnswerCall();
743 } else if (hasActiveCall) {
744 if (!IsScoConnected()) {
745 /**
746 * Bluetooth HSP spec 4.3
747 * If there's no SCO, set up a SCO link.
748 */
749 ConnectSco();
750 } else {
751 /**
752 * Bluetooth HSP spec 4.5
753 * There are two ways to release SCO: sending CHUP to dialer or closing
754 * SCO socket directly. We notify dialer only if there is at least one
755 * active call.
756 */
757 ProcessHangupCall();
758 }
759 } else {
760 // BLDN
761 mDialingRequestProcessed = false;
762 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::NOTIFY_DIALER,
763 NS_LITERAL_STRING("BLDN"));
764 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_RESPOND_TO_BLDN);
765 }
766 }
767
768 void
769 BluetoothHfpManager::NotifyConnectionStateChanged(const nsAString& aType)
770 {
771 MOZ_ASSERT(NS_IsMainThread());
772
773 // Notify Gecko observers
774 nsCOMPtr<nsIObserverService> obs =
775 do_GetService("@mozilla.org/observer-service;1");
776 NS_ENSURE_TRUE_VOID(obs);
777
778 if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
779 mDeviceAddress.get()))) {
780 BT_WARNING("Failed to notify observsers!");
781 }
782
783 // Dispatch an event of status change
784 bool status;
785 nsAutoString eventName;
786 if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
787 status = IsConnected();
788 eventName.AssignLiteral(HFP_STATUS_CHANGED_ID);
789 } else if (aType.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) {
790 status = IsScoConnected();
791 eventName.AssignLiteral(SCO_STATUS_CHANGED_ID);
792 } else {
793 MOZ_ASSERT(false);
794 return;
795 }
796
797 DispatchStatusChangedEvent(eventName, mDeviceAddress, status);
798
799 // Notify profile controller
800 if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
801 if (IsConnected()) {
802 MOZ_ASSERT(mListener);
803
804 // Enumerate current calls
805 mListener->EnumerateCalls();
806
807 OnConnect(EmptyString());
808 } else if (mConnectionState == BTHF_CONNECTION_STATE_DISCONNECTED) {
809 mDeviceAddress.AssignLiteral(BLUETOOTH_ADDRESS_NONE);
810 if (mPrevConnectionState == BTHF_CONNECTION_STATE_DISCONNECTED) {
811 // Bug 979160: This implies the outgoing connection failure.
812 // When the outgoing hfp connection fails, state changes to disconnected
813 // state. Since bluedroid would not report connecting state, but only
814 // report connected/disconnected.
815 OnConnect(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
816 } else {
817 OnDisconnect(EmptyString());
818 }
819 Reset();
820 }
821 }
822 }
823
824 void
825 BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
826 {
827 NS_NAMED_LITERAL_STRING(type, "bluetooth-dialer-command");
828 InfallibleTArray<BluetoothNamedValue> parameters;
829
830 BT_APPEND_NAMED_VALUE(parameters, "command", nsString(aCommand));
831
832 BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
833 }
834
835 void
836 BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
837 {
838 MOZ_ASSERT(NS_IsMainThread());
839
840 // The string that we're interested in will be a JSON string that looks like:
841 // {"key":"volumeup", "value":10}
842 // {"key":"volumedown", "value":2}
843 JSContext* cx = nsContentUtils::GetSafeJSContext();
844 NS_ENSURE_TRUE_VOID(cx);
845
846 JS::Rooted<JS::Value> val(cx);
847 NS_ENSURE_TRUE_VOID(JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val));
848 NS_ENSURE_TRUE_VOID(val.isObject());
849
850 JS::Rooted<JSObject*> obj(cx, &val.toObject());
851 JS::Rooted<JS::Value> key(cx);
852 if (!JS_GetProperty(cx, obj, "key", &key) || !key.isString()) {
853 return;
854 }
855
856 bool match;
857 if (!JS_StringEqualsAscii(cx, key.toString(), AUDIO_VOLUME_BT_SCO_ID, &match) ||
858 !match) {
859 return;
860 }
861
862 JS::Rooted<JS::Value> value(cx);
863 if (!JS_GetProperty(cx, obj, "value", &value) ||
864 !value.isNumber()) {
865 return;
866 }
867
868 mCurrentVgs = value.toNumber();
869
870 // Adjust volume by headset and we don't have to send volume back to headset
871 if (mReceiveVgsFlag) {
872 mReceiveVgsFlag = false;
873 return;
874 }
875
876 // Only send volume back when there's a connected headset
877 if (IsConnected()) {
878 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
879 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
880 sBluetoothHfpInterface->volume_control(BTHF_VOLUME_TYPE_SPK,
881 mCurrentVgs));
882 }
883 }
884
885 void
886 BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
887 {
888 nsCOMPtr<nsIMobileConnectionProvider> connection =
889 do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
890 NS_ENSURE_TRUE_VOID(connection);
891
892 nsCOMPtr<nsIDOMMozMobileConnectionInfo> voiceInfo;
893 connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo));
894 NS_ENSURE_TRUE_VOID(voiceInfo);
895
896 nsString type;
897 voiceInfo->GetType(type);
898 mPhoneType = GetPhoneType(type);
899
900 bool roaming;
901 voiceInfo->GetRoaming(&roaming);
902 mRoam = (roaming) ? 1 : 0;
903
904 // Service
905 nsString regState;
906 voiceInfo->GetState(regState);
907 mService = (regState.EqualsLiteral("registered")) ? 1 : 0;
908
909 // Signal
910 JSContext* cx = nsContentUtils::GetSafeJSContext();
911 NS_ENSURE_TRUE_VOID(cx);
912 JS::Rooted<JS::Value> value(cx);
913 voiceInfo->GetRelSignalStrength(&value);
914 NS_ENSURE_TRUE_VOID(value.isNumber());
915 mSignal = (int)ceil(value.toNumber() / 20.0);
916
917 UpdateDeviceCIND();
918
919 // Operator name
920 nsCOMPtr<nsIDOMMozMobileNetworkInfo> network;
921 voiceInfo->GetNetwork(getter_AddRefs(network));
922 NS_ENSURE_TRUE_VOID(network);
923 network->GetLongName(mOperatorName);
924
925 // According to GSM 07.07, "<format> indicates if the format is alphanumeric
926 // or numeric; long alphanumeric format can be upto 16 characters long and
927 // short format up to 8 characters (refer GSM MoU SE.13 [9])..."
928 // However, we found that the operator name may sometimes be longer than 16
929 // characters. After discussion, we decided to fix this here but not in RIL
930 // or modem.
931 //
932 // Please see Bug 871366 for more information.
933 if (mOperatorName.Length() > 16) {
934 BT_WARNING("The operator name was longer than 16 characters. We cut it.");
935 mOperatorName.Left(mOperatorName, 16);
936 }
937 }
938
939 void
940 BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
941 {
942 nsCOMPtr<nsIIccProvider> icc =
943 do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
944 NS_ENSURE_TRUE_VOID(icc);
945
946 nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
947 icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
948 NS_ENSURE_TRUE_VOID(iccInfo);
949
950 nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
951 NS_ENSURE_TRUE_VOID(gsmIccInfo);
952 gsmIccInfo->GetMsisdn(mMsisdn);
953 }
954
955 void
956 BluetoothHfpManager::HandleShutdown()
957 {
958 MOZ_ASSERT(NS_IsMainThread());
959 sInShutdown = true;
960 Disconnect(nullptr);
961 DisconnectSco();
962 sBluetoothHfpManager = nullptr;
963 }
964
965 void
966 BluetoothHfpManager::SendCLCC(Call& aCall, int aIndex)
967 {
968 NS_ENSURE_TRUE_VOID(aCall.mState !=
969 nsITelephonyProvider::CALL_STATE_DISCONNECTED);
970 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
971
972 bthf_call_state_t callState = ConvertToBthfCallState(aCall.mState);
973
974 if (mPhoneType == PhoneType::CDMA && aIndex == 1 && aCall.IsActive()) {
975 callState = (mCdmaSecondCall.IsActive()) ? BTHF_CALL_STATE_HELD :
976 BTHF_CALL_STATE_ACTIVE;
977 }
978
979 if (callState == BTHF_CALL_STATE_INCOMING &&
980 FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED)) {
981 callState = BTHF_CALL_STATE_WAITING;
982 }
983
984 bt_status_t status = sBluetoothHfpInterface->clcc_response(
985 aIndex,
986 aCall.mDirection,
987 callState,
988 BTHF_CALL_TYPE_VOICE,
989 BTHF_CALL_MPTY_TYPE_SINGLE,
990 NS_ConvertUTF16toUTF8(aCall.mNumber).get(),
991 aCall.mType);
992 NS_ENSURE_TRUE_VOID(status == BT_STATUS_SUCCESS);
993 }
994
995 void
996 BluetoothHfpManager::SendLine(const char* aMessage)
997 {
998 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
999 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
1000 sBluetoothHfpInterface->formatted_at_response(aMessage));
1001 }
1002
1003 void
1004 BluetoothHfpManager::SendResponse(bthf_at_response_t aResponseCode)
1005 {
1006 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
1007 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
1008 sBluetoothHfpInterface->at_response(aResponseCode, 0));
1009 }
1010
1011 void
1012 BluetoothHfpManager::UpdatePhoneCIND(uint32_t aCallIndex)
1013 {
1014 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
1015
1016 int numActive = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_CONNECTED);
1017 int numHeld = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_HELD);
1018 bthf_call_state_t callSetupState =
1019 ConvertToBthfCallState(GetCallSetupState());
1020 nsAutoCString number =
1021 NS_ConvertUTF16toUTF8(mCurrentCallArray[aCallIndex].mNumber);
1022 bthf_call_addrtype_t type = mCurrentCallArray[aCallIndex].mType;
1023
1024 BT_LOGR("[%d] state %d => BTHF: active[%d] held[%d] setupstate[%d]",
1025 aCallIndex, mCurrentCallArray[aCallIndex].mState,
1026 numActive, numHeld, callSetupState);
1027
1028 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
1029 sBluetoothHfpInterface->phone_state_change(
1030 numActive, numHeld, callSetupState, number.get(), type));
1031 }
1032
1033 void
1034 BluetoothHfpManager::UpdateDeviceCIND()
1035 {
1036 NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
1037 NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
1038 sBluetoothHfpInterface->device_status_notification(
1039 (bthf_network_state_t) mService,
1040 (bthf_service_type_t) mRoam,
1041 mSignal,
1042 mBattChg));
1043 }
1044
1045 uint32_t
1046 BluetoothHfpManager::FindFirstCall(uint16_t aState)
1047 {
1048 uint32_t callLength = mCurrentCallArray.Length();
1049
1050 for (uint32_t i = 1; i < callLength; ++i) {
1051 if (mCurrentCallArray[i].mState == aState) {
1052 return i;
1053 }
1054 }
1055
1056 return 0;
1057 }
1058
1059 uint32_t
1060 BluetoothHfpManager::GetNumberOfCalls(uint16_t aState)
1061 {
1062 uint32_t num = 0;
1063 uint32_t callLength = mCurrentCallArray.Length();
1064
1065 for (uint32_t i = 1; i < callLength; ++i) {
1066 if (mCurrentCallArray[i].mState == aState) {
1067 ++num;
1068 }
1069 }
1070
1071 return num;
1072 }
1073
1074 uint16_t
1075 BluetoothHfpManager::GetCallSetupState()
1076 {
1077 uint32_t callLength = mCurrentCallArray.Length();
1078
1079 for (uint32_t i = 1; i < callLength; ++i) {
1080 switch (mCurrentCallArray[i].mState) {
1081 case nsITelephonyProvider::CALL_STATE_INCOMING:
1082 case nsITelephonyProvider::CALL_STATE_DIALING:
1083 case nsITelephonyProvider::CALL_STATE_ALERTING:
1084 return mCurrentCallArray[i].mState;
1085 default:
1086 break;
1087 }
1088 }
1089
1090 return nsITelephonyProvider::CALL_STATE_DISCONNECTED;
1091 }
1092
1093 bthf_call_state_t
1094 BluetoothHfpManager::ConvertToBthfCallState(int aCallState)
1095 {
1096 bthf_call_state_t state;
1097
1098 // Refer to AOSP BluetoothPhoneService.convertCallState
1099 if (aCallState == nsITelephonyProvider::CALL_STATE_INCOMING) {
1100 state = BTHF_CALL_STATE_INCOMING;
1101 } else if (aCallState == nsITelephonyProvider::CALL_STATE_DIALING) {
1102 state = BTHF_CALL_STATE_DIALING;
1103 } else if (aCallState == nsITelephonyProvider::CALL_STATE_ALERTING) {
1104 state = BTHF_CALL_STATE_ALERTING;
1105 } else if (aCallState == nsITelephonyProvider::CALL_STATE_CONNECTED) {
1106 state = BTHF_CALL_STATE_ACTIVE;
1107 } else if (aCallState == nsITelephonyProvider::CALL_STATE_HELD) {
1108 state = BTHF_CALL_STATE_HELD;
1109 } else { // disconnected
1110 state = BTHF_CALL_STATE_IDLE;
1111 }
1112
1113 return state;
1114 }
1115
1116 bool
1117 BluetoothHfpManager::IsTransitionState(uint16_t aCallState, bool aIsConference)
1118 {
1119 /**
1120 * Regard this callstate change as during CHLD=2 transition state if
1121 * - the call becomes active, and numActive > 1
1122 * - the call becomes held, and numHeld > 1 or an incoming call exists
1123 *
1124 * TODO:
1125 * 1) handle CHLD=1 transition state
1126 * 2) handle conference call cases
1127 */
1128 if (!aIsConference) {
1129 switch (aCallState) {
1130 case nsITelephonyProvider::CALL_STATE_CONNECTED:
1131 return (GetNumberOfCalls(aCallState) > 1);
1132 case nsITelephonyProvider::CALL_STATE_HELD:
1133 return (GetNumberOfCalls(aCallState) > 1 ||
1134 FindFirstCall(nsITelephonyProvider::CALL_STATE_INCOMING));
1135 default:
1136 break;
1137 }
1138 }
1139
1140 return false;
1141 }
1142
1143 void
1144 BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
1145 uint16_t aCallState,
1146 const nsAString& aError,
1147 const nsAString& aNumber,
1148 const bool aIsOutgoing,
1149 const bool aIsConference,
1150 bool aSend)
1151 {
1152 // aCallIndex can be UINT32_MAX for the pending outgoing call state update.
1153 // aCallIndex will be updated again after real call state changes. See Bug
1154 // 990467.
1155 if (aCallIndex == UINT32_MAX) {
1156 return;
1157 }
1158
1159 // Update call state only
1160 while (aCallIndex >= mCurrentCallArray.Length()) {
1161 Call call;
1162 mCurrentCallArray.AppendElement(call);
1163 }
1164 mCurrentCallArray[aCallIndex].mState = aCallState;
1165
1166 // Return if SLC is disconnected
1167 if (!IsConnected()) {
1168 return;
1169 }
1170
1171 // Update call information besides call state
1172 mCurrentCallArray[aCallIndex].Set(aNumber, aIsOutgoing);
1173
1174 // Notify bluedroid of phone state change if this
1175 // call state change is not during transition state
1176 if (!IsTransitionState(aCallState, aIsConference)) {
1177 UpdatePhoneCIND(aCallIndex);
1178 }
1179
1180 switch (aCallState) {
1181 case nsITelephonyProvider::CALL_STATE_DIALING:
1182 // We've send Dialer a dialing request and this is the response.
1183 if (!mDialingRequestProcessed) {
1184 SendResponse(BTHF_AT_RESPONSE_OK);
1185 mDialingRequestProcessed = true;
1186 }
1187 break;
1188 case nsITelephonyProvider::CALL_STATE_DISCONNECTED:
1189 // -1 is necessary because call 0 is an invalid (padding) call object.
1190 if (mCurrentCallArray.Length() - 1 ==
1191 GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_DISCONNECTED)) {
1192 // In order to let user hear busy tone via connected Bluetooth headset,
1193 // we postpone the timing of dropping SCO.
1194 if (aError.Equals(NS_LITERAL_STRING("BusyError"))) {
1195 // FIXME: UpdatePhoneCIND later since it causes SCO close but
1196 // Dialer is still playing busy tone via HF.
1197 BT_HF_DISPATCH_MAIN(MainThreadTaskCmd::POST_TASK_CLOSE_SCO);
1198 }
1199
1200 ResetCallArray();
1201 }
1202 break;
1203 default:
1204 break;
1205 }
1206 }
1207
1208 PhoneType
1209 BluetoothHfpManager::GetPhoneType(const nsAString& aType)
1210 {
1211 // FIXME: Query phone type from RIL after RIL implements new API (bug 912019)
1212 if (aType.EqualsLiteral("gsm") || aType.EqualsLiteral("gprs") ||
1213 aType.EqualsLiteral("edge") || aType.EqualsLiteral("umts") ||
1214 aType.EqualsLiteral("hspa") || aType.EqualsLiteral("hsdpa") ||
1215 aType.EqualsLiteral("hsupa") || aType.EqualsLiteral("hspa+")) {
1216 return PhoneType::GSM;
1217 } else if (aType.EqualsLiteral("is95a") || aType.EqualsLiteral("is95b") ||
1218 aType.EqualsLiteral("1xrtt") || aType.EqualsLiteral("evdo0") ||
1219 aType.EqualsLiteral("evdoa") || aType.EqualsLiteral("evdob")) {
1220 return PhoneType::CDMA;
1221 }
1222
1223 return PhoneType::NONE;
1224 }
1225
1226 void
1227 BluetoothHfpManager::UpdateSecondNumber(const nsAString& aNumber)
1228 {
1229 MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
1230
1231 // Always regard second call as incoming call since v1.2 RIL
1232 // doesn't support outgoing second call in CDMA.
1233 mCdmaSecondCall.Set(aNumber, false);
1234
1235 // FIXME: check CDMA + bluedroid
1236 //UpdateCIND(CINDType::CALLSETUP, CallSetupState::INCOMING, true);
1237 }
1238
1239 void
1240 BluetoothHfpManager::AnswerWaitingCall()
1241 {
1242 MOZ_ASSERT(NS_IsMainThread());
1243 MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
1244
1245 // Pick up second call. First call is held now.
1246 mCdmaSecondCall.mState = nsITelephonyProvider::CALL_STATE_CONNECTED;
1247 // FIXME: check CDMA + bluedroid
1248 //UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, true);
1249
1250 //sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
1251 //SendCommand("+CIEV: ", CINDType::CALLHELD);
1252 }
1253
1254 void
1255 BluetoothHfpManager::IgnoreWaitingCall()
1256 {
1257 MOZ_ASSERT(NS_IsMainThread());
1258 MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
1259
1260 mCdmaSecondCall.Reset();
1261 // FIXME: check CDMA + bluedroid
1262 //UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, true);
1263 }
1264
1265 void
1266 BluetoothHfpManager::ToggleCalls()
1267 {
1268 MOZ_ASSERT(NS_IsMainThread());
1269 MOZ_ASSERT(mPhoneType == PhoneType::CDMA);
1270
1271 // Toggle acitve and held calls
1272 mCdmaSecondCall.mState = (mCdmaSecondCall.IsActive()) ?
1273 nsITelephonyProvider::CALL_STATE_HELD :
1274 nsITelephonyProvider::CALL_STATE_CONNECTED;
1275 }
1276
1277 bool
1278 BluetoothHfpManager::ConnectSco()
1279 {
1280 MOZ_ASSERT(NS_IsMainThread());
1281
1282 NS_ENSURE_TRUE(!sInShutdown, false);
1283 NS_ENSURE_TRUE(IsConnected() && !IsScoConnected(), false);
1284 NS_ENSURE_TRUE(sBluetoothHfpInterface, false);
1285
1286 bt_bdaddr_t deviceBdAddress;
1287 StringToBdAddressType(mDeviceAddress, &deviceBdAddress);
1288 NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
1289 sBluetoothHfpInterface->connect_audio(&deviceBdAddress), false);
1290
1291 return true;
1292 }
1293
1294 bool
1295 BluetoothHfpManager::DisconnectSco()
1296 {
1297 NS_ENSURE_TRUE(IsScoConnected(), false);
1298 NS_ENSURE_TRUE(sBluetoothHfpInterface, false);
1299
1300 bt_bdaddr_t deviceBdAddress;
1301 StringToBdAddressType(mDeviceAddress, &deviceBdAddress);
1302 NS_ENSURE_TRUE(BT_STATUS_SUCCESS ==
1303 sBluetoothHfpInterface->disconnect_audio(&deviceBdAddress), false);
1304
1305 return true;
1306 }
1307
1308 bool
1309 BluetoothHfpManager::IsScoConnected()
1310 {
1311 return (mAudioState == BTHF_AUDIO_STATE_CONNECTED);
1312 }
1313
1314 bool
1315 BluetoothHfpManager::IsConnected()
1316 {
1317 return (mConnectionState == BTHF_CONNECTION_STATE_SLC_CONNECTED);
1318 }
1319
1320 void
1321 BluetoothHfpManager::Connect(const nsAString& aDeviceAddress,
1322 BluetoothProfileController* aController)
1323 {
1324 MOZ_ASSERT(NS_IsMainThread());
1325 MOZ_ASSERT(aController && !mController);
1326
1327 if (sInShutdown) {
1328 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
1329 return;
1330 }
1331
1332 if (!sBluetoothHfpInterface) {
1333 BT_LOGR("sBluetoothHfpInterface is null");
1334 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
1335 return;
1336 }
1337
1338 bt_bdaddr_t deviceBdAddress;
1339 StringToBdAddressType(aDeviceAddress, &deviceBdAddress);
1340
1341 bt_status_t result = sBluetoothHfpInterface->connect(&deviceBdAddress);
1342 if (BT_STATUS_SUCCESS != result) {
1343 BT_LOGR("Failed to connect: %x", result);
1344 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
1345 return;
1346 }
1347
1348 mDeviceAddress = aDeviceAddress;
1349 mController = aController;
1350 }
1351
1352 void
1353 BluetoothHfpManager::Disconnect(BluetoothProfileController* aController)
1354 {
1355 MOZ_ASSERT(NS_IsMainThread());
1356 MOZ_ASSERT(!mController);
1357
1358 if (!sBluetoothHfpInterface) {
1359 BT_LOGR("sBluetoothHfpInterface is null");
1360 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
1361 return;
1362 }
1363
1364 bt_bdaddr_t deviceBdAddress;
1365 StringToBdAddressType(mDeviceAddress, &deviceBdAddress);
1366
1367 bt_status_t result = sBluetoothHfpInterface->disconnect(&deviceBdAddress);
1368 if (BT_STATUS_SUCCESS != result) {
1369 BT_LOGR("Failed to disconnect: %x", result);
1370 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
1371 return;
1372 }
1373
1374 mController = aController;
1375 }
1376
1377 void
1378 BluetoothHfpManager::OnConnect(const nsAString& aErrorStr)
1379 {
1380 MOZ_ASSERT(NS_IsMainThread());
1381
1382 /**
1383 * On the one hand, notify the controller that we've done for outbound
1384 * connections. On the other hand, we do nothing for inbound connections.
1385 */
1386 NS_ENSURE_TRUE_VOID(mController);
1387
1388 mController->NotifyCompletion(aErrorStr);
1389 mController = nullptr;
1390 }
1391
1392 void
1393 BluetoothHfpManager::OnDisconnect(const nsAString& aErrorStr)
1394 {
1395 MOZ_ASSERT(NS_IsMainThread());
1396
1397 /**
1398 * On the one hand, notify the controller that we've done for outbound
1399 * connections. On the other hand, we do nothing for inbound connections.
1400 */
1401 NS_ENSURE_TRUE_VOID(mController);
1402
1403 mController->NotifyCompletion(aErrorStr);
1404 mController = nullptr;
1405 }
1406
1407 void
1408 BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
1409 {
1410 // Bluedroid handles this part
1411 MOZ_ASSERT(false);
1412 }
1413
1414 void
1415 BluetoothHfpManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
1416 const nsAString& aServiceUuid,
1417 int aChannel)
1418 {
1419 // Bluedroid handles this part
1420 MOZ_ASSERT(false);
1421 }
1422
1423 void
1424 BluetoothHfpManager::GetAddress(nsAString& aDeviceAddress)
1425 {
1426 aDeviceAddress = mDeviceAddress;
1427 }
1428
1429 NS_IMPL_ISUPPORTS(BluetoothHfpManager, nsIObserver)

mercurial