From d03fb216289cfdf322783be89154a5a15d89c6a3 Mon Sep 17 00:00:00 2001 From: Yoan Le Clanche Date: Thu, 14 Mar 2024 15:55:25 +0100 Subject: [PATCH] Video sync WIP --- teleforma/src/js/video/SyncVideoPlayer.ts | 46 +++++++++++++--- teleforma/src/js/video/VideoComponent.vue | 15 ++++++ teleforma/src/js/video/VideoPlayer.ts | 64 ++++++++++++++++++----- teleforma/src/js/video/constants.ts | 3 +- teleforma/src/js/video/main.d.ts | 1 + 5 files changed, 110 insertions(+), 19 deletions(-) diff --git a/teleforma/src/js/video/SyncVideoPlayer.ts b/teleforma/src/js/video/SyncVideoPlayer.ts index 1e26f5b9..ae304a81 100644 --- a/teleforma/src/js/video/SyncVideoPlayer.ts +++ b/teleforma/src/js/video/SyncVideoPlayer.ts @@ -6,11 +6,12 @@ import VideoPlayer from './VideoPlayer'; const validStates = { [PlayerState.LOADING]: [PlayerState.LOADED], [PlayerState.LOADED]: [PlayerState.PLAYING], - [PlayerState.PLAYING]: [PlayerState.PAUSE, PlayerState.ENDED], + [PlayerState.PLAYING]: [PlayerState.PAUSE, PlayerState.ENDED, PlayerState.BUFFERING], [PlayerState.PAUSE]: [PlayerState.PLAYING, PlayerState.ENDED], [PlayerState.ENDED]: [PlayerState.PLAYING], - [PlayerState.BUFFERING]: [], + [PlayerState.BUFFERING]: [PlayerState.READY, PlayerState.PAUSE, PlayerState.PLAYING], + [PlayerState.READY]: [PlayerState.PLAYING], [PlayerState.UNSTARTED]: [], }; @@ -28,8 +29,8 @@ class SyncVideoPlayer { public options: MultiVideoPlayerOptions; public $container: Element | null; public videoPlayers: VideoPlayer[] = []; + public state: PlayerState; private readyCount: number; - private state: PlayerState; private currentTime: number; constructor(options: MultiVideoPlayerOptions) { @@ -50,6 +51,23 @@ class SyncVideoPlayer { this.currentTime = 0; } + public getDebugInfo() { + return { + state: this.state, + currentTime: this.currentTime, + videoPlayers: this.videoPlayers.map(vp => { + return { + id: vp.videoId, + state: vp.videoState, + currentTime: vp.getCurrentTime(), + duration: vp.getDuration, + isMain: vp.main, + isPlaying: vp.isPlaying, + }; + }), + }; + } + public mount() { this.render(); this.addVideoPlayers(this.options.videoPlayers); @@ -70,12 +88,15 @@ class SyncVideoPlayer { } public async changeState(state: PlayerState, videoPlayer: VideoPlayer) { + // console.log("change global state", state) if (state === PlayerState.BUFFERING) { + return this.pause() + // console.log("change state to BUFFERING") + // return this.pause(); // TODO: find out how to handle buffering - return; + // return; } if (state === PlayerState.PLAYING) { - console.log("set state : playing") return this.play(); } if (state === PlayerState.PAUSE) { @@ -99,6 +120,19 @@ class SyncVideoPlayer { } }); } + if (state === PlayerState.READY) { + // player has finished buffering and ready to start + // check if every player is ready + + const allReady = this.videoPlayers.every(vp => { + return [PlayerState.READY, PlayerState.PLAYING, PlayerState.PAUSE].includes(vp.videoState); + }); + if(allReady){ + console.log("all ready, start playing") + await this.play(); + } + + } if (state === PlayerState.UNSTARTED) { if (this.state === PlayerState.ENDED) { if (this.options.loop) { @@ -109,6 +143,7 @@ class SyncVideoPlayer { } private async moveStateTo(state: PlayerState, success?: (newState: PlayerState, oldState: PlayerState) => void, fail?: (newState: PlayerState, oldState: PlayerState) => void) { + if(state === this.state) return; if (isValidState(this.state, state)) { const oldState = this.state; this.state = state; @@ -127,7 +162,6 @@ class SyncVideoPlayer { public async onReady() { this.readyCount++; if (this.readyCount !== this.videoPlayers.length) return; - console.log("READY2") await this.moveStateTo(PlayerState.LOADED); } diff --git a/teleforma/src/js/video/VideoComponent.vue b/teleforma/src/js/video/VideoComponent.vue index d52a9102..2ebfbaa4 100644 --- a/teleforma/src/js/video/VideoComponent.vue +++ b/teleforma/src/js/video/VideoComponent.vue @@ -14,9 +14,14 @@ const syncVideoPlayer = new SyncVideoPlayer({ // build a list of video ids equal to multivideos length const ids = ref(Array.from({ length: multivideos.length }, (_, i) => `video-${i}`)) +const debugInfo = ref({}) onMounted(() => { syncVideoPlayer.mount() + + setInterval(() => { + debugInfo.value = syncVideoPlayer.getDebugInfo() + }, 50) // const mainVideo = document.getElementById("main-video").querySelector("video") // mainVideo.addEventListener("loadeddata", () => { @@ -49,6 +54,7 @@ onMounted(() => { // thumbnailsVideos!.style.height = `${thumbnailsVideoHeight}px` // } + async function onPlay() { await syncVideoPlayer.play() } @@ -83,6 +89,8 @@ async function onChange(e: Event) { const value = (e.target as HTMLInputElement).value await syncVideoPlayer.timeTo(parseFloat(value)) } + +