Media Control API
Our Media Control API provides a unified way to customise the behaviour of the different media playback controls and media sessions across platforms (iOS, Android, and Web). It enables integration with platform-level media controls such as lock screen controls, notification controls, media session, ...
What is it used for?
- Remote Control Actions: Handle play, pause, seek, skip, and track switching from system UI (lock screen, notifications, etc.).
- Media Session Integration: Display media state and respond to hardware/media key events.
- Custom Playlist Navigation: Enable playlist navigation using system controls.
Platform Support
- Android: Integrates with Media Session and media notifications.
- iOS: Integrates with Now Playing and Remote Command Center.
- Web: Integrates with the Media Session API.
MediaControl API and MediaControl Action Reference
The Media Control API allows you to override the default player's behaviour, by defining a handler for one of the MediaControl Actions:
setHandler(action: MediaControlAction, handler: MediaControlHandler | undefined): void;
Passing undefined as handler removes any previously set handler for that action, restoring the player's default behaviour.
The MediaControlAction enum defines all actions that can be controlled by the Media Control API:
PLAY: Triggered when the user presses play.PAUSE: Triggered when the user presses pause.SKIP_TO_NEXT: Triggered when the user requests to go to the next track or playlist item.SKIP_TO_PREVIOUS: Triggered when the user requests to go to the previous track or playlist item.
Play and pause are only enabled for VOD and when the stream is not displaying an ad. For LIVE streams this can be configured through allowLivePlayPause in the player's MediaControlConfiguration.
If no handler is defined for an action, the player's default behaviour is applied.
iOS: Track Control vs. Seek Behavior
On iOS, when you set handlers for SKIP_TO_NEXT or SKIP_TO_PREVIOUS, these handlers will take precedence over the seek behavior. This means:
- If you provide next/previous track handlers:
- System controls (e.g., lock screen) will display and trigger your handlers for track navigation.
- Seeking forward/backward via next/previous is not shown as seperate controls. (Platform limitation)
- If you do not provide next/previous handlers:
- The system will display and use the seek forward/backward functionality with the configured or default intervals.
This allows you to customize whether system controls are used for playlist navigation or for seeking within the current track.
Note: In both cases, you can always use the system's time slider to adjust the playhead to seek to a location in the stream.
Multiple players: single media-session owner
Each platform exposes a single, process-wide media session and set of remote controls (iOS MPNowPlayingInfoCenter / MPRemoteCommandCenter, Android MediaSession + notification,
Web navigator.mediaSession). When your app renders more than one THEOplayerView at the same time, they all share this single system session.
Because of that, only one player should own the media session at any given time. It is the application's responsibility to designate that single owner and to ensure no other player simultaneously publishes Now Playing info or handles remote commands. If multiple players are allowed to take control at once:
- Now Playing info (title, artwork, position) from the different players will overwrite each other.
- Remote commands (play/pause/seek/skip) become last‑writer‑wins: the most recent player to claim the controls keeps them, and control can flip between players as each one updates its state.
Recommended approach
Keep a single "active" player and toggle ownership so that exactly one player has the media session enabled at a time. You can update ownership across players using:
// Give this player exclusive ownership of the media session / remote commands.
player.mediaControl?.setEnabled(isActive);
where isActive is true for the player that should own the media session and false for all other players. The owner will have its state reflected on the media session widgets.
iOS: lock screen and Control Center play/pause state with multiple playing players
As a good practice, make sure only one player is actively playing at any given time. Shift the media session ownership (as demonstrated above) whenever a player starts playing (e.g. on a PLAY or PLAYING event) and pause all other players. On iOS, Control Center reflects the application's overall audio session state, not that of a specific player, so if multiple players are playing at once its controls will act on all of them.
Configuration
You can add additional media control configuration using the MediaControlConfiguration interface:
export interface MediaControlConfiguration {
mediaSessionEnabled?: boolean; // (Web/Android) Enable/disable media session (default: true)
skipForwardInterval?: number; // (Web/Android/iOS) Skip forward interval (defaults: 5s on Web, Android / 15s on iOS)
skipBackwardInterval?: number; // (Web/Android/iOS) Skip backward interval (defaults: 5s on Web, Android / 15s on iOS)
allowLivePlayPause?: boolean; // (Android/iOS) Enable play/pause for live (defaults: false on Android / true on iOS)
}
Example Usage: Playlist Navigation
The Media Control API can be used to handle playlist navigation via system controls. For example, in a component that owns the playlist:
import { MediaControlAction } from 'react-native-theoplayer';
// ...
useEffect(() => {
if (!player) return;
const handleNext = () => { /* update player source ... */ };
const handlePrevious = () => { /* update player source ... */ };
player.mediaControl?.setHandler(MediaControlAction.SKIP_TO_NEXT, handleNext);
player.mediaControl?.setHandler(MediaControlAction.SKIP_TO_PREVIOUS, handlePrevious);
return () => {
player.mediaControl?.setHandler(MediaControlAction.SKIP_TO_NEXT, undefined);
player.mediaControl?.setHandler(MediaControlAction.SKIP_TO_PREVIOUS, undefined);
};
}, [player, filteredSources]);
This enables users to skip tracks using lock screen or Bluetooth controls. If you do not set these handlers, the controls will perform seek actions instead.
Demo
As a demonstration, see the the PlaylistProvider in our example app.