Skip to content

Subtitles & audio

The subtitle and audio menus fill themselves from the stream (embedded tracks) and from anything you sideload. Track objects and selection calls are identical on every platform.

A subtitle cue over the video with the controls hidden.
The demo app on an iPhone 17 Pro Max, running the published SDK.
player.load(
OGMediaItem.Builder(streamUrl)
.setSideloadedSubtitles(
listOf(
SubtitleSource("https://…/en.vtt", language = "en",
label = "English", isDefault = true),
SubtitleSource("https://…/de.vtt", language = "de", label = "Deutsch"),
),
)
.build(),
)

Positioned WebVTT cues (line: / position: / align: settings) render faithfully on all platforms.

textTracks / audioTracks expose everything with an isSelected flag; selectTextTrack(id) (or null/nil for off) and selectAudioTrack(id) switch. Audio entries carry language and channel count — surfaced as proper display names in the built-in menu.

On the web every load() starts on the stream’s own audio choice — the DEFAULT=YES rendition on HLS; on DASH the AdaptationSet with the highest @selectionPriority, then the one with Role main, then the first listed. A track picked for an earlier item, or on an earlier visit, does not carry over; if your app remembers the viewer’s choice, select it again after the new item loads.

subtitleStyle controls colors, background, edge type and the base size fraction; subtitleTextScale is a viewer-facing multiplier (the demos map it to Small / Default / Large / X-Large chips). Sizing follows the player height with sane clamps, matching TV-style caption behaviour.

Captions can render in your brand font instead of the platform default. The font is your explicit choice, so it applies to embedded and sideloaded cues, on top of any in-stream styling:

player.setSubtitleStyle(
SubtitleStyle.Builder()
.setTypeface(ResourcesCompat.getFont(context, R.font.your_brand_font))
.build(),
)

Pass null (the default) to return to the platform font.