Bug 1095488: Add Bluetooth AVRCP helpers, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Wed, 07 Jan 2015 11:32:05 +0100
changeset 239172 6aa9be9df45007e8a40c5f6accf11302dc562e64
parent 239171 2ba09c9c7479109e642688162e7931f6c906c2cc
child 239173 68e1922b83f0ac9bb064d4f87677d4ef6371b5fa
push id7472
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 20:36:27 +0000
treeherdermozilla-aurora@300ca104f8fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1095488
milestone37.0a1
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;