Safari¶
PRESTOplay for web has dedicated support for Safari, automatically choosing the most appropriate player delegate for the stream format you’re playing.
HLS playback¶
For HLS streams on Safari, PRESTOplay uses a native player delegate that
relies on Safari’s built-in HLS support through the <video> element. This is
the default behavior and requires no extra configuration:
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.hls";
player.open({
source: {
url: 'https://example.com/stream.m3u8',
type: clpp.Type.HLS,
},
});
One strength of this default player is support for FairPlay-protected MPEG-TS streams, which the MSE player can’t provide due to limitations of the browser.
Using the MSE player for HLS¶
The MSE player can also play HLS on Safari — for example, when you need
features only available through MSE-based playback. See
Components for details on the MSE module. To opt in, set
preferNativeHlsOnSafari to false:
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.hls";
player.open({
source: {
url: 'https://example.com/stream.m3u8',
type: clpp.Type.HLS,
},
streaming: {
preferNativeHlsOnSafari: false,
},
});
DASH playback¶
For DASH streams on Safari, PRESTOplay uses the MSE player delegate, which requires the MSE and DASH modules:
import { clpp } from "@castlabs/prestoplay";
import "@castlabs/prestoplay/cl.mse";
import "@castlabs/prestoplay/cl.dash";
player.open({
source: {
url: 'https://example.com/stream.mpd',
type: clpp.Type.DASH,
},
});
Native HLS playback caveats¶
Native player delegate (HLS default) playback has some caveats due to limitations or known issues in Safari’s WebKit API.
IMA on iOS and tracks UI¶
On iOS, the IMA SDK runs in custom playback mode, so track objects are recreated when an ad break ends and playback resumes on the primary content.
Listen for clpp.events.TRACKS_REMOVED followed by clpp.events.TRACKS_ADDED
to get notified.
Because tracks are recreated, your UI must reset its state at the start and
end of each ad break. On AD_BREAK_STARTED, hide the track selection UI and
clear any stale state. On AD_BREAK_STOPPED, read the current tracks from
the track manager — PRESTOplay has restored them by this point — and show the
UI again:
player.on(clpp.events.AD_BREAK_STARTED, () => {
// Hide tracks UI
trackSelectionUI.style.display = 'none';
// Clear your stored tracks state
resetTrackUI();
});
player.on(clpp.events.AD_BREAK_STOPPED, () => {
// Track objects have changed — re-read data from the track manager
// to populate your tracks state
renderTrackUI(player.getAudioTracks(), player.getTextTracks());
// Show tracks UI
trackSelectionUI.style.display = '';
});
Audio tracks on iOS¶
Due to known WebKit issues (#301928, #297904) on iOS 26.4 and 26.3, audio tracks must be formatted in a specific way to work correctly.
Set AUTOSELECT=NO,DEFAULT=NO and use unintelligible language codes such as
l1, l2, l3 in the HLS playlist:
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio/mp4a.40.2",LANGUAGE="l1",NAME="English",AUTOSELECT=NO,DEFAULT=NO,CHANNELS="2",URI="audio-en-US-mp4a.40.2.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio/mp4a.40.2",LANGUAGE="l2",NAME="German",AUTOSELECT=NO,DEFAULT=NO,CHANNELS="2",URI="audio-de-DE-mp4a.40.2.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio/mp4a.40.2",LANGUAGE="l3",NAME="Spanish",AUTOSELECT=NO,DEFAULT=NO,CHANNELS="2",URI="audio-es-ES-mp4a.40.2.m3u8"
Then use the preferredAudioLanguage configuration option to select the
default track, instead of relying on the AUTOSELECT and DEFAULT
attributes:
player.open({
source: '...',
preferredAudioLanguage: ['l1'], // English
});
Lack of metadata about tracks¶
Safari doesn’t provide full metadata for tracks in general. See
SafariConfiguration for options to enable richer track metadata
with the native player delegate, or switch to the MSE player delegate for
access to all playlist metadata.
Video track selection isn’t supported¶
Safari doesn’t support manual selection of video tracks or renditions (changing quality), so these APIs aren’t usable:
The native player delegate handles adaptive bitrate streaming (ABR) internally, so ABR-related configuration doesn’t apply either:
Switch to the MSE player delegate for full control over track selection and ABR.