Skip to main content

Player

The Player class is a player controller that is decoupled from the player view. Create a Player instance using the PlayerProvider, and attach the video surface using the PlayerView when needed. The player instance can be accessed with the usePlayer hook to control playback. Other player hooks, such as usePosition and useDuration, allow responding to player events and creating custom controls.

PlayerProvider​

The PlayerProvider component initializes the player and makes it accessible through the PlayerContext. It takes a player configuration to initialize a player instance:

<PlayerProvider
playerConfig={{
autoPlay: true,
source: {
url: "https://demo.cf.castlabs.com/media/prestohls/master.m3u8",
type: ContentType.Hls,
},
}}
>
{/* component tree */}
</PlayerProvider>

PlayerProvider can be placed anywhere in the component tree. It supports multiple instances, with each PlayerProvider managing its own player. Additionally, it is possible to nest multiple PlayerProvider components.

The number of concurrently active player instances is capped by SdkConfiguration.maxNumberOfPlayers (default 2). Creating an additional player past this limit raises an ErrorCode.MaxNumberOfPlayersExceeded error; raise the limit at SDK initialization if your application needs more.

PlayerView​

The PlayerView component creates a video surface and attaches it to the player. It must be used within the scope of a PlayerProvider. However, the PlayerView doesn't need to be a direct child of the PlayerProvider; it just needs to be within its scope. For example:

<PlayerProvider playerConfig={playerConfig}>
<PlayerView />
</PlayerProvider>

usePlayer​

The usePlayer hook provides a programmatic way to interact with the player in functional components. Similar to the PlayerView component, the hook must be used within the scope of a PlayerProvider. Sample usage:

const player = usePlayer();
player.pause();

Other player hooks can be used to build custom player controls. For example, the usePosition and useDuration hooks can be used to build a time label:

export default function TimeLabel() {
const position = usePosition(); // in milliseconds
const duration = useDuration(); // in milliseconds
return (
<>
{position} / {duration}
</>
);
}

For the full list of hooks, refer to the API documentation.

Picture-in-Picture​

Picture-in-Picture (PiP) is supported on Android, iOS and Web. The player exposes it through Player.supportsPictureInPicture, Player.enterPictureInPictureMode and Player.exitPictureInPictureMode, and the current state can be observed with the usePictureInPictureMode hook:

export default function PictureInPictureButton() {
const player = usePlayer();
const pictureInPictureMode = usePictureInPictureMode();

return (
<Button
onPress={() =>
pictureInPictureMode
? player.exitPictureInPictureMode()
: player.enterPictureInPictureMode()
}
>
{pictureInPictureMode ? "Exit PiP" : "Enter PiP"}
</Button>
);
}

Always check Player.supportsPictureInPicture before offering the control: it reflects the platform capability and, on Android, whether the user has granted the PiP permission to the application.

Android​

The activity hosting the player must declare PiP support in ./android/app/src/main/AndroidManifest.xml:

<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:supportsPictureInPicture="true"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode">
<!-- .... -->
</activity>

By default the SDK adds its own controls to the PiP window — seek backward 10s, play/pause and seek forward 10s — and keeps them in sync with the playback state.

If your application already provides its own PiP controls, set AndroidPlayerConfiguration.pictureInPictureActionsDisabled to true. The SDK then adds no controls of its own and never updates the PiP parameters behind your back, leaving the window's actions entirely under your control:

await player.open({
source: {
url: "https://demo.cf.castlabs.com/media/prestohls/master.m3u8",
type: ContentType.Hls,
},
android: {
pictureInPictureActionsDisabled: true,
},
});

Android PiP controls are RemoteAction objects, which require an Icon and a PendingIntent and therefore cannot be created from JavaScript — your own controls must be installed from native Android code by calling setPictureInPictureParams() on your activity. Apply them after the player has entered Picture-in-Picture, for example from Activity.onPictureInPictureModeChanged(), because entering PiP clears the action list. Call setPictureInPictureParams() again whenever your controls change, such as swapping a pause icon for a play icon.