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 onlyMediaCustomAction 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