Bug 1057337: Implement Bluetooth A2DP notifications, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Mon, 01 Sep 2014 10:11:53 +0200
changeset 224434 b0682f061278ce75c5ff58e3b5460654e922f01d
parent 224433 13e870775e1b0868855b6568af6db56af718862c
child 224435 9170ec6066c261fe960b10eae5bd910b9f3a11fd
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1057337
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 1057337: Implement Bluetooth A2DP notifications, r=shuang This patch adds Bluetooth A2DP and AVRCP notifications to Gecko's A2DP manager. The code has been taken from taken from the callback implementations, and adapted to run on the main thread. No further cleanups have been applied.
dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
dom/bluetooth/bluedroid/BluetoothA2dpManager.h
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -2,17 +2,16 @@
 /* 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 "base/basictypes.h"
 
 #include "BluetoothA2dpManager.h"
-#include "BluetoothInterface.h"
 #include "BluetoothCommon.h"
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
@@ -156,16 +155,29 @@ public:
 
     mAttrs = new BluetoothAvrcpElementAttribute[mNumAttr];
 
     for (uint8_t i = 0; i < mNumAttr; ++i) {
       mAttrs[i].mId = aPlayerAttrs[i];
     }
   }
 
+  UpdateElementAttrsTask(uint8_t aNumAttr,
+                         const BluetoothAvrcpMediaAttribute* aAttrs)
+  : mNumAttr(aNumAttr)
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    mAttrs = new BluetoothAvrcpElementAttribute[mNumAttr];
+
+    for (uint8_t i = 0; i < mNumAttr; ++i) {
+      mAttrs[i].mId = aAttrs[i];
+    }
+  }
+
   nsresult Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     for (uint8_t i = 0; i < mNumAttr; ++i) {
       ConvertAttributeString(mAttrs[i].mId, mAttrs[i].mValue);
     }
 
@@ -245,16 +257,32 @@ AvStatusToSinkString(btav_connection_sta
   } else if (aStatus == BTAV_CONNECTION_STATE_DISCONNECTING) {
     aState = NS_LITERAL_STRING("disconnecting");
   } else {
     BT_WARNING("Unknown sink state");
   }
 }
 
 static void
+AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
+{
+  static const nsLiteralString sString[] = {
+    [A2DP_CONNECTION_STATE_DISCONNECTED] = NS_LITERAL_STRING("disconnected"),
+    [A2DP_CONNECTION_STATE_CONNECTING] = NS_LITERAL_STRING("connecting"),
+    [A2DP_CONNECTION_STATE_CONNECTED] = NS_LITERAL_STRING("connected"),
+    [A2DP_CONNECTION_STATE_DISCONNECTING] = NS_LITERAL_STRING("disconnecting")
+  };
+  if (aState >= MOZ_ARRAY_LENGTH(sString)) {
+    BT_WARNING("Unknown sink state %d", static_cast<int>(aState));
+    return;
+  }
+  aString = sString[aState];
+}
+
+static void
 A2dpConnectionStateCallback(btav_connection_state_t aState,
                             bt_bdaddr_t* aBdAddress)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   nsString remoteDeviceBdAddress;
   BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
 
@@ -1300,10 +1328,208 @@ BluetoothA2dpManager::GetTitle(nsAString
 }
 
 void
 BluetoothA2dpManager::GetArtist(nsAString& aArtist)
 {
   aArtist.Assign(mArtist);
 }
 
+/*
+ * A2DP Notifications
+ */
+
+void
+BluetoothA2dpManager::ConnectionStateNotification(BluetoothA2dpConnectionState aState,
+                                                  const nsAString& aBdAddr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsString a2dpState;
+  AvStatusToSinkString(aState, a2dpState);
+
+  InfallibleTArray<BluetoothNamedValue> props;
+  BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
+
+  BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
+                         nsString(aBdAddr), props);
+  NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
+}
+
+void
+BluetoothA2dpManager::AudioStateNotification(BluetoothA2dpAudioState aState,
+                                             const nsAString& aBdAddr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsString a2dpState;
+
+  if (aState == A2DP_AUDIO_STATE_STARTED) {
+    a2dpState = NS_LITERAL_STRING("playing");
+  } else if (aState == A2DP_AUDIO_STATE_STOPPED) {
+    // for avdtp state stop stream
+    a2dpState = NS_LITERAL_STRING("connected");
+  } else if (aState == A2DP_AUDIO_STATE_REMOTE_SUSPEND) {
+    // for avdtp state suspend stream from remote side
+    a2dpState = NS_LITERAL_STRING("connected");
+  }
+
+  InfallibleTArray<BluetoothNamedValue> props;
+  BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
+
+  BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
+                         nsString(aBdAddr), props);
+  NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
+}
+
+/*
+ * AVRCP Notifications
+ */
+
+void
+BluetoothA2dpManager::GetPlayStatusNotification()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_DispatchToMainThread(new RequestPlayStatusTask());
+}
+
+/* Player application settings is optional for AVRCP 1.3. B2G
+ * currently does not support player-application-setting related
+ * functionality.
+ */
+void
+BluetoothA2dpManager::ListPlayerAppAttrNotification()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::ListPlayerAppValuesNotification(
+  BluetoothAvrcpPlayerAttribute aAttrId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::GetPlayerAppValueNotification(
+  uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::GetPlayerAppAttrsTextNotification(
+  uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::GetPlayerAppValuesTextNotification(
+  uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::SetPlayerAppValueNotification(
+  const BluetoothAvrcpPlayerSettings& aSettings)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+/* This method returns element attributes, which are requested from
+ * CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
+ * meta-data information, but instead uses |GetElementAttrNotifications|
+ * and |GetElementAttrRsp| request them.
+ */
+void
+BluetoothA2dpManager::GetElementAttrNotification(
+  uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_DispatchToMainThread(new UpdateElementAttrsTask(aNumAttrs, aAttrs));
+}
+
+void
+BluetoothA2dpManager::RegisterNotificationNotification(
+  BluetoothAvrcpEvent aEvent, uint32_t aParam)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_DispatchToMainThread(new UpdateRegisterNotificationTask(aEvent, aParam));
+}
+
+/* This method is used to get CT features from the Feature Bit Mask. If
+ * Advanced Control Player bit is set, the CT supports volume sync (absolute
+ * volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
+ * supported.
+ */
+void
+BluetoothA2dpManager::RemoteFeatureNotification(
+    const nsAString& aBdAddr, unsigned long aFeatures)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP 1.4 absolute volume/browse
+}
+
+/* This method is used to get notifications about volume changes on the
+ * remote car kit (if it supports AVRCP 1.4), not notification from phone.
+ */
+void
+BluetoothA2dpManager::VolumeChangeNotification(uint8_t aVolume,
+                                               uint8_t aCType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP 1.4 absolute volume/browse
+}
+
+void
+BluetoothA2dpManager::PassthroughCmdNotification(int aId, int aKeyState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Fast-forward and rewind key events won't be generated from bluedroid
+  // stack after ANDROID_VERSION > 18, but via passthrough callback.
+  nsAutoString name;
+  NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
+                      aKeyState == AVRC_KEY_RELEASE_STATE);
+  switch (aId) {
+    case AVRC_ID_FAST_FOR:
+      if (aKeyState == AVRC_KEY_PRESS_STATE) {
+        name.AssignLiteral("media-fast-forward-button-press");
+      } else {
+        name.AssignLiteral("media-fast-forward-button-release");
+      }
+      break;
+    case AVRC_ID_REWIND:
+      if (aKeyState == AVRC_KEY_PRESS_STATE) {
+        name.AssignLiteral("media-rewind-button-press");
+      } else {
+        name.AssignLiteral("media-rewind-button-release");
+      }
+      break;
+    default:
+      BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
+      return;
+  }
+
+  NS_DispatchToMainThread(new UpdatePassthroughCmdTask(name));
+}
+
 NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)
 
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
@@ -3,21 +3,24 @@
 /* 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/. */
 
 #ifndef mozilla_dom_bluetooth_bluetootha2dpmanager_h__
 #define mozilla_dom_bluetooth_bluetootha2dpmanager_h__
 
 #include "BluetoothCommon.h"
