Interface: RemotePlayback
Defined in: packages/media-session/src/types.ts:99
"Playback is coming out of another device right now, and here is that device's volume."
Published with MediaServiceApi.setRemotePlayback while some remote backend owns the audio — a Cast receiver, a UPnP renderer, a multi-room protocol — and cleared when the phone takes it back. Nothing here is cast-specific: this package works with any player and any output.
Properties
holdLocalAudioSlot?
optional holdLocalAudioSlot?: boolean;
Defined in: packages/media-session/src/types.ts:171
Android only: hold a silent local audio output for as long as this remote playback is published, so the app keeps the platform's "last played locally" slot.
Default
false
What it is for
With the screen off, MediaSessionService discards the session it just
chose — and drops the key entirely — when the caller's uid was the last
to play local audio (b/275185436). The caller with the screen off is
PhoneWindowManager, uid 1000, so any system sound (a notification, a
ringtone) takes the volume keys away from a remote session. It is sticky,
not momentary: the platform's list never evicts its head entry, and an app
whose audio is remote never plays locally to displace it.
The one documented escape: when the head uid goes inactive, the platform promotes the first still-active uid to the head. An app holding a silent local output is that uid, so it reclaims the slot as soon as the interfering sound ends. See the package README, "Two platform conditions".
What it costs, and why it is off by default
A real audio output stays open for the whole remote session, which keeps
the audio HAL awake — measurable battery, for a feature the user only
notices when they reach for the rocker. It also makes
AudioSystem.isStreamActive(STREAM_MUSIC) true, which changes the
failure mode rather than only removing one: if the session is ever
discarded for the other reason (playback not PLAYING), the key now moves
the phone's volume instead of doing nothing.
So it is opt-in. Turn it on when lock-screen volume over a remote device matters more than idle power — a cast-heavy music app — and leave it off otherwise. It takes no audio focus and does not touch your player.
No-op on iOS, where the hardware buttons cannot be taken over at all.
muted?
optional muted?: boolean;
Defined in: packages/media-session/src/types.ts:109
Whether the remote device is muted.
Default
false
routingControllerId?
optional routingControllerId?: string;
Defined in: packages/media-session/src/types.ts:136
Android only: the MediaRouter2 routing-controller id of the route the
audio is on, when the backend exposes one.
Lets the system output switcher tie the volume slider it draws to the route that is playing. A refinement — omit it and everything else still works.
steps?
optional steps?: number;
Defined in: packages/media-session/src/types.ts:119
How many notches a hardware volume key press moves through, silent to full.
Default
20
20 is media3's own choice for a Cast receiver
(RemoteCastPlayer.MAX_VOLUME, media3 1.11.0), so an app that says nothing
gets the step size Android users already feel from every other cast-enabled
app.
volume
volume: number;
Defined in: packages/media-session/src/types.ts:107
The remote device's current volume, 0..1.
The same scale an app's own slider uses, and the one every remote backend already speaks. Quantising it into the platform's integer notches is this package's job — see steps.
volumeControl?
optional volumeControl?: RemoteVolumeControl;
Defined in: packages/media-session/src/types.ts:128
How much of that volume the backend can actually drive.
Default
'absolute'
'absolute' (a level can be set and nudged) is what a Cast receiver, a
UPnP renderer and essentially every network audio target support, so it is
the default. 'fixed' deliberately leaves the hardware keys dead — the
honest state for a device whose volume the sender may not touch.