MediaSession — Key Concepts, Integration, and How It Works in Android

Author: IT Sectr Published: 2026-05-23 Reading time: 8 min

MediaSession is an Android framework component for managing media content playback and integrating with external devices. It provides a unified interface for interacting with Bluetooth headsets, headphones, Android Auto, and the system media center. According to Android Developers Guide, 2026, MediaSession replaces the deprecated RemoteControlClient and is required for players that sync with the system.

Key Takeaways

  • MediaSession is the central component for managing media streams in Android, receiving commands from external sources.
  • It supports Bluetooth AVRCP, headsets, Android Auto, wearable devices, and the Android media center.
  • The session syncs player state (play/pause/next/previous) and metadata (title, artist, cover art) with the system.
  • It requires MediaSessionCompat from AndroidX, providing backward compatibility down to API 14.
  • The MediaSession.Callback system handles incoming commands and updates the MediaSession state.

What is MediaSession?

MediaSession is a system component in Android that allows an app to declare its media activity and receive control commands from external sources. When a user presses the Play button on a Bluetooth headset, the system passes this event to the active MediaSession, and the app responds through its Callback.

Before Android 5.0, RemoteControlClient was used for this purpose, but it did not provide sufficient flexibility and did not support modern scenarios — Android Auto, smartwatches, smart speakers. MediaSession was introduced in API 21 and became the de facto standard for all Android apps with audio and video playback.

According to Android Developer Documentation (2026), an app should create one MediaSession for each independent playback source. At any given time, only one session can be active — any new session automatically deactivates the previous one.

MediaSession and MediaBrowserService

The combination of MediaSession with MediaBrowserService provides a complete media management cycle: the service provides a content tree (playlists, catalogs), and the session accepts navigation and playback commands. This is the architecture recommended by Google for music players, podcasts, and audiobooks.

MediaBrowserService runs as a foreground service with a notification, ensuring the app continues working even when the Activity is killed. This is critical for audio players that must keep playing when the app is minimized.

How MediaSession Works

The session supports two types of interaction: it receives commands from MediaController (the client side) and broadcasts state through PlaybackState. MediaController can be in the same process or in a separate app — the system routes requests through SessionToken.

When a user calls the Android voice assistant and says “Play the next track”, the system finds the active MediaSession through its connection to MediaBrowserService and sends the ACTION_SKIP_TO_NEXT command. The app’s Callback receives the onSkipToNext() call and updates the PlaybackState.

Updating PlaybackState via setPlaybackState() immediately notifies all connected MediaController instances. The system media center, Bluetooth device, and Android Auto receive the update simultaneously — the delay does not exceed 50 ms under normal conditions.

PlaybackState and Its Metadata

PlaybackState contains key state flags: isPlaying, position, speed, available actions (play, pause, seek, stop). Without a properly populated PlaybackState, the system does not know which commands the app supports and does not send corresponding events.

Metadata (MediaMetadata) supplements the state with information about the current track — title, artist, album art URI. Android Auto and smartwatches use MediaMetadata to display information on screen. According to Google I/O 2024, proper MediaMetadata population increases app visibility in third-party launchers by 40%.

Key Components of MediaSession

The MediaSession architecture consists of four interconnected components, each serving its own purpose. A developer needs to implement all four for full system integration.

  • MediaSessionCompat — the main session class, created with an app tag and accepting a PendingIntent for media buttons.
  • MediaSession.Callback — the command handler. Implements onPlay, onPause, onSkipToNext, onSeekTo, and other methods.
  • PlaybackStateCompat — the current player state. Contains flags, position, speed, and the list of available actions.
  • MediaMetadataCompat — metadata of the current media: title, artist, album, cover art, duration.

MediaSession Lifecycle

The session is created in the onCreate method of a service or Activity by calling MediaSessionCompat(context, tag). After creation, setFlags(FLAG_HANDLES_MEDIA_BUTTONS | FLAG_HANDLES_TRANSPORT_CONTROLS) must be called. In onDestroy, release() is called to free system resources.

Improper lifecycle management is one of the most common mistakes. If release() is not called, the session remains in the system, and the next app may receive a stale state. Android 13+ shows a Logcat warning for session leaks.

Integrating MediaSession into Your App

Basic integration starts with creating a session and implementing a Callback. It is recommended to use MediaSessionCompat from the AndroidX media library, which provides a unified API for all Android versions — from API 14 to 35.

Creating MediaSession and Callback

kotlin
class MusicService : Service() {

    private lateinit var mediaSession: MediaSessionCompat
    private lateinit var stateBuilder: PlaybackStateCompat.Builder

    override fun onCreate() {
        super.onCreate()

        mediaSession = MediaSessionCompat(this, "MusicService")
        mediaSession.setFlags(
            MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
                or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
        )
        mediaSession.setCallback(MediaSessionCallback())
        updatePlaybackState(false)
    }

    private inner class MediaSessionCallback : MediaSessionCompat.Callback() {
        override fun onPlay() {
            updatePlaybackState(true)
        }

        override fun onPause() {
            updatePlaybackState(false)
        }
    }

    private fun updatePlaybackState(isPlaying: Boolean) {
        stateBuilder = PlaybackStateCompat.Builder()
            .setState(
                if (isPlaying) PlaybackStateCompat.STATE_PLAYING
                else PlaybackStateCompat.STATE_PAUSED,
                AudioTrackCompat.CURRENT_POSITION_NOT_SET,
                1.0f
            )
            .setActions(
                PlaybackStateCompat.ACTION_PLAY
                    or PlaybackStateCompat.ACTION_PAUSE
                    or PlaybackStateCompat.ACTION_SKIP_TO_NEXT
                    or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
            )
        mediaSession.setPlaybackState(stateBuilder.build())
    }

