2

I want to know what song is currently played on my Android phone. In the past, the solution would be to add an IntentFilter but now the solution should be based on MediaSession. Each media app posts its MediaSession. I have a the following listener:

private val mSessionsChangedListener =
    MediaSessionManager.OnActiveSessionsChangedListener { list: List<MediaController>? ->
        //...here
    }

This listener fires every time a change in the active sessions occur. Then I can utilise MediaMetadata in order to grab the info about the currently playing song. In case there is only 1 active MediaSession, that works. However in case there are multiple apps with active sessions, I'm not sure how to determine which one of the List<MediaController> is actually playing.

I tried checking the playbackState like this:

    list.forEach {
        if (it.playbackState?.state == PlaybackState.STATE_PLAYING) {
            currentMediaController = it
        }
    } 

But when switching between 2 media apps, the playbackState is not updated yet when this listener is triggered.

What is the correct way of determining which MediaController is actually playing?

Thanks!

Ziad Halabi
  • 964
  • 11
  • 31

2 Answers2

1

To determine which MediaController is currently playing when there are multiple active sessions, you can use the MediaController.getPlaybackState() method to get the current playback state of each MediaController. Here's an example code snippet that demonstrates how to do this:

private val mSessionsChangedListener =
    MediaSessionManager.OnActiveSessionsChangedListener { list: List<MediaController>? ->
        list?.forEach { mediaController ->
            val playbackState = mediaController.playbackState
            if (playbackState?.state == PlaybackState.STATE_PLAYING || 
                playbackState?.state == PlaybackState.STATE_BUFFERING) {
                val mediaMetadata = mediaController.metadata
                // Use the metadata to get information about the currently playing song
                //
            }
        }
    }
Daniel Ngandu
  • 81
  • 1
  • 2
  • 11
  • Thanks Daniel for your answer. That solution is not complete unfortunately. When playback switches between different media apps, their "active" state does not change and this listener is not triggered. – Ziad Halabi Apr 12 '23 at 06:47
0

I think maybe something like the following might work:

private var currentMediaController: MediaController? = null

private val mSessionsChangedListener =
    MediaSessionManager.OnActiveSessionsChangedListener { list: List<MediaController>? ->
        var latestPlaybackState: PlaybackState? = null
        var latestMediaController: MediaController? = null

        list?.forEach { mediaController ->
            val playbackState = mediaController.playbackState
            if (playbackState != null) {
                if (latestPlaybackState == null || playbackState.lastPositionUpdateTime > latestPlaybackState.lastPositionUpdateTime) {
                    if (playbackState.state == PlaybackState.STATE_PLAYING) {
                        latestPlaybackState = playbackState
                        latestMediaController = mediaController
                    }
                }
            }
        }

        currentMediaController = latestMediaController
        // Now you have the MediaController that is currently playing.
        // You can get the playback state using currentMediaController?.playbackState.
    }

This code iterates over all the MediaControllers in the list and checks their PlaybackState. If a MediaController has a PlaybackState that is newer than the previous PlaybackState seen, it becomes the new "latest" PlaybackState, and the corresponding MediaController becomes the new latestMediaController. If the PlaybackState indicates that the media is playing, latestMediaController is updated accordingly.

Note that this code assumes that each MediaController has a unique PlaybackState object. If two MediaControllers have the same PlaybackState object (i.e., they are both playing the same media), this code may not work correctly. In that case, you could use other criteria (such as the package name of the MediaController) to determine which one is actually playing. cg

Patrick Nomad
  • 61
  • 1
  • 6
  • Thank you Patrick for your answer. It's an interesting approach to rely on the lastPositionUpdateTime but I'm not sure how reliable that is. Also, the main problem still persist in this solution. If you have 3 current active media sessions and user is simply switching between them, the OnActiveSessionsChangedListener is not triggered if the user pauses a song X from session A and resume song Y from session B. – Ziad Halabi Mar 29 '23 at 16:36