Bug 1029390: Asynchronous init and cleanup of A2DP/AVRCP, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Wed, 23 Jul 2014 07:56:22 +0200
changeset 195574 332edac38e3cab15c3858137188090f09390eb28
parent 195573 55aeb3ffaf0dbca39c6f1778afaf134b736a6a02
child 195575 2ca67af54fa1ac5e59dbb524f99662d17cf159a1
push id27187
push usercbook@mozilla.com
push dateWed, 23 Jul 2014 10:59:56 +0000
treeherdermozilla-central@d0f6259e8446 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1029390
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1029390: Asynchronous init and cleanup of A2DP/AVRCP, r=shuang
dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
dom/bluetooth/bluedroid/BluetoothInterface.cpp
dom/bluetooth/bluedroid/BluetoothInterface.h
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -487,50 +487,102 @@ static btrc_callbacks_t sBtAvrcpCallback
   AvrcpRegisterNotificationCallback,
 #if ANDROID_VERSION > 18
   AvrcpRemoteVolumeChangedCallback,
   AvrcpPassThroughCallback
 #endif
 };
 #endif
 
+#if ANDROID_VERSION > 17
+class InitAvrcpResultHandler MOZ_FINAL : public BluetoothAvrcpResultHandler
+{
+public:
+  InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  { }
+
+  void OnError(bt_status_t aStatus) MOZ_OVERRIDE
+  {
+    BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
+               (int)aStatus);
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void Init() MOZ_OVERRIDE
+  {
+    if (mRes) {
+      mRes->Init();
+    }
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+#endif
+
+class InitA2dpResultHandler MOZ_FINAL : public BluetoothA2dpResultHandler
+{
+public:
+  InitA2dpResultHandler(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  { }
+
+  void OnError(bt_status_t aStatus) MOZ_OVERRIDE
+  {
+    BT_WARNING("BluetoothA2dpInterface::Init failed: %d",
+               (int)aStatus);
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void Init() MOZ_OVERRIDE
+  {
+#if ANDROID_VERSION > 17
+    /* Also init AVRCP if it's available, ... */
+    BluetoothInterface* btInf = BluetoothInterface::GetInstance();
+    NS_ENSURE_TRUE_VOID(btInf);
+
+    sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
+    NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
+
+    sBtAvrcpInterface->Init(&sBtAvrcpCallbacks,
+                            new InitAvrcpResultHandler(mRes));
+#else
+    /* ...or signal success otherwise. */
+    if (mRes) {
+      mRes->Init();
+    }
+#endif
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+
 /*
  * This function will be only called when Bluetooth is turning on.
  * It is important to register a2dp callbacks before enable() gets called.
  * It is required to register a2dp callbacks before a2dp media task
  * starts up.
  */
 // static
 void
 BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
   NS_ENSURE_TRUE_VOID(btInf);
 
   sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
   NS_ENSURE_TRUE_VOID(sBtA2dpInterface);
 
-  int ret = sBtA2dpInterface->Init(&sBtA2dpCallbacks);
-  if (ret != BT_STATUS_SUCCESS) {
-    BT_LOGR("Warning: failed to init a2dp module");
-  }
-
-#if ANDROID_VERSION > 17
-  sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
-  NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
-
-  ret = sBtAvrcpInterface->Init(&sBtAvrcpCallbacks);
-  if (ret != BT_STATUS_SUCCESS) {
-    BT_LOGR("Warning: failed to init avrcp module");
-  }
-#endif
-
-  if (aRes) {
-    aRes->Init();
-  }
+  sBtA2dpInterface->Init(&sBtA2dpCallbacks, new InitA2dpResultHandler(aRes));
 }
 
 BluetoothA2dpManager::~BluetoothA2dpManager()
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(obs);
   if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
     BT_WARNING("Failed to remove shutdown observer!");
@@ -594,34 +646,124 @@ BluetoothA2dpManager::Get()
   NS_ENSURE_FALSE(sInShutdown, nullptr);
 
   // Create a new instance, register, and return
   BluetoothA2dpManager* manager = new BluetoothA2dpManager();
   sBluetoothA2dpManager = manager;
   return sBluetoothA2dpManager;
 }
 
+#if ANDROID_VERSION > 17
+class CleanupAvrcpResultHandler MOZ_FINAL : public BluetoothAvrcpResultHandler
+{
+public:
+  CleanupAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  { }
+
+  void OnError(bt_status_t aStatus) MOZ_OVERRIDE
+  {
+    BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
+               (int)aStatus);
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void Cleanup() MOZ_OVERRIDE
+  {
+    sBtAvrcpInterface = nullptr;
+    if (mRes) {
+      mRes->Deinit();
+    }
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+#endif
+
+class CleanupA2dpResultHandler MOZ_FINAL : public BluetoothA2dpResultHandler
+{
+public:
+  CleanupA2dpResultHandler(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  { }
+
+  void OnError(bt_status_t aStatus) MOZ_OVERRIDE
+  {
+    BT_WARNING("BluetoothA2dpInterface::Cleanup failed: %d",
+               (int)aStatus);
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void Cleanup() MOZ_OVERRIDE
+  {
+    sBtA2dpInterface = nullptr;
+#if ANDROID_VERSION > 17
+    /* Cleanup AVRCP if it's available and initialized, ...*/
+    if (sBtAvrcpInterface) {
+      sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
+    } else
+#endif
+    if (mRes) {
+      /* ...or simply signal success from here. */
+      mRes->Deinit();
+    }
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+
+class CleanupA2dpResultHandlerRunnable MOZ_FINAL : public nsRunnable
+{
+public:
+  CleanupA2dpResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
+  : mRes(aRes)
+  { }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE
+  {
+    sBtA2dpInterface = nullptr;
+#if ANDROID_VERSION > 17
+    /* Cleanup AVRCP if it's available and initialized, ...*/
+    if (sBtAvrcpInterface) {
+      sBtAvrcpInterface->Cleanup(new CleanupAvrcpResultHandler(mRes));
+    } else
+#endif
+    if (mRes) {
+      /* ...or simply signal success from here. */
+      mRes->Deinit();
+    }
+
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<BluetoothProfileResultHandler> mRes;
+};
+
 // static
 void
 BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (sBtA2dpInterface) {
-    sBtA2dpInterface->Cleanup();
-    sBtA2dpInterface = nullptr;
-  }
-#if ANDROID_VERSION > 17
-  if (sBtAvrcpInterface) {
-    sBtAvrcpInterface->Cleanup();
-    sBtAvrcpInterface = nullptr;
-  }
-#endif
-  if (aRes) {
-    aRes->Deinit();
+    sBtA2dpInterface->Cleanup(new CleanupA2dpResultHandler(aRes));
+  } else if (aRes) {
+    // We dispatch a runnable here to make the profile resource handler
+    // behave as if A2DP was initialized.
+    nsRefPtr<nsRunnable> r = new CleanupA2dpResultHandlerRunnable(aRes);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
+    }
   }
 }
 
 void
 BluetoothA2dpManager::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   sInShutdown = true;
--- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.cpp
@@ -883,26 +883,37 @@ BluetoothA2dpInterface::BluetoothA2dpInt
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothA2dpInterface::~BluetoothA2dpInterface()
 { }
 
-bt_status_t
-BluetoothA2dpInterface::Init(btav_callbacks_t* aCallbacks)
+void
+BluetoothA2dpInterface::Init(btav_callbacks_t* aCallbacks,
+                             BluetoothA2dpResultHandler* aRes)
 {
-  return mInterface->init(aCallbacks);
+  bt_status_t status = mInterface->init(aCallbacks);
+
+  if (aRes) {
+    DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Init,
+                                status);
+  }
 }
 
 void
-BluetoothA2dpInterface::Cleanup()
+BluetoothA2dpInterface::Cleanup(BluetoothA2dpResultHandler* aRes)
 {
   mInterface->cleanup();
+
+  if (aRes) {
+    DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Cleanup,
+                                BT_STATUS_SUCCESS);
+  }
 }
 
 bt_status_t
 BluetoothA2dpInterface::Connect(bt_bdaddr_t *aBdAddr)
 {
   return mInterface->connect(aBdAddr);
 }
 
@@ -964,26 +975,37 @@ BluetoothAvrcpInterface::BluetoothAvrcpI
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothAvrcpInterface::~BluetoothAvrcpInterface()
 { }
 
-bt_status_t
-BluetoothAvrcpInterface::Init(btrc_callbacks_t* aCallbacks)
+void
+BluetoothAvrcpInterface::Init(btrc_callbacks_t* aCallbacks,
+                              BluetoothAvrcpResultHandler* aRes)
 {
-  return mInterface->init(aCallbacks);
+  bt_status_t status = mInterface->init(aCallbacks);
+
+  if (aRes) {
+    DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Init,
+                                 status);
+  }
 }
 
 void
-BluetoothAvrcpInterface::Cleanup()
+BluetoothAvrcpInterface::Cleanup(BluetoothAvrcpResultHandler* aRes)
 {
   mInterface->cleanup();
+
+  if (aRes) {
+    DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Cleanup,
+                                 BT_STATUS_SUCCESS);
+  }
 }
 
 bt_status_t
 BluetoothAvrcpInterface::GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
                                           uint32_t aSongLen, uint32_t aSongPos)
 {
   return mInterface->get_play_status_rsp(aPlayStatus, aSongLen, aSongPos);
 }
--- a/dom/bluetooth/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.h
@@ -199,18 +199,19 @@ public:
   virtual void Disconnect() { }
 };
 
 class BluetoothA2dpInterface
 {
 public:
   friend class BluetoothInterface;
 
-  bt_status_t Init(btav_callbacks_t *aCallbacks);
-  void        Cleanup();
+  void Init(btav_callbacks_t *aCallbacks,
+            BluetoothA2dpResultHandler* aRes);
+  void Cleanup(BluetoothA2dpResultHandler* aRes);
 
   bt_status_t Connect(bt_bdaddr_t *aBdAddr);
   bt_status_t Disconnect(bt_bdaddr_t *aBdAddr);
 
 protected:
   BluetoothA2dpInterface(const btav_interface_t* aInterface);
   ~BluetoothA2dpInterface();
 
@@ -256,18 +257,19 @@ public:
 };
 
 class BluetoothAvrcpInterface
 {
 #if ANDROID_VERSION >= 18
 public:
   friend class BluetoothInterface;
 
-  bt_status_t Init(btrc_callbacks_t* aCallbacks);
-  void        Cleanup();
+  void Init(btrc_callbacks_t* aCallbacks,
+            BluetoothAvrcpResultHandler* aRes);
+  void Cleanup(BluetoothAvrcpResultHandler* aRes);
 
   bt_status_t GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
                                uint32_t aSongLen, uint32_t aSongPos);
 
   bt_status_t ListPlayerAppAttrRsp(int aNumAttr, btrc_player_attr_t* aPAttrs);
   bt_status_t ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals);
 
   bt_status_t GetPlayerAppValueRsp(btrc_player_settings_t* aPVals);