From abbdf7f4d9f8b5e399c567ebee5f0ca81d88f4a1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 28 Jul 2014 09:52:51 +0200 Subject: [PATCH] Bug 1042691: Asynchronous init and cleanup of A2DP/AVRCP (under bluetooth2/), r=btian --- .../bluedroid/BluetoothA2dpManager.cpp | 216 +++++++++++++++--- .../bluedroid/BluetoothInterface.cpp | 38 ++- dom/bluetooth2/bluedroid/BluetoothInterface.h | 10 +- 3 files changed, 217 insertions(+), 47 deletions(-) diff --git a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp index 1ccc890cc0d1..b7c524b8955c 100644 --- a/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothA2dpManager.cpp @@ -492,6 +492,85 @@ static btrc_callbacks_t sBtAvrcpCallbacks = { }; #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 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(); + if (!btInf) { + if (mRes) { + mRes->OnError(NS_ERROR_FAILURE); + } + return; + } + + sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface(); + if (!sBtAvrcpInterface) { + if (mRes) { + mRes->OnError(NS_ERROR_FAILURE); + } + return; + } + + sBtAvrcpInterface->Init(&sBtAvrcpCallbacks, + new InitAvrcpResultHandler(mRes)); +#else + /* ...or signal success otherwise. */ + if (mRes) { + mRes->Init(); + } +#endif + } + +private: + nsRefPtr mRes; +}; + /* * This function will be only called when Bluetooth is turning on. * It is important to register a2dp callbacks before enable() gets called. @@ -520,30 +599,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes) return; } - 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(); - if (!sBtAvrcpInterface) { - BT_LOGR("Error: Bluetooth AVRCP interface not available"); - if (aRes) { - aRes->OnError(NS_ERROR_FAILURE); - } - return; - } - - 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() @@ -617,6 +673,99 @@ BluetoothA2dpManager::Get() 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 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 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 mRes; +}; + // static void BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes) @@ -624,17 +773,14 @@ 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 r = new CleanupA2dpResultHandlerRunnable(aRes); + if (NS_FAILED(NS_DispatchToMainThread(r))) { + BT_LOGR("Failed to dispatch cleanup-result-handler runnable"); + } } } diff --git a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp b/dom/bluetooth2/bluedroid/BluetoothInterface.cpp index d7126111217a..58d6c4bf57d6 100644 --- a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothInterface.cpp @@ -888,16 +888,27 @@ BluetoothA2dpInterface::BluetoothA2dpInterface( 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 @@ -969,16 +980,27 @@ BluetoothAvrcpInterface::BluetoothAvrcpInterface( 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 diff --git a/dom/bluetooth2/bluedroid/BluetoothInterface.h b/dom/bluetooth2/bluedroid/BluetoothInterface.h index 0ea223826fbc..3119ff07bc2c 100644 --- a/dom/bluetooth2/bluedroid/BluetoothInterface.h +++ b/dom/bluetooth2/bluedroid/BluetoothInterface.h @@ -204,8 +204,9 @@ 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); @@ -261,8 +262,9 @@ class BluetoothAvrcpInterface 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);