Skip to main content

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 next setPlaybackState broadcast, 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 MPRemoteCommandCenter target (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​

ParameterTypeDescription
namestringMediaCustomAction.name
extrasstringJSON 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​

ParameterType
parentIdstring

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​

ParameterType
idstring

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​

ParameterType
kindstring

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​

ParameterTypeDescription
codeSessionErrorCodethe closed taxonomy. The TS layer attaches the severity.
messagestringa 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​

ParameterType
idstring

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​

ParameterType
querystring
focusNativeSearchFocus

Returns​

void


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​

ParameterType
querystring

Returns​

Promise<NativeBrowseResult>


seekTo​

seekTo: (position: number) => void;

Defined in: packages/media-session/src/specs/media-session.nitro.ts:1237

Parameters​

ParameterTypeDescription
positionnumbermilliseconds

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​

ParameterType
mutedboolean

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​

ParameterType
volumenumber

Returns​

void


setRate​

setRate: (rate: number) => void;

Defined in: packages/media-session/src/specs/media-session.nitro.ts:1249

Parameters​

ParameterType
ratenumber

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​

ParameterType
modeMediaRepeatMode

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​

ParameterType
enabledboolean

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​

ParameterTypeDescription
indexnumberindex into the last broadcast queue

Returns​

void


stop​

stop: () => void;

Defined in: packages/media-session/src/specs/media-session.nitro.ts:1235

Returns​

void