Interface: MediaSessionHandlers
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1232
The fan-in surface: one callback per remote command, supplied once at RnMediaMediaSession.initialize.
A single struct of callbacks rather than ten setXHandler methods: nitrogen
turns each function type into a Func_* wrapper either way, and one struct
makes "the handler set is replaced atomically" true by construction.
All of them are required — an optional callback would push "did the app
implement this?" into native, when the answer is already carried by
NativePlaybackState.capabilities. BaseMediaHandler supplies no-ops.
Contract
- Callbacks return
void, not a promise. Native dispatches and returns immediately — a remote command must never wait on JS (that is an ANR on Android and a dropped command on iOS). The acknowledgement is the app's nextsetPlaybackStatebroadcast, which is also what completes media3's pending-operation future. - Nitro schedules the JS invocation onto the JS thread itself, so native may
call these from a binder thread, the media3 application looper, or a
MPRemoteCommandCentertarget (https://nitro.margelo.com/docs/types/callbacks).
Properties
customAction
customAction: (name: string, extras: string) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1317
A custom action was invoked. Android only — MediaCustomAction documents why iOS has no surface that can invoke one, so this is never called there by the session.
Parameters
| Parameter | Type | Description |
|---|---|---|
name | string | MediaCustomAction.name |
extras | string | JSON object string, '{}' when there are none. A JSON string rather than a map because the Android payload is an arbitrary Bundle from a third-party MediaController; flattening it once, in native, keeps the bridge type trivial and the failure mode visible. |
Returns
void
decreaseDeviceVolume
decreaseDeviceVolume: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1294
One notch quieter. See increaseDeviceVolume.
Returns
void
getChildren
getChildren: (parentId: string) => Promise<NativeBrowseResult>;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1397
Children of a browsable node. The root asks with the exported
BROWSE_ROOT id.
The one place in this struct where native waits on JS, and it is
allowed to: onGetChildren is documented as asynchronous (media3 returns
a ListenableFuture) and the browser — not the user's finger — is the
thing kept waiting. Everything that is a command still returns void.
A returning callback arrives natively as a Nitro Promise<T> callable
from any thread (Promise.kt / Promise.swift, 0.37.0), which is what
lets the media3 application looper bridge it into a ListenableFuture
without a hop through the main thread.
Parameters
| Parameter | Type |
|---|---|
parentId | string |
Returns
Promise<NativeBrowseResult>
getMediaItem
getMediaItem: (id: string) => Promise<NativeBrowseResult>;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1405
One item by id — Android's onGetItem, CarPlay's refresh of a row.
Returns the same result shape carrying 0 or 1 items, rather than an optional item, so the error half is available here too (a locked item should say "premium required", not "does not exist").
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
Promise<NativeBrowseResult>
increaseDeviceVolume
increaseDeviceVolume: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1292
A remote surface asked for one notch louder on the remote device.
This — not setDeviceVolume — is what a hardware volume key press
becomes: the platform delivers VolumeProvider.onAdjustVolume(+1), media3
turns it into Player.increaseDeviceVolume(flags), and the facade lands
here. One notch is 1 / steps of the published range.
Two callbacks rather than one direction argument, deliberately: it is the
exact shape media3 hands us (handleIncreaseDeviceVolume /
handleDecreaseDeviceVolume) and it needs no new enum on the bridge. The
TS layer folds the pair back into one onAdjustDeviceVolume('up'|'down').
Returns
void
onCarConnectionChanged
onCarConnectionChanged: (kind: string) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1436
A car connected or disconnected: 'none' | 'androidAuto' | 'automotiveOs' | 'carPlay'.
A plain string rather than a union because it is the same value
RnMediaMediaSession.getCarConnection returns, and the TS layer
widens both into the CarConnection discriminated union in one place.
Parameters
| Parameter | Type |
|---|---|
kind | string |
Returns
void
onPlaybackResumption
onPlaybackResumption: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1340
Android only: this JS runtime was booted by the media service, to finish a playback resumption that had already started without it.
Fired once, immediately after the handlers are installed and before any
command deferred during the revival is replayed. Purely informational —
the notification is already up, the session already carries the persisted
track, and the play the user pressed is replayed on your handler a beat
later whether or not you implement this.
Returns
void
onRevivalRequested
onRevivalRequested: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1365
Android only: a revival started while this JS runtime was already
alive, and the service needs initialize to be called again before it
can hand the session over.
The one caller is RnMediaMediaSessionService.onRuntimeReady, and the one
scenario is stop-then-resume without a process death: stopService() tore
the session down (handlers cleared, service stopped), the System UI's
resumption card or a media button starts the service again, and the
runtime it finds is the same one that already ran its module scope — so
the module-scope init that saves a cold revival can never run again.
This callback is how native asks the live runtime to re-initialize.
Unlike every other member of this struct, native retains it across
stopService (see MediaSessionController.revivalRequester): it exists
precisely for the window in which the ordinary handlers are gone. It is
dropped when the runtime itself is torn down (dev reload), which is the
only point it could dangle.
The TS layer routes it to MediaServiceConfig.android.onRevivalRequested
and swallows it while init is idle-less (already initializing or ready),
so a cold revival — where module-scope init is already in flight when
the runtime-ready signal fires — never double-initializes.
Returns
void
onSessionError
onSessionError: (code: SessionErrorCode, message: string) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1379
The session could not do something, and no JS call was waiting to be told.
The one outbound member of this struct that is not a user gesture. Both platforms call it; SessionErrorCode documents which codes each can produce and when. Fire-and-forget like the rest — native logs the same line it always logged and then hands it over, so an app that ignores the channel loses nothing it had before.
Parameters
| Parameter | Type | Description |
|---|---|---|
code | SessionErrorCode | the closed taxonomy. The TS layer attaches the severity. |
message | string | a complete sentence naming what failed and, where there is one, the fix. Never a bare exception toString(). |
Returns
void
onSleepTimer
onSleepTimer: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1329
The sleep timer set by RnMediaMediaSession.setSleepTimer elapsed.
The pause has already happened by the time this runs — natively, on the
same path a notification pause takes (ARCHITECTURE §9). This callback is a
notification, not a request: it is where an app clears its own timer UI,
logs, fades out, or calls stopService(). Doing nothing is correct.
Fired at most once per armed timer, and never after RnMediaMediaSession.cancelSleepTimer.
Returns
void
onTaskRemoved
onTaskRemoved: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1305
Android only: the app's task was swiped out of Recents.
Always invoked in addition to the built-in default policy so the JS side
can react (persist state, analytics); the default policy itself lives in
native so it still runs when JS is wedged. See
RnMediaMediaSessionService.onTaskRemoved.
Returns
void
pause
pause: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1234
Returns
void
play
play: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1233
Returns
void
playFromMediaId
playFromMediaId: (id: string) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1422
A car, a head unit or an assistant asked to play a browse item.
void, like play: the acknowledgement is the app's next setQueue /
setPlaybackState broadcast (ARCHITECTURE §9). On Android this arrives
through MediaSession.Callback.onSetMediaItems, which is where every
legacy onPlayFromMediaId lands (MediaSessionLegacyStub, media3 1.11.0).
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
void
playFromSearch
playFromSearch: (query: string, focus: NativeSearchFocus) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1427
"Play some jazz." query may be empty — Assistant's bare "play music" —
which means resume, or pick something.
Parameters
| Parameter | Type |
|---|---|
query | string |
focus | NativeSearchFocus |
Returns
void
search
search: (query: string) => Promise<NativeBrowseResult>;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1413
Browsable search results for the car's search tab.
Never invoked on iOS: CarPlay audio apps have no search template at all
(there is no CPSearchTemplate outside the navigation entitlement), so
the car has no surface to type into. Not a parity gap — a missing surface.
Parameters
| Parameter | Type |
|---|---|
query | string |
Returns
Promise<NativeBrowseResult>
seekTo
seekTo: (position: number) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1237
Parameters
| Parameter | Type | Description |
|---|---|---|
position | number | milliseconds |
Returns
void
setDeviceMuted
setDeviceMuted: (muted: boolean) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1296
A remote surface asked to mute or unmute the remote device.
Parameters
| Parameter | Type |
|---|---|
muted | boolean |
Returns
void
setDeviceVolume
setDeviceVolume: (volume: number) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1278
A remote surface asked for an absolute volume on the remote device,
0..1.
Only reachable while RnMediaMediaSession.setRemotePlayback has
published a volumeControl: 'absolute' device — the system volume dialog's
slider, the output switcher, a MediaController. Same request/acknowledge
contract as every other command: the app moves the backend and republishes
through setRemotePlayback.
Android only, along with increaseDeviceVolume,
decreaseDeviceVolume and setDeviceMuted:
setRemotePlayback is a documented no-op on iOS, where
MPRemoteCommandCenter has no volume command and the hardware buttons
cannot be taken over at all.
Parameters
| Parameter | Type |
|---|---|
volume | number |
Returns
void
setRate
setRate: (rate: number) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1249
Parameters
| Parameter | Type |
|---|---|
rate | number |
Returns
void
setRepeatMode
setRepeatMode: (mode: MediaRepeatMode) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1259
A remote surface asked for a different repeat mode.
A request, not a notification: nothing has changed until the app changes
it and says so with a setPlaybackState carrying the new
NativePlaybackState.repeatMode. Same contract as play/pause —
the app's next broadcast is the acknowledgement, which is also what
completes media3's pending-operation future.
Parameters
| Parameter | Type |
|---|---|
mode | MediaRepeatMode |
Returns
void
setShuffle
setShuffle: (enabled: boolean) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1261
A remote surface asked to turn shuffle on or off. See setRepeatMode.
Parameters
| Parameter | Type |
|---|---|
enabled | boolean |
Returns
void
skipToNext
skipToNext: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1238
Returns
void
skipToPrevious
skipToPrevious: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1239
Returns
void
skipToQueueItem
skipToQueueItem: (index: number) => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1248
Android only from a remote surface — see
MediaCapability's skipToQueueItem for the citation. iOS has no
queue-jump command, so this is never invoked there by the session; the app's
own UI still calls it.
Parameters
| Parameter | Type | Description |
|---|---|---|
index | number | index into the last broadcast queue |
Returns
void
stop
stop: () => void;
Defined in: packages/media-session/src/specs/media-session.nitro.ts:1235
Returns
void