Skip to content

Commit

Permalink
Do not append 608/WebVTT/IMSC cues that have already been appended
Browse files Browse the repository at this point in the history
Fix 608 CC continuity when seeking and while track is disabled
Clear tracks when level's text group-id changes
Update group-id on level switch not just level loading
Merges changes from #3321 into master, while maintaining that `config.cueHandler` must append cues to their supplied TextTrack
  • Loading branch information
Rob Walch committed Jan 28, 2021
1 parent ad5c23b commit 7be9bad
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 130 deletions.
63 changes: 53 additions & 10 deletions demo/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ let stopOnStall = getDemoConfigPropOrDefault('stopOnStall', false);
let bufferingIdx = -1;
let selectedTestStream = null;

const video = document.querySelector('#video');
let video = document.querySelector('#video');
const startTime = Date.now();

let lastSeekingIdx;
Expand Down Expand Up @@ -340,7 +340,32 @@ function loadSelectedStream() {

logStatus('Loading manifest and attaching video element...');

const expiredTracks = [].filter.call(
video.textTracks,
(track) => track.kind !== 'metadata'
);
if (expiredTracks.length) {
const kinds = expiredTracks
.map((track) => track.kind)
.filter((kind, index, self) => self.indexOf(kind) === index);
logStatus(
`Replacing video element to remove ${kinds.join(' and ')} text tracks`
);
const videoWithExpiredTextTracks = video;
video = videoWithExpiredTextTracks.cloneNode(false);
video.removeAttribute('src');
video.volume = videoWithExpiredTextTracks.volume;
video.muted = videoWithExpiredTextTracks.muted;
videoWithExpiredTextTracks.parentNode.insertBefore(
video,
videoWithExpiredTextTracks
);
videoWithExpiredTextTracks.parentNode.removeChild(
videoWithExpiredTextTracks
);
}
addChartEventListeners(hls);
addVideoEventListeners(video);

hls.loadSource(url);
hls.autoLevelCapping = levelCapping;
Expand Down Expand Up @@ -865,7 +890,23 @@ function loadSelectedStream() {
stats.fpsTotalDroppedFrames = data.totalDroppedFrames;
}
});
}

