Zygote
Media, audio & cameraintermediate

Media sessions and playback

A media session is how an app tells the system what it is playing, so the lock screen, the notification shade, the car and the headphones can all control it without knowing anything about the app.

12 minAPI 1–37 · 17interactivequizverified 2026-10-27

Playback is not an app-local concern. The moment audio continues while the screen is off, the system needs to know what is playing, who is playing it, and what the user is allowed to do about it. That contract is the media session.

TL;DR#

  • A MediaSession publishes metadata (title, artist, artwork) and playback state to the system.
  • The system's media controls — lock screen, shade, Quick Settings, Bluetooth, Android Auto — are consumers of that session. They do not talk to your app directly.
  • Media buttons (headset, car, Bluetooth) are routed by the system to the active session.
  • Since Android 13, playback from the background needs a foreground service with a media-playback type and a valid POST_NOTIFICATIONS grant for the notification to be visible.
  • Media3 packages session, player and UI into one library, which is now the recommended stack.

Mental model#

Think of a radio station and a listings magazine.

The station (your app) broadcasts. The listings magazine (the media session) publishes what is on, who made it, and whether it is playing or paused. Every consumer — the car radio, the newspaper, the website — reads the listing rather than calling the station.

Media buttons are the analogue of a remote control: they send "next" or "pause" to whichever station is currently the active one, without knowing its frequency.

Where the analogy breaks#

A listings magazine is read-only. A media session is bidirectional: the system sends commands back (play, pause, seek, skip), and the app sends state updates. It is closer to a shared document with a rigid schema than to a broadcast.

The big picture#

Loading diagram…
Text description of this diagram

A sequence diagram of a media button press. A headset or car emits a media key event, which the system's media session service routes to the active session rather than to every player. The session delivers the command to the player inside the app's MediaSessionService, which reports the new state back. The session publishes metadata and state to every surface that renders it: the notification, the lock screen, the car display and the Bluetooth device. The app's activity is not part of the loop, which is why playback survives the UI being destroyed.

The pieces:

PieceRole
MediaSessionpublishes metadata and playback state; receives commands
MediaControllera client handle the system (and other apps) uses to talk to the session
MediaSessionServicehosts the session in a service so it survives the UI
PlayerNotificationManager / Media3 notificationrenders the session as a notification
MediaButtonReceiverroutes hardware buttons to the active session

Deep dive#

Why it must be a service#

A session must outlive the activity. If playback is in an activity, rotating the phone or pressing back kills it. The session therefore lives in a MediaSessionService, and the activity connects to it with a MediaController.

That architecture is why "the music keeps playing when I leave the app" works, and why the app's UI can be recreated without interrupting playback. It is the same reason a Service exists at all.

The metadata contract#

Metadata is not decoration. It is what the system uses to:

  • draw the lock-screen controls,
  • show the correct title in the car,
  • match the session to a media browse tree,
  • and, on some surfaces, decide the artwork size.

Getting metadata wrong produces the familiar bug where the lock screen shows the previous track's artwork, or the car shows a truncated title. The system caches by session and by metadata version, so an app that updates state without updating metadata leaves stale values on screen.

Playback state and the action mask#

A PlaybackState is more than "playing" or "paused". It carries:

  • the state (playing, paused, buffering, error),
  • the position and playback speed,
  • the actions the app supports (play, pause, skip, seek, stop).

The action mask is how the system knows which buttons to draw. A session that does not declare seek gets no seek bar; one that declares skip-to-next but cannot actually skip produces a button that does nothing.

Media buttons and the active session#

Hardware buttons — headset play/pause, car steering-wheel controls, Bluetooth AVRCP — are delivered as media key events. The system routes them to the active session, which is normally the one that most recently started playing.

This is why two music apps can coexist without fighting: only one is active. It is also why a badly behaved app that grabs the session and never releases it can break the headset button for everyone.

Notifications, foreground services and Android 13#

The notification is how the user sees and controls playback. Since Android 13:

  • POST_NOTIFICATIONS is a runtime permission. A media notification without it is not shown, which means the lock-screen controls disappear too.
  • Playback from the background requires a foreground service with a media-playback type.
  • The notification must be a media-style notification to get the media layout.

Android 15 tightened the background-start rule further: an app that starts audio playback from the background without a valid foreground service can be stopped.1

The practical upshot: a media app's manifest declares the media playback foreground service type, and its code requests notification permission before starting playback. Skipping either produces an app that works in the foreground and mysteriously stops in the background.

Media3, and the end of hand-rolled sessions#

Media3 unifies ExoPlayer, MediaSession, MediaSessionService and the UI components into one library with a consistent API. It replaces the older split between the platform MediaSession and the separate ExoPlayer session extension.2

