Bug 1038591: Convert Bluetooth AVRCP data types in |BluetoothAvrcpInterface|, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Wed, 06 Aug 2014 11:45:22 +0200
changeset 212440 d55ed75e12a03cf755afbea6d7cd604ee6475e0f
parent 212439 cf3bcd7c1082bb4e1789763348ed7180773300d9
child 212441 2b8c20e476c2da49c9162bbfed92072b17223adc
push idunknown
push userunknown
push dateunknown
reviewersshuang
bugs1038591
milestone34.0a1
Bug 1038591: Convert Bluetooth AVRCP data types in |BluetoothAvrcpInterface|, r=shuang With this patch |BluetoothAvrcpInterface| is responsible for converting all Bluetooth data types to Bluedroid types. All callers have been adapted.
dom/bluetooth/BluetoothCommon.h
dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
dom/bluetooth/bluedroid/BluetoothA2dpManager.h
dom/bluetooth/bluedroid/BluetoothInterface.cpp
dom/bluetooth/bluedroid/BluetoothInterface.h
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -209,11 +209,54 @@ enum ControlPlayStatus {
   PLAYSTATUS_PLAYING  = 0x01,
   PLAYSTATUS_PAUSED   = 0x02,
   PLAYSTATUS_FWD_SEEK = 0x03,
   PLAYSTATUS_REV_SEEK = 0x04,
   PLAYSTATUS_UNKNOWN,
   PLAYSTATUS_ERROR    = 0xFF,
 };
 
+enum BluetoothAvrcpPlayerAttribute {
+  AVRCP_PLAYER_ATTRIBUTE_EQUALIZER,
+  AVRCP_PLAYER_ATTRIBUTE_REPEAT,
+  AVRCP_PLAYER_ATTRIBUTE_SHUFFLE,
+  AVRCP_PLAYER_ATTRIBUTE_SCAN
+};
+
+enum BluetoothAvrcpStatus {
+  AVRCP_STATUS_BAD_COMMAND,
+  AVRCP_STATUS_BAD_PARAMETER,
+  AVRCP_STATUS_NOT_FOUND,
+  AVRCP_STATUS_INTERNAL_ERROR,
+  AVRCP_STATUS_SUCCESS
+};
+
+enum BluetoothAvrcpEvent {
+  AVRCP_EVENT_PLAY_STATUS_CHANGED,
+  AVRCP_EVENT_TRACK_CHANGE,
+  AVRCP_EVENT_TRACK_REACHED_END,
+  AVRCP_EVENT_TRACK_REACHED_START,
+  AVRCP_EVENT_PLAY_POS_CHANGED,
+  AVRCP_EVENT_APP_SETTINGS_CHANGED
+};
+
+enum BluetoothAvrcpNotification {
+  AVRCP_NTF_INTERIM,
+  AVRCP_NTF_CHANGED
+};
+
+struct BluetoothAvrcpElementAttribute {
+  uint32_t mId;
+  nsString mValue;
+};
+
+struct BluetoothAvrcpNotificationParam {
+  ControlPlayStatus mPlayStatus;
+  uint8_t mTrack[8];
+  uint32_t mSongPos;
+  uint8_t mNumAttr;
+  uint8_t mIds[256];
+  uint8_t mValues[256];
+};
+
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -84,34 +84,34 @@ public:
     return NS_OK;
   }
 };
 
 #if ANDROID_VERSION > 17
 class UpdateRegisterNotificationTask : public nsRunnable
 {
 public:
-  UpdateRegisterNotificationTask(btrc_event_id_t aEventId, uint32_t aParam)
-    : mEventId(aEventId)
+  UpdateRegisterNotificationTask(BluetoothAvrcpEvent aEvent, uint32_t aParam)
+    : mEvent(aEvent)
     , mParam(aParam)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   nsresult Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
     NS_ENSURE_TRUE(a2dp, NS_OK);
-    a2dp->UpdateRegisterNotification(mEventId, mParam);
+    a2dp->UpdateRegisterNotification(mEvent, mParam);
     return NS_OK;
   }
 private:
