Bug 1064264: Make Bluetooth AVRCP interface generally available (under bluetooth2/), r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Tue, 09 Sep 2014 16:30:06 +0200
changeset 204287 d62523a35f2413477ff4bcb30e44858191247b59
parent 204286 b0da20b437f2f5747bf5b99f13f1c33e3dcd6c81
child 204288 a5b42086875478123e6d8d2436515c54878715c6
push id27454
push userryanvm@gmail.com
push dateTue, 09 Sep 2014 22:58:39 +0000
treeherdermozilla-central@6b3948d3413a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1064264
milestone35.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 1064264: Make Bluetooth AVRCP interface generally available (under bluetooth2/), r=btian 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/bluetooth2/bluedroid/BluetoothInterface.cpp
dom/bluetooth2/bluedroid/BluetoothInterface.h
--- a/dom/bluetooth2/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth2/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 <sys/socket.h>
 #include <unistd.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,270 @@ 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)
 {
+  bt_status_t status;
+
+#if ANDROID_VERSION >= 18
   mInterface->cleanup();
 
+  status = BT_STATUS_SUCCESS;
+#else
+  status = BT_STATUS_UNSUPPORTED;
+#endif
+
   if (aRes) {
     DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Cleanup,
-                                 STATUS_SUCCESS);
+                                 ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 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 +3545,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 +3572,16 @@ BluetoothAvrcpInterface::SetVolume(uint8
 #endif
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::SetVolume,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
-#endif // ANDROID_VERSION >= 18
 
 //
 // Bluetooth Core Interface
 //
 
 typedef
   BluetoothInterfaceRunnable0<BluetoothResultHandler, void>
   BluetoothResultRunnable;
@@ -4289,40 +4352,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>();
@@ -4338,16 +4424,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/bluetooth2/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth2/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