Trying to make the distinction between a video element ('source')

and its parent div ('stream') less confusing
This commit is contained in:
Erik Thuning 2022-10-27 15:43:48 +02:00
parent 3d8d2b44e8
commit 1a661ac4e9

@ -243,14 +243,18 @@
// raw presentation json is stored here
this._presentation = null;
// all streams to be played back
this._streams = [];
// all sources to be played back
this._sources = [];
// the main playback stream at any given time
this._mainStream = null;
// the controlling video element
// other video elements will sync with this source
this._controlSource = null;
// the stream that plays the audio
this._audioStream = null;
// the source that plays the audio
this._audioSource = null;
// the main playback source at any given time
this._mainSource = null;
// list of elements to show/hide based on playlist presence
this._playlistUI = [];
@ -431,8 +435,8 @@
button.addEventListener('click', (event) => {
const speed = event.currentTarget.textContent;
currentSpeed.textContent = speed;
this._streams.forEach((stream) => {
stream.querySelector('video').playbackRate = speed;
this._sources.forEach((source) => {
source.playbackRate = speed;
});
});
});
@ -495,8 +499,7 @@
[createIcon(['subtitles-off',
'subtitles-on'])]);
this._subtitlesButton.addEventListener('click', (event) => {
const track = this._mainStream.querySelector('video')
.textTracks[0];
const track = this._mainSource.textTracks[0];
if(track.mode === 'disabled') {
track.mode = 'showing';
} else {
@ -539,7 +542,7 @@
while(parent.hasChildNodes()) {
parent.removeChild(parent.firstChild());
}
this._streams = [];
this._sources = [];
this._overlayPlayIcons = [];
// initialize UI elements
@ -593,15 +596,11 @@
'src': `${presentation.subtitles}?token=${token}`});
}
// keep a reference to the stream that plays audio
if(stream.playAudio) {
this._audioSource = video;
}
//misc details
video.muted = !stream.playAudio;
video.poster = stream.poster;
video.load();
this._sources.push(video);
// set up overlay icons
const switchIcon = streamRoot.appendChild(
@ -612,25 +611,28 @@
streamRoot.classList.add('main');
switchIcon.classList.add('hidden');
// keep a reference to the main stream around
this._mainStream = streamRoot;
// kepp a reference to the control source around
this._controlSource = video;
// keep a reference to the main source around
this._mainSource = video;
// keep a reference to the source that plays audio
this._audioSource = video;
} else {
playIcon.classList.add('hidden');
}
// set up stream listeners
streamRoot.addEventListener('click', (event) => {
const stream = event.currentTarget;
if(stream.classList.contains('main')) {
// this is the main stream, toggle playback
if(event.currentTarget.classList.contains('main')) {
// this is the main source, toggle playback
this.togglePlayback();
} else {
// this is a secondary stream, switch it to main
this.switchMainStream(stream);
// this is a secondary source, switch it to main
this.switchMainSource(
event.currentTarget.querySelector('video'));
}
});
this._streams.push(streamRoot);
}
this.setActivePlaylistItem();
@ -732,9 +734,8 @@
}
button.addEventListener('click', (event) => {
const res = event.currentTarget.textContent;
const time = this._mainStream.querySelector('video')
.currentTime;
const paused = this._mainStream.paused;
const time = this._mainSource.currentTime;
const paused = this._mainSource.paused;
// temporarily pause playback for the switch
if(!paused) {
this.togglePlayback();
@ -743,10 +744,9 @@
return;
}
current.textContent = res;
this._streams.forEach((stream) => {
const video = stream.querySelector('video');
video.src = video.dataset[res];
video.currentTime = time;
this._sources.forEach((source) => {
source.src = source.dataset[res];
source.currentTime = time;
});
this.togglePlayback();
});
@ -778,11 +778,11 @@
* Jump in the presentation.
*
* The arg 'time' gives the time to jump to as a number of seconds
* since start. Syncronizes any secondary streams via a custom event.
* since start. Syncronizes any secondary sources via a custom event.
*/
setTime(time) {
this._mainstream.currentTime = time;
this._mainstream.dispatchEvent(new CustomEvent('sync'));
this._mainSource.currentTime = time;
this._mainSource.dispatchEvent(new CustomEvent('sync'));
}
/*
@ -837,73 +837,70 @@
/*
* Start or stop playback.
*
* Toggles Playback button states and synchronizes streams.
* Toggles Playback button states and synchronizes sources.
*/
togglePlayback() {
this.toggleButtonState(this._playButton);
const paused = this._mainStream.querySelector('video').paused;
this._streams.forEach((stream) => {
const videoElem = stream.querySelector('video');
const paused = this._controlSource.paused;
this._sources.forEach((source) => {
if(paused) {
videoElem.play();
source.play();
} else {
videoElem.pause();
source.pause();
}
this.toggleIconState(stream.querySelector('.play'));
this.toggleIconState(
source.parentNode.querySelector('.play'));
});
this.syncStreams();
this.syncSources();
}
/*
* Synchronize all secondary streams to the current main stream.
* Synchronize all secondary sources to the current main source.
*/
syncStreams() {
const mainVideo = this._mainStream.querySelector('video');
this._streams.forEach((stream) => {
const video = stream.querySelector('video');
if(stream.classList.contains('main')) {
syncSources() {
this._sources.forEach((source) => {
if(source == this._controlSource) {
return;
}
video.currentTime = mainVideo.currentTime;
source.currentTime = this._controlSource.currentTime;
});
}
/*
* Switch the main playback stream to the one passed in newMain.
* Switch the main playback source to the one passed in newMain.
*/
switchMainStream(newMain) {
switchMainSource(newMain) {
function switchIcons(elem) {
elem.querySelectorAll('svg').forEach((icon) => {
icon.classList.toggle('hidden');
});
}
this._mainStream.classList.remove('main');
switchIcons(this._mainStream);
const oldMainParent = this._mainSource.parentNode;
oldMainParent.classList.remove('main');
switchIcons(oldMainParent);
newMain.classList.add('main');
switchIcons(newMain);
const newMainParent = newMain.parentNode;
newMainParent.classList.add('main');
switchIcons(newMainParent);
const oldTrack = this._mainStream.querySelector('video')
.textTracks[0];
const newTrack = newMain.querySelector('video')
.textTracks[0];
const oldTrack = this._mainSource.textTracks[0];
const newTrack = newMain.textTracks[0];
const oldState = oldTrack.mode;
oldTrack.mode = newTrack.mode;
newTrack.mode = oldState;
this._mainStream = newMain;
this.syncStreams();
this._mainSource = newMain;
this.syncSources();
}
updateProgress() {
if(this._progressInterval != null) {
window.clearInterval(this._progressInterval)
}
const trackedVideo = this._mainStream.querySelector('video');
this._progressInterval = window.setInterval(
() => {
this._elapsed.textContent = this.formatTime(
trackedVideo.currentTime);
this._controlSource.currentTime);
}, 200);
}
}