function addVideoEventListeners(video) {
video.removeEventListener('resize', handleVideoEvent);
video.removeEventListener('seeking', handleVideoEvent);
video.removeEventListener('seeked', handleVideoEvent);
video.removeEventListener('pause', handleVideoEvent);
video.removeEventListener('play', handleVideoEvent);
video.removeEventListener('canplay', handleVideoEvent);
video.removeEventListener('canplaythrough', handleVideoEvent);
video.removeEventListener('ended', handleVideoEvent);
video.removeEventListener('playing', handleVideoEvent);
video.removeEventListener('error', handleVideoEvent);
video.removeEventListener('loadedmetadata', handleVideoEvent);
video.removeEventListener('loadeddata', handleVideoEvent);
video.removeEventListener('durationchange', handleVideoEvent);
video.removeEventListener('volumechange', handleVolumeEvent);
video.addEventListener('resize', handleVideoEvent);
video.addEventListener('seeking', handleVideoEvent);
video.addEventListener('seeked', handleVideoEvent);
Expand All @@ -879,15 +920,7 @@ function loadSelectedStream() {
video.addEventListener('loadedmetadata', handleVideoEvent);
video.addEventListener('loadeddata', handleVideoEvent);
video.addEventListener('durationchange', handleVideoEvent);
video.addEventListener('volumechange', (evt) => {
localStorage.setItem(
STORAGE_KEYS.volume,
JSON.stringify({
muted: video.muted,
volume: video.volume,
})
);
});
video.addEventListener('volumechange', handleVolumeEvent);
}

function handleUnsupported() {
Expand Down Expand Up @@ -985,6 +1018,16 @@ function handleVideoEvent(evt) {
trimEventHistory();
}

function handleVolumeEvent() {
localStorage.setItem(
STORAGE_KEYS.volume,
JSON.stringify({
muted: video.muted,
volume: video.volume,
})
);
}

function handleLevelError(data) {
var levelObj = data.context || data;
hls.removeLevel(levelObj.level, levelObj.urlId || 0);
Expand Down
23 changes: 15 additions & 8 deletions src/controller/audio-track-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ErrorData,
LevelLoadingData,
AudioTrackLoadedData,
LevelSwitchingData,
} from '../types/events';
import BasePlaylistController from './base-playlist-controller';
import { PlaylistContextType } from '../types/loader';
Expand All @@ -30,6 +31,7 @@ class AudioTrackController extends BasePlaylistController {
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
hls.on(Events.ERROR, this.onError, this);
}
Expand All @@ -39,6 +41,7 @@ class AudioTrackController extends BasePlaylistController {
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
hls.off(Events.ERROR, this.onError, this);
}
Expand Down Expand Up @@ -85,18 +88,22 @@ class AudioTrackController extends BasePlaylistController {
}
}

/**
* When a level is loading, if it has redundant audioGroupIds (in the same ordinality as it's redundant URLs)
* we are setting our audio-group ID internally to the one set, if it is different from the group ID currently set.
*
* If group-ID got update, we re-select the appropriate audio-track with this group-ID matching the currently
* selected one (based on NAME property).
*/
protected onLevelLoading(
event: Events.LEVEL_LOADING,
data: LevelLoadingData
): void {
const levelInfo = this.hls.levels[data.level];
this.switchLevel(data.level);
}

protected onLevelSwitching(
event: Events.LEVEL_SWITCHING,
data: LevelSwitchingData
): void {
this.switchLevel(data.level);
}

private switchLevel(levelIndex: number) {
const levelInfo = this.hls.levels[levelIndex];

if (!levelInfo?.audioGroupIds) {
return;
Expand Down
10 changes: 3 additions & 7 deletions src/controller/id3-track-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Events } from '../events';
import {
sendAddTrackEvent,
clearCurrentCues,
getCuesInRange,
removeCuesInRange,
} from '../utils/texttrack-utils';
import * as ID3 from '../demux/id3';
import type {
Expand Down Expand Up @@ -138,12 +138,8 @@ class ID3TrackController implements ComponentAPI {
if (!type || type === 'audio') {
// id3 cues come from parsed audio only remove cues when audio buffer is cleared
const { id3Track } = this;
if (!id3Track || !id3Track.cues || !id3Track.cues.length) {
return;
}
const cues = getCuesInRange(id3Track.cues, startOffset, endOffset);
for (let i = 0; i < cues.length; i++) {
id3Track.removeCue(cues[i]);
if (id3Track) {
removeCuesInRange(id3Track, startOffset, endOffset);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/controller/subtitle-stream-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export class SubtitleStreamController
return;
}
this.fragmentTracker.removeAllFragments();
this.fragPrevious = null;
this.currentTrackId = -1;
this.levels.forEach((level: Level) => {
this.tracksBuffered[level.id] = [];
Expand Down Expand Up @@ -173,6 +174,8 @@ export class SubtitleStreamController
this.levels = subtitleTracks.map(
(mediaPlaylist) => new Level(mediaPlaylist)
);
this.fragmentTracker.removeAllFragments();
this.fragPrevious = null;
this.levels.forEach((level: Level) => {
this.tracksBuffered[level.id] = [];
});
Expand Down
15 changes: 14 additions & 1 deletion src/controller/subtitle-track-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
MediaAttachedData,
SubtitleTracksUpdatedData,
ManifestParsedData,
LevelSwitchingData,
} from '../types/events';
import type { MediaPlaylist } from '../types/media-playlist';
import { ErrorData, LevelLoadingData } from '../types/events';
Expand Down Expand Up @@ -44,6 +45,7 @@ class SubtitleTrackController extends BasePlaylistController {
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
hls.on(Events.ERROR, this.onError, this);
}
Expand All @@ -55,6 +57,7 @@ class SubtitleTrackController extends BasePlaylistController {
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
hls.off(Events.ERROR, this.onError, this);
}
Expand Down Expand Up @@ -163,8 +166,18 @@ class SubtitleTrackController extends BasePlaylistController {
event: Events.LEVEL_LOADING,
data: LevelLoadingData
): void {
const levelInfo = this.hls.levels[data.level];
this.switchLevel(data.level);
}

protected onLevelSwitching(
event: Events.LEVEL_SWITCHING,
data: LevelSwitchingData
): void {
this.switchLevel(data.level);
}

private switchLevel(levelIndex: number) {
const levelInfo = this.hls.levels[levelIndex];
if (!levelInfo?.textGroupIds) {
return;
}
Expand Down

0 comments on commit 7be9bad

Please sign in to comment.