Selecting the Playback Mode
You can leverage the W3C Media APIs to build media player applications for the Vega OS in a few different ways:
- Directly using the W3C Media APIs: This is a suitable approach when playing flat (non-ABR) content.
- Building a custom JavaScript player using the W3C Media APIs: Developers can create their own proprietary JavaScript-based media player by directly integrating the relevant W3C Media APIs.
- Integrating existing JavaScript player libraries: There are several popular JavaScript media player libraries available, such as Shaka Player, hls.js, dash.js, and Bitmovin Player. Developers can choose to integrate one of these existing players, which provide abstraction over the underlying W3C Media APIs.
For an overview of the W3C Media APIs in Vega SDK, see React Native W3C Media API on Vega OS.
Regardless of the approach, you should familiarize yourself with the relevant W3C specifications and the documentation for the selected player APIs:
This provides a comprehensive understanding of the available functionality and capabilities, allowing for more informed decisions and better implementation of media player apps for the Vega OS.
Depending on the nature of the content, whether it is flat or ABR, the app needs to use one of the following playback modes.
URL Mode
URL mode is designed for playing non-adaptive content formats such as MP4 and MP3 files. In this mode, you set the media source directly using the HTMLMediaElement.src attribute.
Audio-Only Playback Example
The following example demonstrates a simple audio-only playback implementation.
/*
* Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All rights reserved.
*
* PROPRIETARY/CONFIDENTIAL. USE IS SUBJECT TO LICENSE TERMS.
*/
import React, {useRef} from 'react';
import {View, Text} from 'react-native';
import {VideoPlayer} from '@amazon-devices/react-native-w3cmedia';
export const App = () => {
const audio = useRef<VideoPlayer | null>(new AudioPlayer());
audio.current?.initialize().then(() => {
audio.current!.autoplay = true;
audio.current!.src = 'https://<streaming server>.com/audio_only.mp3';
});
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'black'}}>
<Text style={{color: 'white', fontSize: 18}}>Audio Playback</Text>
</View>
);
};
This example:
- Creates a VideoPlayer instance using
useRef() - Initializes the player and sets autoplay to true so playback starts automatically
- Sets the audio source URL using the src attribute
- Renders a simple UI with text indicating audio playback
Video Playback Example
The following example demonstrates video playback in URL mode.
/*
* Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All rights reserved.
*
* PROPRIETARY/CONFIDENTIAL. USE IS SUBJECT TO LICENSE TERMS.
*/
import React, {useRef} from 'react';
import {View} from 'react-native';
import {
VideoPlayer,
KeplerVideoSurfaceView,
} from '@amazon-devices/react-native-w3cmedia';
export const App = () => {
const video = useRef<VideoPlayer | null>(new VideoPlayer());
const onSurfaceViewCreated = async (surfaceHandle: string) => {
await video.current?.initialize();
video.current?.setSurfaceHandle(surfaceHandle);
video.current!.autoplay = true;
video.current!.src = 'https://<streaming server>.com/av.mp4';
};
const onSurfaceViewDestroyed = async (surfaceHandle: string) => {
video.current?.clearSurfaceHandle(surfaceHandle);
await video.current?.deinitialize();
video.current = null;
};
return (
<View style={{flex: 1}}>
<KeplerVideoSurfaceView
style={{flex: 1}}
onSurfaceViewCreated={onSurfaceViewCreated}
onSurfaceViewDestroyed={onSurfaceViewDestroyed}
/>
</View>
);
};
This example:
- Creates an instance of
VideoPlayerusinguseRef() - Implements
onSurfaceViewCreatedcallback that:- Initializes the video player
- Connects the player to the surface using
setSurfaceHandle() - Enables autoplay
- Sets the video source URL
- Implements
onSurfaceViewDestroyedcallback that:- Disconnects the surface handle
- Deinitializes the player
- Cleans up the player reference
- Renders the component with lifecycle callbacks
Key Differences Between Audio and Video Playback:
- Surface management: Video playback requires managing the KeplerVideoSurfaceView lifecycle through onSurfaceViewCreated and onSurfaceViewDestroyed callbacks
- Surface handle: Video playback needs to connect the player to the rendering surface using setSurfaceHandle()
- Cleanup: Video playback requires proper cleanup of surface handles and deinitialization when the surface is destroyed
MSE Mode
Use the MSE (Media Source Extensions) mode to play adaptive bitrate content, such as HLS or DASH streams. This mode requires integrating a JavaScript-based media player library that handles downloading and managing adaptive media streams.
Choosing a Media Player
Several JavaScript media player libraries support MSE, including:
- Open-source: Shaka Player, Dash.js, HLS.js, Bitmovin, Video.js
- Commercial: Bitmovin, and other proprietary solutions
Your app must integrate one of these players and use the Vega-provided W3C APIs to interact with the media content. For a complete list of compatible players, see Vega compatible media players in "Supported Libraries and Services."
MSE Streaming Example with Shaka Player
The following example demonstrates streaming DASH content using Shaka Player.
/*
/*
* Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All rights reserved.
*
* PROPRIETARY/CONFIDENTIAL. USE IS SUBJECT TO LICENSE TERMS.
*/
import React, {useRef} from 'react';
import {View} from 'react-native';
import {
VideoPlayer,
KeplerVideoSurfaceView,
KeplerCaptionsView,
} from '@amazon-devices/react-native-w3cmedia';
import {ShakaPlayer, ShakaPlayerSettings} from './shakaplayer/ShakaPlayer';
const content = {
secure: 'false',
uri: 'https://<streaming server>.com/dash.mpd',
drm_scheme: '',
drm_license_uri: '',
};
const playerSettings: ShakaPlayerSettings = {
secure: false,
abrEnabled: true,
};
export const App = () => {
const videoPlayer = useRef<VideoPlayer | null>(new VideoPlayer());
const shakaPlayer = useRef<any>(null);
const onSurfaceViewCreated = async (surfaceHandle: string) => {
await videoPlayer.current?.initialize();
videoPlayer.current?.setSurfaceHandle(surfaceHandle);
videoPlayer.current!.autoplay = true;
shakaPlayer.current = new ShakaPlayer(videoPlayer.current!, playerSettings);
shakaPlayer.current.load(content, true);
};
const onSurfaceViewDestroyed = async (surfaceHandle: string) => {
videoPlayer.current?.clearSurfaceHandle(surfaceHandle);
shakaPlayer.current?.unload();
shakaPlayer.current = null;
await videoPlayer.current?.deinitialize();
videoPlayer.current = null;
};
const onCaptionViewCreated = (captionsHandle: string) => {
videoPlayer.current?.setCaptionViewHandle(captionsHandle);
};
return (
<View style={{flex: 1, backgroundColor: 'black'}}>
<KeplerVideoSurfaceView
style={{flex: 1}}
onSurfaceViewCreated={onSurfaceViewCreated}
onSurfaceViewDestroyed={onSurfaceViewDestroyed}
/>
<KeplerCaptionsView
onCaptionViewCreated={onCaptionViewCreated}
show={true}
style={{
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: 'transparent',
zIndex: 2,
}}
/>
</View>
);
};
This example:
- Configures content: Defines the DASH manifest URL and DRM settings (if needed)
- Sets player options: Enables adaptive bitrate (ABR) streaming
- Initializes video player: Creates and initializes the VideoPlayer instance when the surface is created
- Integrates Shaka Player: Creates a ShakaPlayer instance and loads the content
- Manages captions: Sets up the KeplerCaptionsView component for subtitle rendering
- Handles cleanup: Properly unloads the player and deinitializes resources when the surface is destroyed
Building and Testing
Use the Vega SDK to build the app and run it on a device or simulator. For detailed instructions, see the following topics:
Important: URL Mode vs MSE Mode
URL mode is not supported for adaptive streaming. While URL mode may work for some basic adaptive content in limited cases, its behavior is not guaranteed and it is not officially supported for adaptive bitrate streaming.
Use URL mode only for:
- Non-adaptive content (MP4, MP3 files) • Simple playback scenarios
Use MSE mode for:
- Adaptive bitrate content (HLS, DASH streams)
- DRM-protected content
- Live streaming
- Advanced playback features
For adaptive content, always use MSE mode with a JavaScript-based media player library that properly handles adaptive streaming protocols.
Next steps
When choosing a player, consider factors such as the supported features, performance, community support, and licensing. Review the documentation and examples provided by each player to determine the best fit for your application's requirements. Once you've selected a player, refer to their integration guides to learn how to set it up and use it within your React Native media player app. Some of the these players are already ported, please see the following:
- Playing Adaptive Streaming Content (HLS/DASH) with Shaka Player
- Play adaptive content using Dash.js Player
- Play adaptive content using Hls.js Player
Related topics
Last updated: Jan 13, 2026

