Skip to content

Commit 306b682

Browse files
matvp91avelad
andauthored
fix: Text tracks with src= on Safari & UITextDisplayer are sometimes rendered natively (#8256)
This concerns `src=` mode. Safari loads text tracks separately, where on `loadeddata`, we might not have `video.textTracks` set to its final value (as Safari could still be processing another text track underneath). This PR introduces an artificial wait on the `addtrack` and assumes, if no other track is added within the next 500ms, textTracks shall be in its final state. Issues when we work with `textTracks` too early: - When we set mode of a textTrack to `hidden` (we'd do that to allow UiTextDisplayer to render text tracks), Safari might overwrite this decision (based on `AUTOSELECT=YES`) when a subsequent text track is parsed. This leaves us in an invalid state where textTracks are rendered natively but we have listeners bound to the wrong one. More info here: #8255 - It could be no textTracks are available at all on `loadeddata` due to Safari internally defering the load for text tracks. This would break preferences. --------- Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
1 parent b2a1d35 commit 306b682

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

lib/player.js

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3197,41 +3197,41 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
31973197
fullyLoaded.resolve();
31983198
});
31993199

3200+
const waitForNativeTracks = () => {
3201+
return new Promise((resolve) => {
3202+
const GRACE_PERIOD = 0.5;
3203+
const timer = new shaka.util.Timer(resolve);
3204+
// Applying the text preference too soon can result in it being
3205+
// reverted. Wait for native HLS to pick something first.
3206+
this.loadEventManager_.listen(mediaElement.textTracks,
3207+
'change', () => timer.tickAfter(GRACE_PERIOD));
3208+
timer.tickAfter(GRACE_PERIOD);
3209+
});
3210+
};
3211+
32003212
// We can't switch to preferred languages, though, until the data is
32013213
// loaded.
32023214
shaka.util.MediaReadyState.waitForReadyState(mediaElement,
32033215
HTMLMediaElement.HAVE_CURRENT_DATA,
32043216
this.loadEventManager_,
32053217
async () => {
3218+
await waitForNativeTracks();
3219+
// If we have moved on to another piece of content while waiting for
3220+
// the above event/timer, we should not change tracks here.
3221+
if (unloaded) {
3222+
return;
3223+
}
3224+
32063225
this.setupPreferredAudioOnSrc_();
32073226

3208-
// Applying the text preference too soon can result in it being
3209-
// reverted. Wait for native HLS to pick something first.
32103227
const textTracks = this.getFilteredTextTracks_();
3211-
if (!textTracks.find((t) => t.mode != 'disabled')) {
3212-
await new Promise((resolve) => {
3213-
this.loadEventManager_.listenOnce(
3214-
mediaElement.textTracks, 'change', resolve);
3215-
3216-
// We expect the event to fire because it does on Safari.
3217-
// But in case it doesn't on some other platform or future
3218-
// version, move on in 1 second no matter what. This keeps the
3219-
// language settings from being completely ignored if something
3220-
// goes wrong.
3221-
new shaka.util.Timer(resolve).tickAfter(1);
3222-
});
3223-
} else if (textTracks.length > 0) {
3228+
// If Safari native picked one for us, we'll set text visible.
3229+
if (textTracks.some((t) => t.mode === 'showing')) {
32243230
this.isTextVisible_ = true;
32253231
this.textDisplayer_.setTextVisibility(true);
32263232
}
32273233

3228-
// If we have moved on to another piece of content while waiting for
3229-
// the above event/timer, we should not change tracks here.
3230-
if (unloaded) {
3231-
return;
3232-
}
3233-
3234-
if (this.getFilteredTextTracks_().length) {
3234+
if (textTracks.length) {
32353235
if (this.textDisplayer_.enableTextDisplayer) {
32363236
this.textDisplayer_.enableTextDisplayer();
32373237
} else {

0 commit comments

Comments
 (0)