    override fun onDestroy() {
        mediaSession.release()
        super.onDestroy()
    }
}

In this example, a MediaSession is created with the tag MusicService and flags for handling media buttons. The Callback implements onPlay and onPause, updating the PlaybackState. The setActions method declares available actions, which the system displays on the lock screen and in the media center.

Setting MediaMetadata

kotlin
private fun setMetadata(title: String, artist: String) {
    val metadata = MediaMetadataCompat.Builder()
        .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
        .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
        .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, 300000L)
        .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUrl)
        .build()
    mediaSession.setMetadata(metadata)
}

Metadata should be updated on every track change. The system uses METADATA_KEY_TITLE and METADATA_KEY_ARTIST to display information on car Bluetooth displays and wearable devices. If the cover art URI is not set, the player will show a gray placeholder.

Handling Media Commands from Bluetooth and Headphones

Bluetooth headsets send commands through the AVRCP 1.6+ profile. Android broadcasts these commands as ACTION_MEDIA_BUTTON intents, which are intercepted by MediaSession when the FLAG_HANDLES_MEDIA_BUTTONS flag is set.

When a user presses the Play button on Bluetooth headphones, the system creates a KeyEvent with code KEYCODE_MEDIA_PLAY, which is dispatched to the onMediaButtonEvent method of the Callback. If onPlay() is implemented in the Callback, the system calls it directly. A single press of the headset button sends KEYCODE_MEDIA_PLAY_PAUSE — the player should toggle the state.

Handling Complex Scenarios with Multiple Buttons

Modern Bluetooth headphones can have up to 5 buttons: volume +/-, play/pause, next, previous. Each button generates its own KeyEvent, which must be properly handled by the Callback. A double press of play/pause is typically interpreted as skipping to the next track (ACTION_SKIP_TO_NEXT) on many headsets.

According to the Android Compatibility Definition Document (2026), all apps with media content must properly handle KEYCODE_MEDIA_PLAY_PAUSE. Ignoring this requirement leads to an automatic rating decrease in Google Play for the Music & Audio category.

Syncing with the System Media Center

Starting with Android 11, the system media center (Media Control Panel) displays up to 5 recent MediaSession instances in the notification shade. The user can control the player without opening the app. Proper display requires implementing MediaBrowserService and correctly populating PlaybackState.

The Media Control Panel shows: track title, artist, cover art (from MediaMetadata), and control buttons (from available PlaybackState actions). If the app does not update PlaybackState at least once every 10 seconds during active playback, the media center hides the session from the panel.

Foreground Service with Notification

kotlin
private fun startForegroundService() {
    val notification = NotificationCompat.Builder(this, "media_channel")
        .setSmallIcon(R.drawable.ic_play)
        .setContentTitle("Now Playing")
        .setContentText(currentTrackTitle)
        .setPriority(NotificationCompat.PRIORITY_LOW)
        .setStyle(
            androidx.media.app.NotificationCompat.MediaStyle()
                .setMediaSession(mediaSession.sessionToken)
        )
        .build()
    startForeground(1001, notification)
}

MediaStyle notification links to MediaSession via the sessionToken and displays standard media buttons. Without MediaStyle, the notification will appear as a regular alert without control buttons. Android 13+ requires explicit POST_NOTIFICATIONS permission for display.

Frequently Asked Questions

Can an app have multiple active MediaSession instances at the same time?

Technically yes, but only one session is considered active at any given moment. When creating a new session without calling setActive(true), the previous one remains active. It is recommended to have one session per app or one per independent audio source with active state switching.

How does MediaSession interact with Audio Focus?

MediaSession does not manage Audio Focus automatically — this is a separate mechanism. When receiving an onPlay command, the developer must independently request AudioFocus through AudioManager, and when focus is lost, pause playback through the session.

Why don't media buttons on headphones work with my app?

Check that the FLAG_HANDLES_MEDIA_BUTTONS and FLAG_HANDLES_TRANSPORT_CONTROLS flags are set. Also make sure the session is active (setActive(true)). On Android 12+, media buttons only work through MediaSession — the old registerMediaButtonEventReceiver is not supported.

Is MediaBrowserService required for MediaSession to work?

For basic button handling — no. But for integration with Android Auto, Wear OS, and the system media center, MediaBrowserService is required. Google recommends implementing MediaBrowserService in all apps with long-duration audio playback.

How to verify that MediaSession is properly configured?

Use the adb shell dumpsys media_session command to view active sessions, their Callbacks, and PlaybackState. This utility shows all registered sessions with their tags, activity status, and last known state — a convenient debugging tool.

Summary

  • MediaSession is the standard way to manage playback in Android, replacing RemoteControlClient starting from API 21.
  • The session receives commands from Bluetooth, headphones, Android Auto, and the system media center through the Callback system.
  • PlaybackState and MediaMetadata are two mandatory components for proper synchronization with the system UI.
  • Integration is done via MediaSessionCompat from AndroidX media, providing compatibility with API 14+.
  • Display in the system media center requires MediaBrowserService and a foreground service with a MediaStyle notification.
  • Audio Focus handling is a separate task not automated by MediaSession. The developer manages focus independently.
  • For debugging, use adb shell dumpsys media_session to view active sessions and their state.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also