Bug 1095488: Add Bluetooth AVRCP helpers, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Wed, 07 Jan 2015 11:32:05 +0100
changeset 222434 6aa9be9df45007e8a40c5f6accf11302dc562e64
parent 222433 2ba09c9c7479109e642688162e7931f6c906c2cc
child 222435 68e1922b83f0ac9bb064d4f87677d4ef6371b5fa
push id28065
push userkwierso@gmail.com
push dateWed, 07 Jan 2015 22:51:36 +0000
treeherdermozilla-central@d55528833b3e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1095488
milestone37.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 1095488: Add Bluetooth AVRCP helpers, r=shuang
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -65,16 +65,49 @@ Convert(int aIn, int16_t& aOut)
     aOut = 0; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = static_cast<int16_t>(aIn);
   return NS_OK;
 }
 
 nsresult
+Convert(int32_t aIn, BluetoothDeviceType& aOut)
+{
+  static const BluetoothDeviceType sDeviceType[] = {
+    CONVERT(0x00, static_cast<BluetoothDeviceType>(0)), // invalid, required by gcc
+    CONVERT(0x01, DEVICE_TYPE_BREDR),
+    CONVERT(0x02, DEVICE_TYPE_BLE),
+    CONVERT(0x03, DEVICE_TYPE_DUAL)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sDeviceType))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sDeviceType[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(int32_t aIn, BluetoothScanMode& aOut)
+{
+  static const BluetoothScanMode sScanMode[] = {
+    CONVERT(0x00, SCAN_MODE_NONE),
+    CONVERT(0x01, SCAN_MODE_CONNECTABLE),
+    CONVERT(0x02, SCAN_MODE_CONNECTABLE_DISCOVERABLE)
+  };
+  if (NS_WARN_IF(aIn < 0) ||
+      NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sScanMode))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sScanMode[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, bool& aOut)
 {
   static const bool sBool[] = {
     CONVERT(0x00, false),
     CONVERT(0x01, true)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
     return NS_ERROR_ILLEGAL_VALUE;
@@ -93,16 +126,23 @@ Convert(uint8_t aIn, char& aOut)
 nsresult
 Convert(uint8_t aIn, int& aOut)
 {
   aOut = static_cast<int>(aIn);
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, unsigned long& aOut)
+{
+  aOut = static_cast<unsigned long>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut)
 {
   static const BluetoothA2dpAudioState sAudioState[] = {
     CONVERT(0x00, A2DP_AUDIO_STATE_REMOTE_SUSPEND),
     CONVERT(0x01, A2DP_AUDIO_STATE_STOPPED),
     CONVERT(0x02, A2DP_AUDIO_STATE_STARTED)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAudioState))) {
@@ -138,16 +178,103 @@ Convert(uint8_t aIn, BluetoothAclState& 
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAclState))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sAclState[aIn];
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, BluetoothAvrcpEvent& aOut)
+{
+  static const BluetoothAvrcpEvent sAvrcpEvent[] = {
+    CONVERT(0x00, static_cast<BluetoothAvrcpEvent>(0)),
+    CONVERT(0x01, AVRCP_EVENT_PLAY_STATUS_CHANGED),
+    CONVERT(0x02, AVRCP_EVENT_TRACK_CHANGE),
+    CONVERT(0x03, AVRCP_EVENT_TRACK_REACHED_END),
+    CONVERT(0x04, AVRCP_EVENT_TRACK_REACHED_START),
+    CONVERT(0x05, AVRCP_EVENT_PLAY_POS_CHANGED),
+    CONVERT(0x06, static_cast<BluetoothAvrcpEvent>(0)),
+    CONVERT(0x07, static_cast<BluetoothAvrcpEvent>(0)),
+    CONVERT(0x08, AVRCP_EVENT_APP_SETTINGS_CHANGED)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn == 0x06) ||
+      NS_WARN_IF(aIn == 0x07) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpEvent))) {
+    aOut = static_cast<BluetoothAvrcpEvent>(0); // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpEvent[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpMediaAttribute& aOut)
+{
+  static const BluetoothAvrcpMediaAttribute sAvrcpMediaAttribute[] = {
+    CONVERT(0x00, static_cast<BluetoothAvrcpMediaAttribute>(0)),
+    CONVERT(0x01, AVRCP_MEDIA_ATTRIBUTE_TITLE),
+    CONVERT(0x02, AVRCP_MEDIA_ATTRIBUTE_ARTIST),
+    CONVERT(0x03, AVRCP_MEDIA_ATTRIBUTE_ALBUM),
+    CONVERT(0x04, AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM),
+    CONVERT(0x05, AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS),
+    CONVERT(0x06, AVRCP_MEDIA_ATTRIBUTE_GENRE),
+    CONVERT(0x07, AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpMediaAttribute))) {
+    // silences compiler warning
+    aOut = static_cast<BluetoothAvrcpMediaAttribute>(0);
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpMediaAttribute[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpPlayerAttribute& aOut)
+{
+  static const BluetoothAvrcpPlayerAttribute sAvrcpPlayerAttribute[] = {
+    CONVERT(0x00, static_cast<BluetoothAvrcpPlayerAttribute>(0)),
+    CONVERT(0x01, AVRCP_PLAYER_ATTRIBUTE_EQUALIZER),
+    CONVERT(0x02, AVRCP_PLAYER_ATTRIBUTE_REPEAT),
+    CONVERT(0x03, AVRCP_PLAYER_ATTRIBUTE_SHUFFLE),
+    CONVERT(0x04, AVRCP_PLAYER_ATTRIBUTE_SCAN)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpPlayerAttribute))) {
+    // silences compiler warning
+    aOut = static_cast<BluetoothAvrcpPlayerAttribute>(0);
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpPlayerAttribute[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpRemoteFeature& aOut)
+{
+  static const BluetoothAvrcpRemoteFeature sAvrcpRemoteFeature[] = {
+    CONVERT(0x00, AVRCP_REMOTE_FEATURE_NONE),
+    CONVERT(0x01, AVRCP_REMOTE_FEATURE_METADATA),
+    CONVERT(0x02, AVRCP_REMOTE_FEATURE_ABSOLUTE_VOLUME),
+    CONVERT(0x03, AVRCP_REMOTE_FEATURE_BROWSE)
+  };
+  if (NS_WARN_IF(!aIn) ||
+      NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAvrcpRemoteFeature))) {
+    // silences compiler warning
+    aOut = static_cast<BluetoothAvrcpRemoteFeature>(0);
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAvrcpRemoteFeature[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothBondState& aOut)
 {
   static const BluetoothBondState sBondState[] = {
     CONVERT(0x00, BOND_STATE_NONE),
     CONVERT(0x01, BOND_STATE_BONDING),
     CONVERT(0x02, BOND_STATE_BONDED)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBondState))) {
@@ -244,33 +371,16 @@ Convert(uint8_t aIn, BluetoothHandsfreeV
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sVolumeType))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sVolumeType[aIn];
   return NS_OK;
 }
 
 nsresult
