Loading android/app/jni/com_android_bluetooth_avrcp_target.cpp +25 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(""); Loading Loading @@ -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}, Loading android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java +59 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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"); Loading @@ -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) -> { Loading @@ -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()) { Loading @@ -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>(); Loading Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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(); Loading android/app/src/com/android/bluetooth/avrcp/AvrcpNativeInterface.java +5 −0 Original line number Diff line number Diff line Loading @@ -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)); Loading android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java +22 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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:" Loading @@ -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); Loading android/pandora/server/src/MediaPlayerBrowserService.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
android/app/jni/com_android_bluetooth_avrcp_target.cpp +25 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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(""); Loading Loading @@ -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}, Loading
android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java +59 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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"); Loading @@ -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) -> { Loading @@ -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()) { Loading @@ -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>(); Loading Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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(); Loading
android/app/src/com/android/bluetooth/avrcp/AvrcpNativeInterface.java +5 −0 Original line number Diff line number Diff line Loading @@ -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)); Loading
android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java +22 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -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:" Loading @@ -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); Loading
android/pandora/server/src/MediaPlayerBrowserService.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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