Bug 1061126: Make Bluetooth AVRCP interface generally available, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Tue, 02 Sep 2014 12:46:07 +0200
changeset 226221 bae6b0b0a4b5207ef67ddf38de09c9bbcc9fe90a
parent 226220 ad902f1fd574941061127da71d3ee2fafc0df79f
child 226222 92f2ed449adb243d20580e6d8105c3920e89023b
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1061126
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 1061126: Make Bluetooth AVRCP interface generally available, r=shuang The methods of |BluetoothAVRCPInterface| are now always available. On Android versions before 18, which don't support AVRCP, they always fail with STATUS_UNSUPPORTED.
dom/bluetooth/bluedroid/BluetoothInterface.cpp
dom/bluetooth/bluedroid/BluetoothInterface.h
--- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.cpp
@@ -1,19 +1,19 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "BluetoothInterface.h"
 #include <errno.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include "base/message_loop.h"
-#include "BluetoothInterface.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 #if MOZ_IS_GCC && MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
 /* use designated array initializers if supported */
 #define CONVERT(in_, out_) \
   [in_] = out_
@@ -2981,16 +2981,17 @@ struct interface_traits<BluetoothAvrcpIn
 {
   typedef const btrc_interface_t const_interface_type;
 
   static const char* profile_id()
   {
     return BT_PROFILE_AV_RC_ID;
   }
 };
+#endif
 
 typedef
   BluetoothInterfaceRunnable0<BluetoothAvrcpResultHandler, void>
   BluetoothAvrcpResultRunnable;
 
 typedef
   BluetoothInterfaceRunnable1<BluetoothAvrcpResultHandler, void,
                               BluetoothStatus, BluetoothStatus>
@@ -3013,25 +3014,23 @@ DispatchBluetoothAvrcpResult(
       &BluetoothAvrcpResultHandler::OnError, aStatus);
   }
   nsresult rv = NS_DispatchToMainThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
   }
   return rv;
 }
-#endif
 
 // Notification handling
 //
 
 BluetoothAvrcpNotificationHandler::~BluetoothAvrcpNotificationHandler()
 { }
 
-#if ANDROID_VERSION >= 18
 static BluetoothAvrcpNotificationHandler* sAvrcpNotificationHandler;
 
 struct BluetoothAvrcpCallback
 {
   class AvrcpNotificationHandlerWrapper
   {
   public:
     typedef BluetoothAvrcpNotificationHandler ObjectType;
@@ -3087,36 +3086,35 @@ struct BluetoothAvrcpCallback
     uint8_t, const BluetoothAvrcpMediaAttribute*>
     GetElementAttrNotification;
 
   typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
                                          void,
                                          BluetoothAvrcpEvent, uint32_t>
     RegisterNotificationNotification;
 
-#if ANDROID_VERSION >= 19
   typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
                                          void,
                                          nsString, unsigned long,
                                          const nsAString&>
     RemoteFeatureNotification;
 
   typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
                                          void,
                                          uint8_t, uint8_t>
     VolumeChangeNotification;
 
   typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
                                          void,
                                          int, int>
     PassthroughCmdNotification;
-#endif // ANDROID_VERSION >= 19
 
   // Bluedroid AVRCP callbacks
 
+#if ANDROID_VERSION >= 18
   static void
   GetPlayStatus()
   {
     GetPlayStatusNotification::Dispatch(
       &BluetoothAvrcpNotificationHandler::GetPlayStatusNotification);
   }
 
   static void
@@ -3176,16 +3174,17 @@ struct BluetoothAvrcpCallback
 
   static void
   RegisterNotification(btrc_event_id_t aEvent, uint32_t aParam)
   {
     RegisterNotificationNotification::Dispatch(
       &BluetoothAvrcpNotificationHandler::RegisterNotificationNotification,
       aEvent, aParam);
   }
+#endif // ANDROID_VERSION >= 18
 
 #if ANDROID_VERSION >= 19
   static void
   RemoteFeature(bt_bdaddr_t* aBdAddr, btrc_remote_features_t aFeatures)
   {
     RemoteFeatureNotification::Dispatch(
       &BluetoothAvrcpNotificationHandler::RemoteFeatureNotification,
       aBdAddr, aFeatures);
@@ -3208,30 +3207,38 @@ struct BluetoothAvrcpCallback
   }
 #endif // ANDROID_VERSION >= 19
 };
 
 // Interface
 //
 
 BluetoothAvrcpInterface::BluetoothAvrcpInterface(
-  const btrc_interface_t* aInterface)
+#if ANDROID_VERSION >= 18
+  const btrc_interface_t* aInterface
+#endif
+  )
+#if ANDROID_VERSION >= 18
 : mInterface(aInterface)