-  btrc_event_id_t mEventId;
+  BluetoothAvrcpEvent mEvent;
   uint32_t mParam;
 };
 
 /*
  * This function maps attribute id and returns corresponding values
  * Attribute id refers to btrc_media_attr_t in bt_rc.h
  */
 static void
@@ -144,43 +144,45 @@ ConvertAttributeString(int aAttrId, nsAS
       aAttrStr.AppendInt(a2dp->GetDuration());
       break;
   }
 }
 
 class UpdateElementAttrsTask : public nsRunnable
 {
 public:
-  UpdateElementAttrsTask(uint8_t aNumAttr, btrc_media_attr_t* aPlayerAttrs)
-    : mNumAttr(aNumAttr)
-    , mPlayerAttrs(aPlayerAttrs)
+  UpdateElementAttrsTask(uint8_t aNumAttr, const btrc_media_attr_t* aPlayerAttrs)
+  : mNumAttr(aNumAttr)
   {
     MOZ_ASSERT(!NS_IsMainThread());
+
+    mAttrs = new BluetoothAvrcpElementAttribute[mNumAttr];
+
+    for (uint8_t i = 0; i < mNumAttr; ++i) {
+      mAttrs[i].mId = aPlayerAttrs[i];
+    }
   }
 
   nsresult Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    btrc_element_attr_val_t* attrs = new btrc_element_attr_val_t[mNumAttr];
-    for (int i = 0; i < mNumAttr; i++) {
-      nsAutoString attrText;
-      attrs[i].attr_id = mPlayerAttrs[i];
-      ConvertAttributeString(mPlayerAttrs[i], attrText);
-      strcpy((char *)attrs[i].text, NS_ConvertUTF16toUTF8(attrText).get());
+    for (uint8_t i = 0; i < mNumAttr; ++i) {
+      ConvertAttributeString(mAttrs[i].mId, mAttrs[i].mValue);
     }
 
     NS_ENSURE_TRUE(sBtAvrcpInterface, NS_OK);
-    sBtAvrcpInterface->GetElementAttrRsp(mNumAttr, attrs, nullptr);
+    sBtAvrcpInterface->GetElementAttrRsp(mNumAttr, mAttrs, nullptr);
 
     return NS_OK;
   }
+
 private:
   uint8_t mNumAttr;
-  btrc_media_attr_t* mPlayerAttrs;
+  nsAutoArrayPtr<BluetoothAvrcpElementAttribute> mAttrs;
 };
 
 class UpdatePassthroughCmdTask : public nsRunnable
 {
 public:
   UpdatePassthroughCmdTask(const nsAString& aName)
     : mName(aName)
   {
@@ -337,19 +339,40 @@ AvrcpGetElementAttrCallback(uint8_t aNum
  * To reply RegisterNotification INTERIM response
  * See AVRCP 1.3 Spec 25.2
  * aParam: It only valids if event_id is BTRC_EVT_PLAY_POS_CHANGED,
  * which is playback interval time
  */
 static void
 AvrcpRegisterNotificationCallback(btrc_event_id_t aEventId, uint32_t aParam)
 {
+  BluetoothAvrcpEvent event;
+
   MOZ_ASSERT(!NS_IsMainThread());
 
-  NS_DispatchToMainThread(new UpdateRegisterNotificationTask(aEventId, aParam));
+  switch (aEventId) {
+    case BTRC_EVT_PLAY_STATUS_CHANGED:
+      event = AVRCP_EVENT_PLAY_STATUS_CHANGED;
+    case BTRC_EVT_TRACK_CHANGE:
+      event = AVRCP_EVENT_TRACK_CHANGE;
+    case BTRC_EVT_TRACK_REACHED_END:
+      event = AVRCP_EVENT_TRACK_REACHED_END;
+    case BTRC_EVT_TRACK_REACHED_START:
+      event = AVRCP_EVENT_TRACK_REACHED_START;
+    case BTRC_EVT_PLAY_POS_CHANGED:
+      event = AVRCP_EVENT_PLAY_POS_CHANGED;
+    case BTRC_EVT_APP_SETTINGS_CHANGED:
+      event = AVRCP_EVENT_APP_SETTINGS_CHANGED;
+      break;
+    default:
+      BT_LOGR("Unknown event 0x%x", aEventId);
+      return;
+  }
+
+  NS_DispatchToMainThread(new UpdateRegisterNotificationTask(event, aParam));
 }
 
 /*
  * Player application settings is optional for Avrcp 1.3
  * B2G 1.3 currently does not support Player application setting
  * related functions. Support Player Setting in the future version
  */
 static void
@@ -1092,36 +1115,35 @@ BluetoothA2dpManager::UpdateMetaData(con
   MOZ_ASSERT(NS_IsMainThread());
 
 #if ANDROID_VERSION > 17
   NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
 
   // Send track changed and position changed if track num is not the same.
   // See also AVRCP 1.3 Spec 5.4.2
   if (mMediaNumber != aMediaNumber &&
-      mTrackChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
-    btrc_register_notification_t param;
+      mTrackChangedNotifyType == AVRCP_NTF_INTERIM) {
+    BluetoothAvrcpNotificationParam param;
     // convert to network big endian format
     // since track stores as uint8[8]
     // 56 = 8 * (BTRC_UID_SIZE -1)
     for (int i = 0; i < BTRC_UID_SIZE; ++i) {
-      param.track[i] = (aMediaNumber >> (56 - 8 * i));
+      param.mTrack[i] = (aMediaNumber >> (56 - 8 * i));
     }
-    mTrackChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
-    sBtAvrcpInterface->RegisterNotificationRsp(BTRC_EVT_TRACK_CHANGE,
-                                               BTRC_NOTIFICATION_TYPE_CHANGED,
-                                               &param, nullptr);
-    if (mPlayPosChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
-      param.song_pos = mPosition;
+    mTrackChangedNotifyType = AVRCP_NTF_CHANGED;
+    sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_TRACK_CHANGE,
+                                               AVRCP_NTF_CHANGED,
+                                               param, nullptr);
+    if (mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
+      param.mSongPos = mPosition;
       // EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
-      mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
-      sBtAvrcpInterface->RegisterNotificationRsp(
-        BTRC_EVT_PLAY_POS_CHANGED,
-        BTRC_NOTIFICATION_TYPE_CHANGED,
-        &param, nullptr);
+      mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
+      sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
+                                                 AVRCP_NTF_CHANGED,
+                                                 param, nullptr);
     }
   }
 
   mTitle.Assign(aTitle);
   mArtist.Assign(aArtist);
   mAlbum.Assign(aAlbum);
   mMediaNumber = aMediaNumber;
   mTotalMediaCount = aTotalMediaCount;
@@ -1138,105 +1160,105 @@ BluetoothA2dpManager::UpdatePlayStatus(u
                                        uint32_t aPosition,
                                        ControlPlayStatus aPlayStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
 #if ANDROID_VERSION > 17
   NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
   // always update playstatus first
-  sBtAvrcpInterface->GetPlayStatusRsp((btrc_play_status_t)aPlayStatus,
-                                      aDuration, aPosition, nullptr);
+  sBtAvrcpInterface->GetPlayStatusRsp(aPlayStatus, aDuration,
+                                      aPosition, nullptr);
   // when play status changed, send both play status and position
   if (mPlayStatus != aPlayStatus &&
-      mPlayStatusChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
-    btrc_register_notification_t param;
-    param.play_status = (btrc_play_status_t)aPlayStatus;
-    mPlayStatusChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
-    sBtAvrcpInterface->RegisterNotificationRsp(BTRC_EVT_PLAY_STATUS_CHANGED,
-                                               BTRC_NOTIFICATION_TYPE_CHANGED,
-                                               &param, nullptr);
+      mPlayStatusChangedNotifyType == AVRCP_NTF_INTERIM) {
+    BluetoothAvrcpNotificationParam param;
+    param.mPlayStatus = aPlayStatus;
+    mPlayStatusChangedNotifyType = AVRCP_NTF_CHANGED;
+    sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_STATUS_CHANGED,
+                                               AVRCP_NTF_CHANGED,
+                                               param, nullptr);
   }
 
   if (mPosition != aPosition &&
-      mPlayPosChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
-    btrc_register_notification_t param;
-    param.song_pos = aPosition;
-    mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
-    sBtAvrcpInterface->RegisterNotificationRsp(BTRC_EVT_PLAY_POS_CHANGED,
-                                               BTRC_NOTIFICATION_TYPE_CHANGED,
-                                               &param, nullptr);
+      mPlayPosChangedNotifyType == AVRCP_NTF_INTERIM) {
+    BluetoothAvrcpNotificationParam param;
+    param.mSongPos = aPosition;
+    mPlayPosChangedNotifyType = AVRCP_NTF_CHANGED;
+    sBtAvrcpInterface->RegisterNotificationRsp(AVRCP_EVENT_PLAY_POS_CHANGED,
+                                               AVRCP_NTF_CHANGED,
+                                               param, nullptr);
   }
 
   mDuration = aDuration;
   mPosition = aPosition;
   mPlayStatus = aPlayStatus;
 #endif
 }
 
 /*
  * This function handles RegisterNotification request from
  * AvrcpRegisterNotificationCallback, which updates current
  * track/status/position status in the INTERRIM response.
  *
  * aParam is only valid when position changed
  */
 void
-BluetoothA2dpManager::UpdateRegisterNotification(int aEventId, int aParam)
+BluetoothA2dpManager::UpdateRegisterNotification(BluetoothAvrcpEvent aEvent,
+                                                 uint32_t aParam)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
 #if ANDROID_VERSION > 17
   NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
 
-  btrc_register_notification_t param;
+  BluetoothAvrcpNotificationParam param;
 
-  switch (aEventId) {
-    case BTRC_EVT_PLAY_STATUS_CHANGED:
-      mPlayStatusChangedNotifyType = BTRC_NOTIFICATION_TYPE_INTERIM;
-      param.play_status = (btrc_play_status_t)mPlayStatus;
+  switch (aEvent) {
+    case AVRCP_EVENT_PLAY_STATUS_CHANGED:
+      mPlayStatusChangedNotifyType = AVRCP_NTF_INTERIM;
+      param.mPlayStatus = mPlayStatus;
       break;
-    case BTRC_EVT_TRACK_CHANGE:
+    case AVRCP_EVENT_TRACK_CHANGE:
       // In AVRCP 1.3 and 1.4, the identifier parameter of EVENT_TRACK_CHANGED
       // is different.
       // AVRCP 1.4: If no track is selected, we shall return 0xFFFFFFFFFFFFFFFF,
       // otherwise return 0x0 in the INTERRIM response. The expanded text in
       // version 1.4 is to allow for new UID feature. As for AVRCP 1.3, we shall
       // return 0xFFFFFFFF. Since PTS enforces to check this part to comply with
       // the most updated spec.
-      mTrackChangedNotifyType = BTRC_NOTIFICATION_TYPE_INTERIM;
+      mTrackChangedNotifyType = AVRCP_NTF_INTERIM;
       // needs to convert to network big endian format since track stores
       // as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1).
       for (int index = 0; index < BTRC_UID_SIZE; ++index) {
         // We cannot easily check if a track is selected, so whenever A2DP is
         // streaming, we assume a track is selected.
         if (mSinkState == BluetoothA2dpManager::SinkState::SINK_PLAYING) {
-          param.track[index] = 0x0;
+          param.mTrack[index] = 0x0;
         } else {
-          param.track[index] = 0xFF;
+          param.mTrack[index] = 0xFF;
         }
       }
       break;
-    case BTRC_EVT_PLAY_POS_CHANGED:
+    case AVRCP_EVENT_PLAY_POS_CHANGED:
       // If no track is selected, return 0xFFFFFFFF in the INTERIM response
-      mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_INTERIM;
+      mPlayPosChangedNotifyType = AVRCP_NTF_INTERIM;
       if (mSinkState == BluetoothA2dpManager::SinkState::SINK_PLAYING) {
-        param.song_pos = mPosition;
+        param.mSongPos = mPosition;
       } else {
-        param.song_pos = 0xFFFFFFFF;
+        param.mSongPos = 0xFFFFFFFF;
       }
       mPlaybackInterval = aParam;
       break;
     default:
       break;
   }
 
-  sBtAvrcpInterface->RegisterNotificationRsp((btrc_event_id_t)aEventId,
-                                              BTRC_NOTIFICATION_TYPE_INTERIM,
-                                              &param, nullptr);
+  sBtAvrcpInterface->RegisterNotificationRsp(aEvent, AVRCP_NTF_INTERIM,
+                                             param, nullptr);
 #endif
 }
 
 void
 BluetoothA2dpManager::GetAlbum(nsAString& aAlbum)
 {
   aAlbum.Assign(mAlbum);
 }
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
@@ -47,17 +47,17 @@ public:
                       const nsAString& aArtist,
                       const nsAString& aAlbum,
                       uint64_t aMediaNumber,
                       uint64_t aTotalMediaCount,
                       uint32_t aDuration);
   void UpdatePlayStatus(uint32_t aDuration,
                         uint32_t aPosition,
                         ControlPlayStatus aPlayStatus);
-  void UpdateRegisterNotification(int aEventId, int aParam);
+  void UpdateRegisterNotification(BluetoothAvrcpEvent aEvent, uint32_t aParam);
   void GetAlbum(nsAString& aAlbum);
   uint32_t GetDuration();
   ControlPlayStatus GetPlayStatus();
   uint32_t GetPosition();
   uint64_t GetMediaNumber();
   uint64_t GetTotalMediaNumber();
   void GetTitle(nsAString& aTitle);
   void GetArtist(nsAString& aArtist);
@@ -100,16 +100,16 @@ private:
    * 1. The initial response to this Notify command shall be an INTERIM
    * response with current status.
    * 2. The following response shall be a CHANGED response with the updated
    * status.
    * mPlayStatusChangedNotifType, mTrackChangedNotifType,
    * mPlayPosChangedNotifType represents current RegisterNotification
    * notification type.
    */
-  int mPlayStatusChangedNotifyType;
-  int mTrackChangedNotifyType;
-  int mPlayPosChangedNotifyType;
+  BluetoothAvrcpNotification mPlayStatusChangedNotifyType;
+  BluetoothAvrcpNotification mTrackChangedNotifyType;
+  BluetoothAvrcpNotification mPlayPosChangedNotifyType;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.cpp
@@ -350,16 +350,163 @@ Convert(BluetoothHandsfreeVolumeType aIn
   };
   if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sVolumeType[aIn];
   return NS_OK;
 }
 