-Convert(int32_t aIn, BluetoothDeviceType& aOut)
-{
-  static const BluetoothDeviceType sDeviceType[] = {
-    CONVERT(0x00, static_cast<BluetoothDeviceType>(0)), // invalid, required by gcc
-    CONVERT(0x01, DEVICE_TYPE_BREDR),
-    CONVERT(0x02, DEVICE_TYPE_BLE),
-    CONVERT(0x03, DEVICE_TYPE_DUAL)
-  };
-  if (NS_WARN_IF(!aIn) ||
-      NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sDeviceType))) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = sDeviceType[aIn];
-  return NS_OK;
-}
-
-nsresult
 Convert(uint8_t aIn, BluetoothPropertyType& aOut)
 {
   static const BluetoothPropertyType sPropertyType[] = {
     CONVERT(0x00, static_cast<BluetoothPropertyType>(0)), // invalid, required by gcc
     CONVERT(0x01, PROPERTY_BDNAME),
     CONVERT(0x02, PROPERTY_BDADDR),
     CONVERT(0x03, PROPERTY_UUIDS),
     CONVERT(0x04, PROPERTY_CLASS_OF_DEVICE),
@@ -313,32 +423,16 @@ Convert(BluetoothSocketType aIn, uint8_t
     aOut = 0; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sSocketType[aIn];
   return NS_OK;
 }
 
 nsresult
-Convert(int32_t aIn, BluetoothScanMode& aOut)
-{
-  static const BluetoothScanMode sScanMode[] = {
-    CONVERT(0x00, SCAN_MODE_NONE),
-    CONVERT(0x01, SCAN_MODE_CONNECTABLE),
-    CONVERT(0x02, SCAN_MODE_CONNECTABLE_DISCOVERABLE)
-  };
-  if (NS_WARN_IF(aIn < 0) ||
-      NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sScanMode))) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = sScanMode[aIn];
-  return NS_OK;
-}
-
-nsresult
 Convert(uint8_t aIn, BluetoothSspPairingVariant& aOut)
 {
   static const BluetoothSspPairingVariant sSspPairingVariant[] = {
     CONVERT(0x00, SSP_VARIANT_PASSKEY_CONFIRMATION),
     CONVERT(0x01, SSP_VARIANT_PASSKEY_ENTRY),
     CONVERT(0x02, SSP_VARIANT_CONSENT),
     CONVERT(0x03, SSP_VARIANT_PASSKEY_NOTIFICATION)
   };
@@ -375,16 +469,28 @@ Convert(uint8_t aIn, BluetoothStatus& aO
 nsresult
 Convert(uint32_t aIn, int& aOut)
 {
   aOut = static_cast<int>(aIn);
   return NS_OK;
 }
 
 nsresult
+Convert(uint32_t aIn, uint8_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<uint8_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(size_t aIn, uint16_t& aOut)
 {
   if (NS_WARN_IF(aIn >= (1ul << 16))) {
     aOut = 0; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = static_cast<uint16_t>(aIn);
   return NS_OK;
@@ -517,16 +623,60 @@ Convert(const BluetoothAddress& aIn, nsA
   }
 
   aOut = NS_ConvertUTF8toUTF16(str);
 
   return NS_OK;
 }
 
 nsresult
+Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut)
+{
+  static const uint8_t sValue[] = {
+    CONVERT(AVRCP_EVENT_PLAY_STATUS_CHANGED, 0x01),
+    CONVERT(AVRCP_EVENT_TRACK_CHANGE, 0x02),
+    CONVERT(AVRCP_EVENT_TRACK_REACHED_END, 0x03),
+    CONVERT(AVRCP_EVENT_TRACK_REACHED_START, 0x04),
+    CONVERT(AVRCP_EVENT_PLAY_POS_CHANGED, 0x05),
+    CONVERT(AVRCP_EVENT_APP_SETTINGS_CHANGED, 0x08)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut)
+{
+  static const bool sValue[] = {
+    CONVERT(AVRCP_NTF_INTERIM, 0x00),
+    CONVERT(AVRCP_NTF_CHANGED, 0x01)
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<unsigned long>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<unsigned long>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<unsigned long>(aIn);
+  return NS_OK;
+}
+
+nsresult
 Convert(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut)
 {
   static const uint8_t sAtResponse[] = {
     CONVERT(HFP_AT_RESPONSE_ERROR, 0x00),
     CONVERT(HFP_AT_RESPONSE_OK, 0x01)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAtResponse))) {
     aOut = 0x00; // silences compiler warning
@@ -743,16 +893,40 @@ Convert(BluetoothSspPairingVariant aIn, 
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sString))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = NS_ConvertUTF8toUTF16(sString[aIn]);
   return NS_OK;
 }
 
+nsresult
+Convert(ControlPlayStatus aIn, uint8_t& aOut)
+{
+  static const uint8_t sValue[] = {
+    CONVERT(PLAYSTATUS_STOPPED, 0x00),
+    CONVERT(PLAYSTATUS_PLAYING, 0x01),
+    CONVERT(PLAYSTATUS_PAUSED, 0x02),
+    CONVERT(PLAYSTATUS_FWD_SEEK, 0x03),
+    CONVERT(PLAYSTATUS_REV_SEEK, 0x04)
+  };
+  if (aIn == PLAYSTATUS_ERROR) {
+    /* This case is handled separately to not populate
+     * |sValue| with empty entries. */
+    aOut = 0xff;
+    return NS_OK;
+  }
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
 /* |ConvertArray| is a helper for converting arrays. Pass an
  * instance of this structure as the first argument to |Convert|
  * to convert an array. The output type has to support the array
  * subscript operator.
  */
 template <typename T>
 struct ConvertArray
 {
@@ -794,16 +968,152 @@ PackPDU(bool aIn, BluetoothDaemonPDU& aP
 
 nsresult
 PackPDU(const BluetoothAddress& aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(PackArray<uint8_t>(aIn.mAddr, sizeof(aIn.mAddr)), aPDU);
 }
 
 nsresult
+PackPDU(const BluetoothAvrcpAttributeTextPairs& aIn,
+        BluetoothDaemonPDU& aPDU)
+{
+  size_t i;
+
+  for (i = 0; i < aIn.mLength; ++i) {
+    nsresult rv = PackPDU(aIn.mAttr[i], aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    uint8_t len;
+    const uint8_t* str;
+
+    if (aIn.mText[i]) {
+      str = reinterpret_cast<const uint8_t*>(aIn.mText[i]);
+      len = strlen(aIn.mText[i]) + 1;
+    } else {
+      /* write \0 character for NULL strings */
+      str = reinterpret_cast<const uint8_t*>("\0");
+      len = 1;
+    }
+
+    rv = PackPDU(len, aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = PackPDU(PackArray<uint8_t>(str, len), aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PackPDU(const BluetoothAvrcpAttributeValuePairs& aIn,
+        BluetoothDaemonPDU& aPDU)
+{
+  size_t i;
+
+  for (i = 0; i < aIn.mLength; ++i) {
+    nsresult rv = PackPDU(aIn.mAttr[i], aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = PackPDU(aIn.mValue[i], aPDU);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv = PackPDU(PackConversion<uint32_t, uint8_t>(aIn.mId), aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  const NS_ConvertUTF16toUTF8 cstr(aIn.mValue);
+
+  if (NS_WARN_IF(cstr.Length() == PR_UINT32_MAX)) {
+    return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
+  }
+
+  PRUint32 clen = cstr.Length() + 1; /* include \0 character */
+
+  rv = PackPDU(PackConversion<PRUint32, uint8_t>(clen), aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return PackPDU(
+    PackArray<uint8_t>(reinterpret_cast<const uint8_t*>(cstr.get()), clen),
+    aPDU);
+}
+
+nsresult
+PackPDU(BluetoothAvrcpEvent aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<BluetoothAvrcpEvent, uint8_t>(aIn), aPDU);
+}
+
+nsresult
+PackPDU(const BluetoothAvrcpEventParamPair& aIn, BluetoothDaemonPDU& aPDU)
+{
+  nsresult rv;
+
+  switch (aIn.mEvent) {
+    case AVRCP_EVENT_PLAY_STATUS_CHANGED:
+      rv = PackPDU(aIn.mParam.mPlayStatus, aPDU);
+      break;
+    case AVRCP_EVENT_TRACK_CHANGE:
+      rv = PackPDU(PackArray<uint8_t>(aIn.mParam.mTrack,
+                                      MOZ_ARRAY_LENGTH(aIn.mParam.mTrack)),
+                   aPDU);
+      break;
+    case AVRCP_EVENT_TRACK_REACHED_END:
+      /* fall through */
+    case AVRCP_EVENT_TRACK_REACHED_START:
+      /* no data to pack */
+      rv = NS_OK;
+      break;
+    case AVRCP_EVENT_PLAY_POS_CHANGED:
+      rv = PackPDU(aIn.mParam.mSongPos, aPDU);
+      break;
+    case AVRCP_EVENT_APP_SETTINGS_CHANGED:
+      /* pack number of attribute-value pairs */
+      rv = PackPDU(aIn.mParam.mNumAttr, aPDU);
+      if (NS_FAILED(rv)) {
+        return rv;
+      }
+      /* pack attribute-value pairs */
+      rv = PackPDU(BluetoothAvrcpAttributeValuePairs(aIn.mParam.mIds,
+                                                     aIn.mParam.mValues,
+                                                     aIn.mParam.mNumAttr),
+                   aPDU);
+      break;
+    default:
+      rv = NS_ERROR_ILLEGAL_VALUE;
+      break;
+  }
+  return rv;
+}
+
+nsresult
+PackPDU(BluetoothAvrcpNotification aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(
+    PackConversion<BluetoothAvrcpNotification, uint8_t>(aIn), aPDU);
+}
+
+nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(aIn.mType, aIn.mLength,
                  PackArray<uint8_t>(aIn.mValue.get(), aIn.mLength), aPDU);
 }
 
 nsresult
 PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU)
@@ -944,16 +1254,22 @@ PackPDU(const BluetoothServiceName& aIn,
 }
 
 nsresult
 PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU)
 {
   return PackPDU(PackConversion<BluetoothSocketType, uint8_t>(aIn), aPDU);
 }
 
+nsresult
+PackPDU(ControlPlayStatus aIn, BluetoothDaemonPDU& aPDU)
+{
+  return PackPDU(PackConversion<ControlPlayStatus, uint8_t>(aIn), aPDU);
+}
+
 //
 // Unpacking
 //
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, bool& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, bool>(aOut));
@@ -981,16 +1297,66 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, Blue
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAclState& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothAclState>(aOut));
 }
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpEvent& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpEvent>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpMediaAttribute& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpMediaAttribute>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerAttribute& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpPlayerAttribute>(aOut));
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerSettings& aOut)
+{
+  /* Read number of attribute-value pairs */
+  nsresult rv = UnpackPDU(aPDU, aOut.mNumAttr);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* Read attribute-value pairs */
+  for (uint8_t i = 0; i < aOut.mNumAttr; ++i) {
+    nsresult rv = UnpackPDU(aPDU, aOut.mIds[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    rv = UnpackPDU(aPDU, aOut.mValues[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpRemoteFeature& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothAvrcpRemoteFeature>(aOut));
+}
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut)
 {
   return UnpackPDU(aPDU, UnpackConversion<uint8_t, BluetoothBondState>(aOut));
 }
 
 nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothDeviceType& aOut)
 {
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -45,16 +45,55 @@ enum BluetoothSspPairingVariant {
   SSP_VARIANT_CONSENT,
   SSP_VARIANT_PASSKEY_NOTIFICATION
 };
 
 struct BluetoothAddress {
   uint8_t mAddr[6];
 };
 
+struct BluetoothAvrcpAttributeTextPairs {
+  BluetoothAvrcpAttributeTextPairs(const uint8_t* aAttr,
+                                   const char** aText,
+                                   size_t aLength)
+    : mAttr(aAttr)
+    , mText(aText)
+    , mLength(aLength)
+  { }
+
+  const uint8_t* mAttr;
+  const char** mText;
+  size_t mLength;
+};
+
+struct BluetoothAvrcpAttributeValuePairs {
+  BluetoothAvrcpAttributeValuePairs(const uint8_t* aAttr,
+                                    const uint8_t* aValue,
+                                    size_t aLength)
+    : mAttr(aAttr)
+    , mValue(aValue)
+    , mLength(aLength)
+  { }
+
+  const uint8_t* mAttr;
+  const uint8_t* mValue;
+  size_t mLength;
+};
+
+struct BluetoothAvrcpEventParamPair {
+  BluetoothAvrcpEventParamPair(BluetoothAvrcpEvent aEvent,
+                               const BluetoothAvrcpNotificationParam& aParam)
+    : mEvent(aEvent)
+    , mParam(aParam)
+  { }
+
+  BluetoothAvrcpEvent mEvent;
+  const BluetoothAvrcpNotificationParam& mParam;
+};
+
 struct BluetoothConfigurationParameter {
   uint8_t mType;
   uint16_t mLength;
   nsAutoArrayPtr<uint8_t> mValue;
 };
 
 struct BluetoothDaemonPDUHeader {
   BluetoothDaemonPDUHeader()
@@ -105,34 +144,55 @@ Convert(bool aIn, BluetoothScanMode& aOu
 
 nsresult
 Convert(int aIn, uint8_t& aOut);
 
 nsresult
 Convert(int aIn, int16_t& aOut);
 
 nsresult
+Convert(int32_t aIn, BluetoothDeviceType& aOut);
+
+nsresult
+Convert(int32_t aIn, BluetoothScanMode& aOut);
+
+nsresult
 Convert(uint8_t aIn, bool& aOut);
 
 nsresult
 Convert(uint8_t aIn, char& aOut);
 
 nsresult
 Convert(uint8_t aIn, int& aOut);
 
 nsresult
+Convert(uint8_t aIn, unsigned long& aOut);
+
+nsresult
 Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothA2dpConnectionState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothAclState& aOut);
 
 nsresult
+Convert(uint8_t aIn, BluetoothAvrcpEvent& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpMediaAttribute& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpPlayerAttribute& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothAvrcpRemoteFeature& aOut);
+
+nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeAudioState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeCallHoldType& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothHandsfreeConnectionState& aOut);
 
@@ -162,16 +222,19 @@ Convert(uint8_t aIn, BluetoothSspPairing
 
 nsresult
 Convert(uint8_t aIn, BluetoothStatus& aOut);
 
 nsresult
 Convert(uint32_t aIn, int& aOut);
 
 nsresult
+Convert(uint32_t aIn, uint8_t& aOut);
+
+nsresult
 Convert(size_t aIn, uint16_t& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothAddress& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothPinCode& aOut);
 
@@ -186,16 +249,25 @@ Convert(const nsAString& aIn, BluetoothS
 
 nsresult
 Convert(BluetoothAclState aIn, bool& aOut);
 
 nsresult
 Convert(const BluetoothAddress& aIn, nsAString& aOut);
 
 nsresult
+Convert(BluetoothAvrcpEvent aIn, uint8_t& aOut);
+
+nsresult
+Convert(BluetoothAvrcpNotification aIn, uint8_t& aOut);
+
+nsresult
+Convert(BluetoothAvrcpRemoteFeature aIn, unsigned long& aOut);
+
+nsresult
 Convert(BluetoothHandsfreeAtResponse aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothHandsfreeCallAddressType aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothHandsfreeCallDirection aIn, uint8_t& aOut);
 
@@ -230,16 +302,19 @@ nsresult
 Convert(BluetoothSocketType aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothSspPairingVariant aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothSspPairingVariant aIn, nsAString& aOut);
 
+nsresult
+Convert(ControlPlayStatus aIn, uint8_t& aOut);
+
 //
 // Packing
 //
 
 nsresult
 PackPDU(bool aIn, BluetoothDaemonPDU& aPDU);
 
 inline nsresult
@@ -265,16 +340,36 @@ PackPDU(uint32_t aIn, BluetoothDaemonPDU
 {
   return aPDU.Write(aIn);
 }
 
 nsresult
 PackPDU(const BluetoothAddress& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
+PackPDU(const BluetoothAvrcpAttributeTextPairs& aIn,
+        BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothAvrcpAttributeValuePairs& aIn,
+        BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothAvrcpEvent aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothAvrcpEventParamPair& aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothAvrcpNotification aIn, BluetoothDaemonPDU& aPDU);
+
+nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothDaemonPDUHeader& aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothHandsfreeAtResponse& aIn, BluetoothDaemonPDU& aPDU);
 
@@ -318,16 +413,19 @@ nsresult
 PackPDU(BluetoothSocketType aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothSspPairingVariant aIn, BluetoothDaemonPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothScanMode aIn, BluetoothDaemonPDU& aPDU);
 
+nsresult
+PackPDU(ControlPlayStatus aIn, BluetoothDaemonPDU& aPDU);
+
 /* |PackConversion| is a helper for packing converted values. Pass
  * an instance of this structure to |PackPDU| to convert a value from
  * the input type to the output type and and write it to the PDU.
  */
 template<typename Tin, typename Tout>
 struct PackConversion {
   PackConversion(const Tin& aIn)
   : mIn(aIn)
@@ -571,16 +669,31 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, Blue
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAddress& aOut)
 {
   return aPDU.Read(aOut.mAddr, sizeof(aOut.mAddr));
 }
 
 nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpEvent& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpMediaAttribute& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerAttribute& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpPlayerSettings& aOut);
+
+nsresult
+UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothAvrcpRemoteFeature& aOut);
+
+nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothBondState& aOut);
 
 inline nsresult
 UnpackPDU(BluetoothDaemonPDU& aPDU, BluetoothDaemonPDUHeader& aOut)
 {
   nsresult rv = UnpackPDU(aPDU, aOut.mService);
   if (NS_FAILED(rv)) {
     return rv;