+#endif
 {
+#if ANDROID_VERSION >= 18
   MOZ_ASSERT(mInterface);
+#endif
 }
 
 BluetoothAvrcpInterface::~BluetoothAvrcpInterface()
 { }
 
 void
 BluetoothAvrcpInterface::Init(
   BluetoothAvrcpNotificationHandler* aNotificationHandler,
   BluetoothAvrcpResultHandler* aRes)
 {
+#if ANDROID_VERSION >= 18
   static btrc_callbacks_t sCallbacks = {
     sizeof(sCallbacks),
 #if ANDROID_VERSION >= 19
     BluetoothAvrcpCallback::RemoteFeature,
 #endif
     BluetoothAvrcpCallback::GetPlayStatus,
     BluetoothAvrcpCallback::ListPlayerAppAttr,
     BluetoothAvrcpCallback::ListPlayerAppValues,
@@ -3242,216 +3249,264 @@ BluetoothAvrcpInterface::Init(
     BluetoothAvrcpCallback::GetElementAttr,
     BluetoothAvrcpCallback::RegisterNotification
 #if ANDROID_VERSION >= 19
     ,
     BluetoothAvrcpCallback::VolumeChange,
     BluetoothAvrcpCallback::PassthroughCmd
 #endif
   };
+#endif // ANDROID_VERSION >= 18
 
   sAvrcpNotificationHandler = aNotificationHandler;
 
+#if ANDROID_VERSION >= 18
   bt_status_t status = mInterface->init(&sCallbacks);
+#else
+  bt_status_t status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Init,
                                  ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::Cleanup(BluetoothAvrcpResultHandler* aRes)
 {
+#if ANDROID_VERSION >= 18
   mInterface->cleanup();
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Cleanup,
                                  STATUS_SUCCESS);
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
                                           uint32_t aSongLen, uint32_t aSongPos,
                                           BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   btrc_play_status_t playStatus = BTRC_PLAYSTATE_STOPPED;
 
   if (!(NS_FAILED(Convert(aPlayStatus, playStatus)))) {
     status = mInterface->get_play_status_rsp(playStatus, aSongLen, aSongPos);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayStatusRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::ListPlayerAppAttrRsp(
   int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs,
   BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   ConvertArray<BluetoothAvrcpPlayerAttribute> pAttrsArray(aPAttrs, aNumAttr);
   nsAutoArrayPtr<btrc_player_attr_t> pAttrs;
 
   if (NS_SUCCEEDED(Convert(pAttrsArray, pAttrs))) {
     status = mInterface->list_player_app_attr_rsp(aNumAttr, pAttrs);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::ListPlayerAppAttrRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::ListPlayerAppValueRsp(
   int aNumVal, uint8_t* aPVals, BluetoothAvrcpResultHandler* aRes)
 {
+#if ANDROID_VERSION >= 18
   bt_status_t status = mInterface->list_player_app_value_rsp(aNumVal, aPVals);
+#else
+  bt_status_t status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::ListPlayerAppValueRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayerAppValueRsp(
   uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues,
   BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   btrc_player_settings_t pVals;
 
   /* FIXME: you need to implement the missing conversion functions */
   NS_NOTREACHED("Conversion function missing");
 
   if (false /* TODO: we don't support any player app values currently */) {
     status = mInterface->get_player_app_value_rsp(&pVals);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayerAppAttrTextRsp(
   int aNumAttr, const uint8_t* aIds, const char** aTexts,
   BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   btrc_player_setting_text_t* aPAttrs;
 
   /* FIXME: you need to implement the missing conversion functions */
   NS_NOTREACHED("Conversion function missing");
 
   if (false /* TODO: we don't support any attributes currently */) {
     status = mInterface->get_player_app_attr_text_rsp(aNumAttr, aPAttrs);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayerAppAttrTextRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayerAppValueTextRsp(
   int aNumVal, const uint8_t* aIds, const char** aTexts,
   BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   btrc_player_setting_text_t* pVals;
 
   /* FIXME: you need to implement the missing conversion functions */
   NS_NOTREACHED("Conversion function missing");
 
   if (false /* TODO: we don't support any values currently */) {
     status = mInterface->get_player_app_value_text_rsp(aNumVal, pVals);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueTextRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::GetElementAttrRsp(
   uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttrs,
   BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   ConvertArray<BluetoothAvrcpElementAttribute> pAttrsArray(aAttrs, aNumAttr);
   nsAutoArrayPtr<btrc_element_attr_val_t> pAttrs;
 
   if (NS_SUCCEEDED(Convert(pAttrsArray, pAttrs))) {
     status = mInterface->get_element_attr_rsp(aNumAttr, pAttrs);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetElementAttrRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::SetPlayerAppValueRsp(
   BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes)
 {
   bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   btrc_status_t rspStatus = BTRC_STS_BAD_CMD; // silences compiler warning
 
   if (NS_SUCCEEDED(Convert(aRspStatus, rspStatus))) {
     status = mInterface->set_player_app_value_rsp(rspStatus);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::SetPlayerAppValueRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothAvrcpInterface::RegisterNotificationRsp(
   BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType,
   const BluetoothAvrcpNotificationParam& aParam,
   BluetoothAvrcpResultHandler* aRes)
 {
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   nsresult rv;
-  bt_status_t status;
   btrc_event_id_t event = { };
   btrc_notification_type_t type = BTRC_NOTIFICATION_TYPE_INTERIM;
   btrc_register_notification_t param;
 
   switch (aEvent) {
     case AVRCP_EVENT_PLAY_STATUS_CHANGED:
       rv = Convert(aParam.mPlayStatus, param.play_status);
       break;
@@ -3484,16 +3539,19 @@ BluetoothAvrcpInterface::RegisterNotific
 
   if (NS_SUCCEEDED(rv) &&
       NS_SUCCEEDED(Convert(aEvent, event)) &&
       NS_SUCCEEDED(Convert(aType, type))) {
     status = mInterface->register_notification_rsp(event, type, &param);
   } else {
     status = BT_STATUS_PARM_INVALID;
   }
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::RegisterNotificationRsp,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
@@ -3508,17 +3566,16 @@ BluetoothAvrcpInterface::SetVolume(uint8
 #endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::SetVolume,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
-#endif
 
 //
 // Bluetooth Core Interface
 //
 
 typedef
   BluetoothInterfaceRunnable0<BluetoothResultHandler, void>
   BluetoothResultRunnable;
@@ -4287,40 +4344,63 @@ BluetoothInterface::LeTestMode(uint16_t 
                             ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 /* Profile Interfaces */
 
 template <class T>
 T*
-BluetoothInterface::GetProfileInterface()
+BluetoothInterface::CreateProfileInterface()
 {
-  static T* sBluetoothProfileInterface;
-
-  if (sBluetoothProfileInterface) {
-    return sBluetoothProfileInterface;
-  }
-
   typename interface_traits<T>::const_interface_type* interface =
     reinterpret_cast<typename interface_traits<T>::const_interface_type*>(
       mInterface->get_profile_interface(interface_traits<T>::profile_id()));
 
   if (!interface) {
     BT_WARNING("Bluetooth profile '%s' is not supported",
                interface_traits<T>::profile_id());
     return nullptr;
   }
 
   if (interface->size != sizeof(*interface)) {
     BT_WARNING("interface of incorrect size");
     return nullptr;
   }
 
-  sBluetoothProfileInterface = new T(interface);
+  return new T(interface);
+}
+
+#if ANDROID_VERSION < 18
+/*
+ * Bluedroid versions that don't support AVRCP will call this function
+ * to create an AVRCP interface. All interface methods will fail with
+ * the error constant STATUS_UNSUPPORTED.
+ */
+template <>
+BluetoothAvrcpInterface*
+BluetoothInterface::CreateProfileInterface<BluetoothAvrcpInterface>()
+{
+  BT_WARNING("Bluetooth profile 'avrcp' is not supported");
+
+  return new BluetoothAvrcpInterface();
+}
+#endif
+
+template <class T>
+T*
+BluetoothInterface::GetProfileInterface()
+{
+  static T* sBluetoothProfileInterface;
+
+  if (sBluetoothProfileInterface) {
+    return sBluetoothProfileInterface;
+  }
+
+  sBluetoothProfileInterface = CreateProfileInterface<T>();
 
   return sBluetoothProfileInterface;
 }
 
 BluetoothSocketInterface*
 BluetoothInterface::GetBluetoothSocketInterface()
 {
   return GetProfileInterface<BluetoothSocketInterface>();
@@ -4336,16 +4416,12 @@ BluetoothA2dpInterface*
 BluetoothInterface::GetBluetoothA2dpInterface()
 {
   return GetProfileInterface<BluetoothA2dpInterface>();
 }
 
 BluetoothAvrcpInterface*
 BluetoothInterface::GetBluetoothAvrcpInterface()
 {
-#if ANDROID_VERSION >= 18
   return GetProfileInterface<BluetoothAvrcpInterface>();
-#else
-  return nullptr;
-#endif
 }
 
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.h
@@ -422,17 +422,16 @@ public:
 
   virtual void RegisterNotificationRsp() { }
 
   virtual void SetVolume() { }
 };
 
 class BluetoothAvrcpInterface
 {
-#if ANDROID_VERSION >= 18
 public:
   friend class BluetoothInterface;
 
   void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
             BluetoothAvrcpResultHandler* aRes);
   void Cleanup(BluetoothAvrcpResultHandler* aRes);
 
   void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
@@ -468,20 +467,25 @@ public:
   void RegisterNotificationRsp(BluetoothAvrcpEvent aEvent,
                                BluetoothAvrcpNotification aType,
                                const BluetoothAvrcpNotificationParam& aParam,
                                BluetoothAvrcpResultHandler* aRes);
 
   void SetVolume(uint8_t aVolume, BluetoothAvrcpResultHandler* aRes);
 
 protected:
-  BluetoothAvrcpInterface(const btrc_interface_t* aInterface);
+  BluetoothAvrcpInterface(
+#if ANDROID_VERSION >= 18
+    const btrc_interface_t* aInterface
+#endif
+    );
   ~BluetoothAvrcpInterface();
 
 private:
+#if ANDROID_VERSION >= 18
   const btrc_interface_t* mInterface;
 #endif
 };
 
 //
 // Bluetooth Core Interface
 //
 
@@ -653,16 +657,19 @@ public:
   BluetoothAvrcpInterface* GetBluetoothAvrcpInterface();
 
 protected:
   BluetoothInterface(const bt_interface_t* aInterface);
   ~BluetoothInterface();
 
 private:
   template <class T>
+  T* CreateProfileInterface();
+
+  template <class T>
   T* GetProfileInterface();
 
   const bt_interface_t* mInterface;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif