Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0299274d authored by Étienne Ruffieux (xWF)'s avatar Étienne Ruffieux (xWF) Committed by Gerrit Code Review
Browse files

Merge "Implement AVRCP's set addressed player" into main

parents 69fe1730 3713e8af
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ static uint16_t getCurrentPlayerId();
static std::vector<MediaPlayerInfo> getMediaPlayerList();
using SetBrowsedPlayerCb = MediaInterface::SetBrowsedPlayerCallback;
static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb);
static uint16_t setAddressedPlayer(uint16_t player_id);
using GetFolderItemsCb = MediaInterface::FolderItemsCallback;
static void getFolderItems(uint16_t player_id, std::string media_id, GetFolderItemsCb cb);
static void playItem(uint16_t player_id, bool now_playing, std::string media_id);
@@ -146,10 +147,19 @@ public:
    getFolderItems(player_id, media_id, folder_cb);
  }

  void GetAddressedPlayer(GetAddressedPlayerCallback cb) override {
    uint16_t current_player = getCurrentPlayerId();
    cb.Run(current_player);
  }

  void SetBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCallback browse_cb) override {
    setBrowsedPlayer(player_id, browse_cb);
  }

  void SetAddressedPlayer(uint16_t player_id, SetAddressedPlayerCallback addressed_cb) override {
    addressed_cb.Run(setAddressedPlayer(player_id));
  }

  void RegisterUpdateCallback(MediaCallbacks* callback) override {
    // TODO(apanicke): Allow multiple registrations in the future
    mServiceCallbacks = callback;
@@ -209,6 +219,7 @@ static jmethodID method_getCurrentMediaId;
static jmethodID method_getNowPlayingList;

static jmethodID method_setBrowsedPlayer;
static jmethodID method_setAddressedPlayer;
static jmethodID method_getCurrentPlayerId;
static jmethodID method_getMediaPlayerList;
static jmethodID method_getFolderItemsRequest;
@@ -695,6 +706,19 @@ static void setBrowsedPlayerResponseNative(JNIEnv* env, jobject /* object */, ji
  set_browsed_player_cb.Run(success == JNI_TRUE, root, num_items);
}

static uint16_t setAddressedPlayer(uint16_t player_id) {
  log::debug("");
  std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
  CallbackEnv sCallbackEnv(__func__);
  if (!sCallbackEnv.valid() || !mJavaInterface) {
    return 0u;
  }

  jint new_player =
          sCallbackEnv->CallIntMethod(mJavaInterface, method_setAddressedPlayer, player_id);
  return static_cast<int>(new_player) & 0xFFFF;
}

static void getFolderItemsResponseNative(JNIEnv* env, jobject /* object */, jstring parent_id,
                                         jobject list) {
  log::debug("");
@@ -1065,6 +1089,7 @@ int register_com_android_bluetooth_avrcp_target(JNIEnv* env) {
          {"getCurrentPlayerId", "()I", &method_getCurrentPlayerId},
          {"getMediaPlayerList", "()Ljava/util/List;", &method_getMediaPlayerList},
          {"setBrowsedPlayer", "(I)V", &method_setBrowsedPlayer},
          {"setAddressedPlayer", "(I)I", &method_setAddressedPlayer},
          {"getFolderItemsRequest", "(ILjava/lang/String;)V", &method_getFolderItemsRequest},
          {"playItem", "(IZLjava/lang/String;)V", &method_playItem},
          {"setActiveDevice", "(Ljava/lang/String;)V", &method_setActiveDevice},
+59 −16
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ public class MediaPlayerList {
            Collections.synchronizedMap(new HashMap<Integer, MediaBrowserWrapper>());
    private int mActivePlayerId = NO_ACTIVE_PLAYER;
    private int mBrowsingPlayerId = NO_ACTIVE_PLAYER;
    private int mAddressedPlayerId = NO_ACTIVE_PLAYER;

    private MediaUpdateCallback mCallback;
    private boolean mAudioPlaybackIsActive = false;
@@ -329,7 +330,9 @@ public class MediaPlayerList {

    /** returns the current player ID. */
    public int getCurrentPlayerId() {
        if (Flags.browsingRefactor()) {
        if (Flags.setAddressedPlayer()) {
            return mAddressedPlayerId;
        } else if (Flags.browsingRefactor()) {
            return mBrowsingPlayerId;
        } else {
            return BLUETOOTH_PLAYER_ID;
@@ -350,7 +353,16 @@ public class MediaPlayerList {
        return mMediaPlayers.get(mActivePlayerId);
    }

    /** This is used to send passthrough command to media session */
    /** Returns the {@link #MediaPlayerWrapper} with ID matching {@link #mAddressedPlayerId}. */
    public MediaPlayerWrapper getAddressedPlayer() {
        return mMediaPlayers.get(mAddressedPlayerId);
    }

    /**
     * This is used to send passthrough command to media session
     *
     * <p>Note: This is used only by MCP, AVRCP uses AvrcpTargetService.
     */
    public void sendMediaKeyEvent(int key, boolean pushed) {
        if (mMediaSessionManager == null) {
            Log.d(TAG, "Bluetooth is turning off, ignore it");
@@ -363,8 +375,11 @@ public class MediaPlayerList {

    public void getPlayerRoot(int playerId, GetPlayerRootCallback cb) {
        if (Flags.browsingRefactor()) {
            if (!haveMediaBrowser(playerId)) {
                cb.run(playerId, false, "", 0);
                return;
            }
            mBrowsingPlayerId = playerId;
            if (haveMediaBrowser(playerId)) {
            MediaBrowserWrapper wrapper = mMediaBrowserWrappers.get(playerId);
            wrapper.getRootId(
                    (rootId) -> {
@@ -374,8 +389,6 @@ public class MediaPlayerList {
                                    cb.run(playerId, true, rootId, itemList.size());
                                });
                    });
                sendFolderUpdate(false, true, false);
            }
        } else {
            // Fix PTS AVRCP/TG/MCN/CB/BI-02-C
            if (Utils.isPtsTestMode()) {
@@ -398,6 +411,18 @@ public class MediaPlayerList {
        }
    }

    /** Sets which player the AV/C commands should be addressed to. */
    public int setAddressedPlayer(int playerId) {
        if (!Flags.setAddressedPlayer()) {
            return BLUETOOTH_PLAYER_ID;
        }
        if (mMediaPlayerIds.containsValue(playerId)) {
            mAddressedPlayerId = playerId;
            sendFolderUpdate(false, true, false);
        }
        return mAddressedPlayerId;
    }

    /** Returns a list valid browsable players. */
    public List<PlayerInfo> getMediaPlayerList() {
        List<PlayerInfo> ret = new ArrayList<PlayerInfo>();
@@ -564,8 +589,15 @@ public class MediaPlayerList {
        }

        long queueItemId = Long.parseLong(m.group(1));
        if (getActivePlayer() != null) {
            getActivePlayer().playItemFromQueue(queueItemId);

        MediaPlayerWrapper player;
        if (Flags.setAddressedPlayer()) {
            player = getAddressedPlayer();
        } else {
            player = getActivePlayer();
        }
        if (player != null) {
            player.playItemFromQueue(queueItemId);
        }
    }

@@ -894,7 +926,11 @@ public class MediaPlayerList {
        // tells us otherwise
        if (playerId == mActivePlayerId && playerId != NO_ACTIVE_PLAYER) {
            getActivePlayer().unregisterCallback();
            if (mAddressedPlayerId == mActivePlayerId) {
                mAddressedPlayerId = NO_ACTIVE_PLAYER;
            }
            mActivePlayerId = NO_ACTIVE_PLAYER;

            List<Metadata> queue = new ArrayList<Metadata>();
            queue.add(Util.empty_data());
            MediaData newData = new MediaData(Util.empty_data(), null, queue);
@@ -948,6 +984,13 @@ public class MediaPlayerList {

        if (Utils.isPtsTestMode()) {
            sendFolderUpdate(true, true, false);
        } else if (Flags.setAddressedPlayer()) {
            // If the new active player has been set by Addressed player key event
            // We don't send an addressed player update.
            if (mActivePlayerId != mAddressedPlayerId) {
                mAddressedPlayerId = mActivePlayerId;
                sendFolderUpdate(false, true, false);
            }
        }

        MediaData data = getActivePlayer().getCurrentMediaData();
+5 −0
Original line number Diff line number Diff line
@@ -192,6 +192,11 @@ public class AvrcpNativeInterface {
        setBrowsedPlayerResponseNative(playerId, success, rootId, numItems);
    }

    int setAddressedPlayer(int playerId) {
        d("setAddressedPlayer: playerId=" + playerId);
        return mAvrcpService.setAddressedPlayer(playerId);
    }

    void getFolderItemsRequest(int playerId, String mediaId) {
        d("getFolderItemsRequest: playerId=" + playerId + " mediaId=" + mediaId);
        mAvrcpService.getFolderItems(playerId, mediaId, (a, b) -> getFolderItemsResponse(a, b));
+22 −2
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.VisibleForTesting;

import java.util.List;
@@ -485,6 +486,11 @@ public class AvrcpTargetService extends ProfileService {
        mMediaPlayerList.getPlayerRoot(playerId, cb);
    }

    /** See {@link MediaPlayerList#setAddressedPlayer}. */
    int setAddressedPlayer(int playerId) {
        return mMediaPlayerList.setAddressedPlayer(playerId);
    }

    /** See {@link MediaPlayerList#getFolderItems}. */
    void getFolderItems(int playerId, String mediaId, MediaPlayerList.GetFolderItemsCallback cb) {
        mMediaPlayerList.getFolderItems(playerId, mediaId, cb);
@@ -499,8 +505,22 @@ public class AvrcpTargetService extends ProfileService {

    /** Informs {@link AudioManager} of an incoming key event from a remote device. */
    void sendMediaKeyEvent(int key, boolean pushed) {
        MediaPlayerWrapper activePlayer = mMediaPlayerList.getActivePlayer();
        if (Flags.setAddressedPlayer()) {
            MediaPlayerWrapper addressedPlayer = mMediaPlayerList.getAddressedPlayer();
            // A/V controls should be sent to the addressed player.
            // We don't have a way to set a media player as the active session so we
            // keep the active device playing until we receive a PLAY event for the
            // addressed player. Other events will still be broadcasted to active player.
            if (addressedPlayer != null
                    && KeyEvent.KEYCODE_MEDIA_PLAY == AvrcpPassthrough.toKeyCode(key)
                    && activePlayer != addressedPlayer) {
                addressedPlayer.playCurrent();
                return;
            }
        }

        BluetoothDevice activeDevice = getA2dpActiveDevice();
        MediaPlayerWrapper player = mMediaPlayerList.getActivePlayer();
        mMediaKeyEventLogger.logd(
                TAG,
                "sendMediaKeyEvent:"
@@ -511,7 +531,7 @@ public class AvrcpTargetService extends ProfileService {
                        + " pushed="
                        + pushed
                        + " to "
                        + (player == null ? null : player.getPackageName()));
                        + (activePlayer == null ? null : activePlayer.getPackageName()));
        int action = pushed ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP;
        KeyEvent event = new KeyEvent(action, AvrcpPassthrough.toKeyCode(key));
        mAudioManager.dispatchMediaKeyEvent(event);
+1 −1
Original line number Diff line number Diff line
@@ -240,7 +240,7 @@ class MediaPlayerBrowserService : MediaBrowserServiceCompat() {
            result.sendResult(mediaIdToChildren[NOW_PLAYING_PREFIX])
        } else {
            Log.i(TAG, "onloadchildren inside else")
            result.sendResult(null)
            result.sendResult(mediaIdToChildren[ROOT])
        }
    }

Loading