+#include "BluetoothInterface.h"
 #include "BluetoothProfileController.h"
 #include "BluetoothProfileManagerBase.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 class BluetoothA2dpManager : public BluetoothProfileManagerBase
+                           , public BluetoothA2dpNotificationHandler
+                           , public BluetoothAvrcpNotificationHandler
 {
 public:
   BT_DECL_PROFILE_MGR_BASE
   virtual void GetName(nsACString& aName)
   {
     aName.AssignLiteral("A2DP");
   }
 
@@ -58,24 +61,63 @@ public:
   ControlPlayStatus GetPlayStatus();
   uint32_t GetPosition();
   uint64_t GetMediaNumber();
   uint64_t GetTotalMediaNumber();
   void GetTitle(nsAString& aTitle);
   void GetArtist(nsAString& aArtist);
 
 private:
-  class SinkPropertyChangedHandler;
   BluetoothA2dpManager();
   void ResetA2dp();
   void ResetAvrcp();
 
   void HandleShutdown();
   void NotifyConnectionStatusChanged();
 
+  void ConnectionStateNotification(BluetoothA2dpConnectionState aState,
+                                   const nsAString& aBdAddr) MOZ_OVERRIDE;
+  void AudioStateNotification(BluetoothA2dpAudioState aState,
+                              const nsAString& aBdAddr) MOZ_OVERRIDE;
+
+  void GetPlayStatusNotification() MOZ_OVERRIDE;
+
+  void ListPlayerAppAttrNotification() MOZ_OVERRIDE;
+
+  void ListPlayerAppValuesNotification(
+    BluetoothAvrcpPlayerAttribute aAttrId) MOZ_OVERRIDE;
+
+  void GetPlayerAppValueNotification(
+    uint8_t aNumAttrs,
+    const BluetoothAvrcpPlayerAttribute* aAttrs) MOZ_OVERRIDE;
+
+  void GetPlayerAppAttrsTextNotification(
+    uint8_t aNumAttrs,
+    const BluetoothAvrcpPlayerAttribute* aAttrs) MOZ_OVERRIDE;
+
+  void GetPlayerAppValuesTextNotification(
+    uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) MOZ_OVERRIDE;
+
+  void SetPlayerAppValueNotification(
+    const BluetoothAvrcpPlayerSettings& aSettings) MOZ_OVERRIDE;
+
+  void GetElementAttrNotification(
+    uint8_t aNumAttrs,
+    const BluetoothAvrcpMediaAttribute* aAttrs) MOZ_OVERRIDE;
+
+  void RegisterNotificationNotification(
+    BluetoothAvrcpEvent aEvent, uint32_t aParam) MOZ_OVERRIDE;
+
+  void RemoteFeatureNotification(
+    const nsAString& aBdAddr, unsigned long aFeatures) MOZ_OVERRIDE;
+
+  void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) MOZ_OVERRIDE;
+
+  void PassthroughCmdNotification(int aId, int aKeyState) MOZ_OVERRIDE;
+
   nsString mDeviceAddress;
   nsRefPtr<BluetoothProfileController> mController;
 
   // A2DP data member
   bool mA2dpConnected;
   SinkState mSinkState;
 
   // AVRCP data member