Skip to content

Commit bdf1fc5

Browse files
matvp91avelad
andcommitted
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 <[email protected]>
1 parent b08c64b commit bdf1fc5

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

lib/player.js

+22-22
Original file line numberDiff line numberDiff line change
@@ -3092,41 +3092,41 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
30923092
fullyLoaded.resolve();
30933093
});
30943094

3095+
const waitForNativeTracks = () => {
3096+
return new Promise((resolve) => {
3097+
const GRACE_PERIOD = 0.5;
3098+
const timer = new shaka.util.Timer(resolve);
3099+
// Applying the text preference too soon can result in it being
3100+
// reverted. Wait for native HLS to pick something first.
3101+
this.loadEventManager_.listen(mediaElement.textTracks,
3102+
'change', () => timer.tickAfter(GRACE_PERIOD));
3103+
timer.tickAfter(GRACE_PERIOD);
3104+
});
3105+
};
3106+
30953107
// We can't switch to preferred languages, though, until the data is
30963108
// loaded.
30973109
shaka.util.MediaReadyState.waitForReadyState(mediaElement,
30983110
HTMLMediaElement.HAVE_CURRENT_DATA,
30993111
this.loadEventManager_,
31003112
async () => {
3113+
await waitForNativeTracks();
3114+
// If we have moved on to another piece of content while waiting for
3115+
// the above event/timer, we should not change tracks here.
3116+
if (unloaded) {
3117+
return;
3118+
}
3119+
31013120
this.setupPreferredAudioOnSrc_();
31023121

3103-
// Applying the text preference too soon can result in it being
3104-
// reverted. Wait for native HLS to pick something first.
31053122
const textTracks = this.getFilteredTextTracks_();
3106-
if (!textTracks.find((t) => t.mode != 'disabled')) {
3107-
await new Promise((resolve) => {
3108-
this.loadEventManager_.listenOnce(
3109-
mediaElement.textTracks, 'change', resolve);
3110-
3111-
// We expect the event to fire because it does on Safari.
3112-
// But in case it doesn't on some other platform or future
3113-
// version, move on in 1 second no matter what. This keeps the
3114-
// language settings from being completely ignored if something
3115-
// goes wrong.
3116-
new shaka.util.Timer(resolve).tickAfter(1);
3117-
});
3118-
} else if (textTracks.length > 0) {
3123+
// If Safari native picked one for us, we'll set text visible.
3124+
if (textTracks.some((t) => t.mode === 'showing')) {
31193125
this.isTextVisible_ = true;
31203126
this.textDisplayer_.setTextVisibility(true);
31213127
}
31223128

3123-
// If we have moved on to another piece of content while waiting for
3124-
// the above event/timer, we should not change tracks here.
3125-
if (unloaded) {
3126-
return;
3127-
}
3128-
3129-
if (this.getFilteredTextTracks_().length) {
3129+
if (textTracks.length) {
31303130
if (this.textDisplayer_.enableTextDisplayer) {
31313131
this.textDisplayer_.enableTextDisplayer();
31323132
} else {

0 commit comments

Comments
 (0)