Fix bogus text track in UI with src= mode

When the non-UI TextDisplayer is constructed, it creates an extra
TextTrack that can never be removed.  This leads to a bogus text track
showing up in the UI when content is played in src= mode.

This changes the TextDisplayer to disable the extra TextTrack (since
there is no API to remove it) and changes the Player to ignore
disabled TextTracks when generating a track list for src= playbacks.

Closes #2516

Change-Id: I2e651f737445049da5fa46a798a2bc0751de2822
This commit is contained in:
Joey Parrish
2020-04-21 12:39:49 -07:00
parent 05d1db50af
commit ad3d4604af
4 changed files with 41 additions and 1 deletions
+2 -1
View File
@@ -2855,7 +2855,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
return tracks;
} else if (this.video_ && this.video_.src && this.video_.textTracks) {
const textTracks = Array.from(this.video_.textTracks);
const textTracks = Array.from(this.video_.textTracks)
.filter((t) => t.mode != 'disabled');
const StreamUtils = shaka.util.StreamUtils;
return textTracks.map((text) => StreamUtils.html5TextTrackToTrack(text));
} else {
+9
View File
@@ -33,6 +33,8 @@ shaka.text.SimpleTextDisplayer = class {
// If the video element has TextTracks, disable them. If we see one that
// was created by a previous instance of Shaka Player, reuse it.
for (const track of Array.from(video.textTracks)) {
// NOTE: There is no API available to remove a TextTrack from a video
// element.
track.mode = 'disabled';
if (track.label == shaka.text.SimpleTextDisplayer.TextTrackLabel_) {
@@ -145,6 +147,13 @@ shaka.text.SimpleTextDisplayer = class {
if (this.textTrack_) {
const removeIt = (cue) => true;
shaka.text.SimpleTextDisplayer.removeWhere_(this.textTrack_, removeIt);
// Prevent this extra TextTrack from affecting future playbacks. Without
// this, we get something bogus in the track list for src= playbacks, as
// in https://github.com/google/shaka-player/issues/2516
// NOTE: There is no API available to remove a TextTrack from a video
// element.
this.textTrack_.mode = 'disabled';
}
this.textTrack_ = null;
+8
View File
@@ -223,6 +223,14 @@ describe('Player Src Equals', () => {
expect(player.getTextTracks()).toEqual([]);
});
it('ignores disabled text tracks on the video element', async () => {
const textTrack = video.addTextTrack('subtitles', 'label');
textTrack.mode = 'disabled';
await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
expect(player.getTextTracks()).toEqual([]);
});
// TODO: test HLS on platforms with native HLS
it('allows selecting text tracks', async () => {
await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
+22
View File
@@ -42,6 +42,10 @@ describe('SimpleTextDisplayer', () => {
window.VTTCue = /** @type {?} */(FakeVTTCue);
});
afterEach(async () => {
await displayer.destroy();
});
afterAll(() => {
window.VTTCue = originalVTTCue;
});
@@ -296,6 +300,24 @@ describe('SimpleTextDisplayer', () => {
});
});
describe('destroy', () => {
it('disables the TextTrack it created', async () => {
// There should only be the one track created by this displayer.
expect(video.textTracks.length).toBe(1);
/** @type {!TextTrack} */
const textTrack = video.textTracks[0];
// It should not be disabled before we destroy it.
expect(textTrack.mode).not.toBe('disabled');
await displayer.destroy();
// It should be disabled after we destroy it.
expect(textTrack.mode).toBe('disabled');
});
});
function createFakeCue(startTime, endTime) {
return {startTime: startTime, endTime: endTime};
}