The architectural benefit is the same as AndroidX generally: the app owns the version of the media stack it uses, so behaviour does not depend on the device's platform version. For media apps, where codec and session behaviour differs between OEMs, that is worth a lot.

Output switching#

When the user unplugs headphones or connects a car, the audio route changes. The session keeps playing; the system re-routes. The app can observe the change and decide whether to pause — the near-universal choice is to pause when headphones are unplugged, because continuing on the speaker is a privacy problem.

Casting is the other form of output switching: the session moves from the phone to a remote device, and the phone becomes a remote control. Media3's session APIs support this through a MediaRouteSelector-style flow, with the session surviving the transfer.

The session lifecycle, and what the system remembers#

A session is not a singleton for the life of the app. It is created when playback becomes possible, and it can be released when the app has nothing to play. The system keeps a small amount of state across that boundary:

  • The active session — which app currently owns the media buttons.
  • The last known metadata — so the lock screen is not blank for a moment when playback resumes.
  • The resumption stack — on some surfaces, the last app that played audio may be resumed by a headset button even after it has been stopped.

That last point is the reason the active session is a scarce resource. An app that creates a session and immediately marks itself playing can take the buttons away from an app the user is actually listening to. The correct behaviour is to become active when playback genuinely starts, and to deactivate when it stops.

Testing playback without a device in your hand#

Playback bugs are hard to reproduce on a desk. Three techniques cover most of them:

  • Simulate media buttons with adb shell media dispatch play, which uses the same path as a headset button and exposes routing problems immediately.
  • Change the route by connecting and disconnecting a Bluetooth device, and verify that the session pauses rather than continuing on the speaker.
  • Kill the UI with am force-stop on the activity's task while playback continues, to prove the service really owns the session rather than the activity.

Each of those maps to one of the architectural claims on this page: buttons are routed, routes change, and the session outlives the UI.

How it evolved#

Interface changes16 releases
APIVersionWhat changed
11.0
  • Pull-down notification shade
  • Home screen with widgets
31.5 Cupcake
  • Home screen widgets and folders
92.3 Gingerbread
  • New UI with dark theme and green accents
113.0 Honeycomb
  • The Holo design language arrives
123.1 Honeycomb
  • Resizable widgets
164.1 Jelly Bean
  • Project Butter: vsync-driven, smooth UI
  • Expandable notifications
204.4W KitKat (Wear)
  • Voice-driven card UI
215.0 Lollipop
  • Material Design
  • Notifications on the lock screen
247.0 Nougat
  • Quick Settings tiles
  • Direct Reply in notifications
268.0 Oreo
  • Notification channels
289 Pie
  • Dark theme groundwork
2910
  • System-wide dark theme
3011
  • Conversation notifications and bubbles
  • Media controls in Quick Settings
3112
  • Material You dynamic colour
3313 Tiramisu
  • Themed app icons
  • Runtime notification permission
3616 Baklava
  • Material 3 Expressive
  • Live Updates notifications
2010–2014RemoteControlClientLock-screen controls via a client object attached to audio focus.API 8
2014 →MediaSessionA proper session with metadata, state and transport controls.API 21
2020 →Session in a serviceSessions move into a service that outlives the UI.
2022 →Media3Player, session and UI packaged as one Jetpack library.API 33

Under the hood#

Curiosity corner#

  • The lock screen is a client, not a feature. It renders whatever the active session publishes, which is why a badly built session looks wrong everywhere at once.
  • Headphone buttons are media keys. A single-button headset sends play/pause; a three-button one sends next/previous as double and triple clicks, decoded by the system.
  • A session can be browsed without playing. Media browse trees let a car show an app's library before anything is playing.

Try it#

See the active session

adb shell dumpsys media_session | head -60 adb shell cmd media_session volume --stream 3 --get adb shell media dispatch play

Example output
Active Sessions:
com.example.music / MediaSessionService
state: PLAYING
metadata: Example Track / Example Artist
actions: PLAY_PAUSE SKIP_NEXT SEEK_TO

media dispatch sends a media key event, which is the same path a headset button takes. If the session responds, the routing is correct.

Check yourself#

Check yourself

1 / 12

What are the four stages the media framework separates?

0 answered · 0 correct

Sources#

Sources

Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.

  1. docsBehavior changes: Apps targeting Android 15 or higherdeveloper.android.comaccessed 2026-10-27↩
  2. docsMedia3 overviewdeveloper.android.comaccessed 2026-10-27↩
  3. docsNotifications overviewdeveloper.android.comaccessed 2026-10-27↩
  4. docsBehavior changes: Apps targeting Android 13 or higherdeveloper.android.comaccessed 2026-10-27↩
  5. docsFirebase Cloud Messagingfirebase.google.comaccessed 2026-10-27↩