+#if ANDROID_VERSION >= 18
+static nsresult
+Convert(ControlPlayStatus aIn, btrc_play_status_t& aOut)
+{
+  static const btrc_play_status_t sPlayStatus[] = {
+    [PLAYSTATUS_STOPPED] = BTRC_PLAYSTATE_STOPPED,
+    [PLAYSTATUS_PLAYING] = BTRC_PLAYSTATE_PLAYING,
+    [PLAYSTATUS_PAUSED] = BTRC_PLAYSTATE_PAUSED,
+    [PLAYSTATUS_FWD_SEEK] = BTRC_PLAYSTATE_FWD_SEEK,
+    [PLAYSTATUS_REV_SEEK] = BTRC_PLAYSTATE_REV_SEEK
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sPlayStatus)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sPlayStatus[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(enum BluetoothAvrcpPlayerAttribute aIn, btrc_player_attr_t& aOut)
+{
+  static const btrc_player_attr_t sPlayerAttr[] = {
+    [AVRCP_PLAYER_ATTRIBUTE_EQUALIZER] = BTRC_PLAYER_ATTR_EQUALIZER,
+    [AVRCP_PLAYER_ATTRIBUTE_REPEAT] = BTRC_PLAYER_ATTR_REPEAT,
+    [AVRCP_PLAYER_ATTRIBUTE_SHUFFLE] = BTRC_PLAYER_ATTR_SHUFFLE,
+    [AVRCP_PLAYER_ATTRIBUTE_SCAN] = BTRC_PLAYER_ATTR_SCAN
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sPlayerAttr[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(enum BluetoothAvrcpStatus aIn, btrc_status_t& aOut)
+{
+  static const btrc_status_t sStatus[] = {
+    [AVRCP_STATUS_BAD_COMMAND] = BTRC_STS_BAD_CMD,
+    [AVRCP_STATUS_BAD_PARAMETER] = BTRC_STS_BAD_PARAM,
+    [AVRCP_STATUS_NOT_FOUND] = BTRC_STS_NOT_FOUND,
+    [AVRCP_STATUS_INTERNAL_ERROR] = BTRC_STS_INTERNAL_ERR,
+    [AVRCP_STATUS_SUCCESS] = BTRC_STS_NO_ERROR
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sStatus)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sStatus[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(enum BluetoothAvrcpEvent aIn, btrc_event_id_t& aOut)
+{
+  static const btrc_event_id_t sEventId[] = {
+    [AVRCP_EVENT_PLAY_STATUS_CHANGED] = BTRC_EVT_PLAY_STATUS_CHANGED,
+    [AVRCP_EVENT_TRACK_CHANGE] = BTRC_EVT_TRACK_CHANGE,
+    [AVRCP_EVENT_TRACK_REACHED_END] = BTRC_EVT_TRACK_REACHED_END,
+    [AVRCP_EVENT_TRACK_REACHED_START] = BTRC_EVT_TRACK_REACHED_START,
+    [AVRCP_EVENT_PLAY_POS_CHANGED] = BTRC_EVT_PLAY_POS_CHANGED,
+    [AVRCP_EVENT_APP_SETTINGS_CHANGED] = BTRC_EVT_APP_SETTINGS_CHANGED
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sEventId)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sEventId[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(enum BluetoothAvrcpNotification aIn, btrc_notification_type_t& aOut)
+{
+  static const btrc_notification_type_t sNotificationType[] = {
+    [AVRCP_NTF_INTERIM] = BTRC_NOTIFICATION_TYPE_INTERIM,
+    [AVRCP_NTF_CHANGED] = BTRC_NOTIFICATION_TYPE_CHANGED
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sNotificationType)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sNotificationType[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(const BluetoothAvrcpElementAttribute& aIn, btrc_element_attr_val_t& aOut)
+{
+  const NS_ConvertUTF16toUTF8 value(aIn.mValue);
+  size_t len = std::min<size_t>(strlen(value.get()), sizeof(aOut.text) - 1);
+
+  memcpy(aOut.text, value.get(), len);
+  aOut.text[len] = '\0';
+  aOut.attr_id = aIn.mId;
+
+  return NS_OK;
+}
+
+#endif
+
+/* |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
+{
+  ConvertArray(const T* aData, unsigned long aLength)
+  : mData(aData)
+  , mLength(aLength)
+  { }
+
+  const T* mData;
+  unsigned long mLength;
+};
+
+/* This implementation of |Convert| converts the elements of an
+ * array one-by-one. The result data structures must have enough
+ * memory allocated.
+ */
+template<typename Tin, typename Tout>
+static nsresult
+Convert(const ConvertArray<Tin>& aIn, Tout& aOut)
+{
+  for (unsigned long i = 0; i < aIn.mLength; ++i) {
+    nsresult rv = Convert(aIn.mData[i], aOut[i]);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
+/* This implementation of |Convert| is a helper that automatically
+ * allocates enough memory to hold the conversion results. The
+ * actual conversion is performed by the array-conversion helper
+ * above.
+ */
+template<typename Tin, typename Tout>
+static nsresult
+Convert(const ConvertArray<Tin>& aIn, nsAutoArrayPtr<Tout>& aOut)
+{
+  aOut = new Tout[aIn.mLength];
+  Tout* out = aOut.get();
+
+  return Convert<Tin, Tout*>(aIn, out);
+}
+
 //
 // Result handling
 //
 
 template <typename Obj, typename Res>
 class BluetoothInterfaceRunnable0 : public nsRunnable
 {
 public:
@@ -1485,34 +1632,49 @@ BluetoothAvrcpInterface::Cleanup(Bluetoo
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Cleanup,
                                  BT_STATUS_SUCCESS);
   }
 }
 
 void
-BluetoothAvrcpInterface::GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
+BluetoothAvrcpInterface::GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
                                           uint32_t aSongLen, uint32_t aSongPos,
                                           BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->get_play_status_rsp(aPlayStatus, aSongLen,
-                                                       aSongPos);
+  bt_status_t status;
+  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;
+  }
+
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayStatusRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::ListPlayerAppAttrRsp(
-  int aNumAttr, btrc_player_attr_t* aPAttrs,
+  int aNumAttr, const BluetoothAvrcpPlayerAttribute* aPAttrs,
   BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->list_player_app_attr_rsp(aNumAttr, aPAttrs);
+  bt_status_t status;
+  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;
+  }
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::ListPlayerAppAttrRsp, status);
   }
 }
 
 void
@@ -1524,84 +1686,174 @@ BluetoothAvrcpInterface::ListPlayerAppVa
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::ListPlayerAppValueRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayerAppValueRsp(
-  btrc_player_settings_t* aPVals, BluetoothAvrcpResultHandler* aRes)
+  uint8_t aNumAttrs, const uint8_t* aIds, const uint8_t* aValues,
+  BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->get_player_app_value_rsp(aPVals);
+  bt_status_t status;
+  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;
+  }
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayerAppAttrTextRsp(
-  int aNumAttr, btrc_player_setting_text_t* aPAttrs,
+  int aNumAttr, const uint8_t* aIds, const char** aTexts,
   BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->get_player_app_attr_text_rsp(aNumAttr,
-                                                                aPAttrs);
+  bt_status_t status;
+  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;
+  }
+
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayerAppAttrTextRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::GetPlayerAppValueTextRsp(
-  int aNumVal, btrc_player_setting_text_t* aPVals,
+  int aNumVal, const uint8_t* aIds, const char** aTexts,
   BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->get_player_app_value_text_rsp(aNumVal,
-                                                                 aPVals);
+  bt_status_t status;
+  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;
+  }
+
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetPlayerAppValueTextRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::GetElementAttrRsp(
-  uint8_t aNumAttr, btrc_element_attr_val_t* aPAttrs,
+  uint8_t aNumAttr, const BluetoothAvrcpElementAttribute* aAttrs,
   BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->get_element_attr_rsp(aNumAttr, aPAttrs);
+  bt_status_t status;
+  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;
+  }
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::GetElementAttrRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::SetPlayerAppValueRsp(
-  btrc_status_t aRspStatus, BluetoothAvrcpResultHandler* aRes)
+  BluetoothAvrcpStatus aRspStatus, BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->set_player_app_value_rsp(aRspStatus);
+  bt_status_t status;
+  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;
+  }
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::SetPlayerAppValueRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::RegisterNotificationRsp(
-  btrc_event_id_t aEventId, btrc_notification_type_t aType,
-  btrc_register_notification_t* aPParam, BluetoothAvrcpResultHandler* aRes)
+  BluetoothAvrcpEvent aEvent, BluetoothAvrcpNotification aType,
+  const BluetoothAvrcpNotificationParam& aParam,
+  BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->register_notification_rsp(aEventId, aType,
-                                                             aPParam);
+  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;
+    case AVRCP_EVENT_TRACK_CHANGE:
+      MOZ_ASSERT(sizeof(aParam.mTrack) == sizeof(param.track));
+      memcpy(param.track, aParam.mTrack, sizeof(param.track));
+      rv = NS_OK;
+      break;
+    case AVRCP_EVENT_TRACK_REACHED_END:
+      NS_NOTREACHED("Unknown conversion");
+      rv = NS_ERROR_ILLEGAL_VALUE;
+      break;
+    case AVRCP_EVENT_TRACK_REACHED_START:
+      NS_NOTREACHED("Unknown conversion");
+      rv = NS_ERROR_ILLEGAL_VALUE;
+      break;
+    case AVRCP_EVENT_PLAY_POS_CHANGED:
+      param.song_pos = aParam.mSongPos;
+      rv = NS_OK;
+      break;
+    case AVRCP_EVENT_APP_SETTINGS_CHANGED:
+      NS_NOTREACHED("Unknown conversion");
+      rv = NS_ERROR_ILLEGAL_VALUE;
+      break;
+    default:
+      NS_NOTREACHED("Unknown conversion");
+      rv = NS_ERROR_ILLEGAL_VALUE;
+      break;
+  }
+
+  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;
+  }
+
   if (aRes) {
     DispatchBluetoothAvrcpResult(
       aRes, &BluetoothAvrcpResultHandler::RegisterNotificationRsp, status);
   }
 }
 
 void
 BluetoothAvrcpInterface::SetVolume(uint8_t aVolume,
--- a/dom/bluetooth/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.h
@@ -271,43 +271,49 @@ class BluetoothAvrcpInterface
 #if ANDROID_VERSION >= 18
 public:
   friend class BluetoothInterface;
 
   void Init(btrc_callbacks_t* aCallbacks,
             BluetoothAvrcpResultHandler* aRes);
   void Cleanup(BluetoothAvrcpResultHandler* aRes);
 
-  void GetPlayStatusRsp(btrc_play_status_t aPlayStatus,
+  void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
                         uint32_t aSongLen, uint32_t aSongPos,
                         BluetoothAvrcpResultHandler* aRes);
 
-  void ListPlayerAppAttrRsp(int aNumAttr, btrc_player_attr_t* aPAttrs,
+  void ListPlayerAppAttrRsp(int aNumAttr,
+                            const BluetoothAvrcpPlayerAttribute* aPAttrs,
                             BluetoothAvrcpResultHandler* aRes);
   void ListPlayerAppValueRsp(int aNumVal, uint8_t* aPVals,
                              BluetoothAvrcpResultHandler* aRes);
 
-  void GetPlayerAppValueRsp(btrc_player_settings_t* aPVals,
+  /* TODO: redesign this interface once we actually use it */
+  void GetPlayerAppValueRsp(uint8_t aNumAttrs,
+                            const uint8_t* aIds, const uint8_t* aValues,
                             BluetoothAvrcpResultHandler* aRes);
+  /* TODO: redesign this interface once we actually use it */
   void GetPlayerAppAttrTextRsp(int aNumAttr,
-                               btrc_player_setting_text_t* aPAttrs,
+                               const uint8_t* aIds, const char** aTexts,
                                BluetoothAvrcpResultHandler* aRes);
+  /* TODO: redesign this interface once we actually use it */
   void GetPlayerAppValueTextRsp(int aNumVal,
-                                btrc_player_setting_text_t* aPVals,
+                                const uint8_t* aIds, const char** aTexts,
                                 BluetoothAvrcpResultHandler* aRes);
 
-  void GetElementAttrRsp(uint8_t aNumAttr, btrc_element_attr_val_t* aPAttrs,
+  void GetElementAttrRsp(uint8_t aNumAttr,
+                         const BluetoothAvrcpElementAttribute* aAttr,
                          BluetoothAvrcpResultHandler* aRes);
 
-  void SetPlayerAppValueRsp(btrc_status_t aRspStatus,
+  void SetPlayerAppValueRsp(BluetoothAvrcpStatus aRspStatus,
                             BluetoothAvrcpResultHandler* aRes);
 
-  void RegisterNotificationRsp(btrc_event_id_t aEventId,
-                               btrc_notification_type_t aType,
-                               btrc_register_notification_t* aPParam,
+  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();