From e8453967a83e0b2b822c75429c661e59c3ffae20 Mon Sep 17 00:00:00 2001 From: Florens Douwes Date: Sat, 25 Apr 2020 18:36:40 +0200 Subject: [PATCH] player: workaround for autoplay adds autostart=true/false and nosound=true/false to the query params shows the player element when autoplay is off, so that the user can manually click on it. --- backend/src/Room.ts | 7 ++ frontend/src/components/Centurion.tsx | 2 +- frontend/src/components/Player.ts | 58 -------------- frontend/src/components/Player.tsx | 110 ++++++++++++++++++++++++++ frontend/src/css/player.sass | 4 + frontend/src/lib/Connection.ts | 14 +++- 6 files changed, 134 insertions(+), 61 deletions(-) delete mode 100644 frontend/src/components/Player.ts create mode 100644 frontend/src/components/Player.tsx create mode 100644 frontend/src/css/player.sass diff --git a/backend/src/Room.ts b/backend/src/Room.ts index f22a8fa..ba5bf77 100644 --- a/backend/src/Room.ts +++ b/backend/src/Room.ts @@ -24,6 +24,7 @@ export default class Room { // For debugging purposes speedFactor = 1; + autoStart = false; constructor(name: number) { this.id = name; @@ -59,6 +60,12 @@ export default class Room { this.setLeader(user); } + if (this.autoStart) { + this.seekTime = 2500000; + this.running = true; + this.start(); + } + this.sync(); } diff --git a/frontend/src/components/Centurion.tsx b/frontend/src/components/Centurion.tsx index 0d9f301..061d628 100644 --- a/frontend/src/components/Centurion.tsx +++ b/frontend/src/components/Centurion.tsx @@ -16,12 +16,12 @@ const Centurion = () => { const feedContent = ( - + ); diff --git a/frontend/src/components/Player.ts b/frontend/src/components/Player.ts deleted file mode 100644 index 59f82be..0000000 --- a/frontend/src/components/Player.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {roomTime, useRoomRunningAndReadyChanged, useRoomTime, useTimelineSongFileChanged} from "../lib/Connection"; -import {useRef, useState} from "react"; - - -const Player = () => { - const roomRunning = useRoomRunningAndReadyChanged(); - const _ = useRoomTime() - const timeline = useTimelineSongFileChanged(); - - const player = useRef(timeline ? new Audio(timeline.songFile) : null); - - const [timesSeeked, setTimesSeeked] = useState(0); - - // If our time synchronisation algorithm thing thinks the time is off by more - // than this value, we seek the running player to correct it. - const diffSecondsRequiredToSeekRunningPlayer = 0.20; - - // Hard cap we are allowed to seek this player. Some browsers are slow or inaccurate - // and will always be off. To avoid endless skipping of the song this cap stops seeking the - // player. - const maxTimesSeekAllow = 20; - - if (player.current && roomRunning?.running && roomRunning.readyToParticipate) { - let targetTime = roomTime() / 1000; - let diff = player.current.currentTime - targetTime; - - console.log('PLAYER DIFF', 'Our time diff with the server: ', diff, - 'Time required to seek (seconds): ', diffSecondsRequiredToSeekRunningPlayer); - - if (Math.abs(diff) > diffSecondsRequiredToSeekRunningPlayer) { - if (roomRunning.speedFactor != 1 || timesSeeked < maxTimesSeekAllow) { - player.current.currentTime = targetTime; - - player.current.playbackRate = Math.max(Math.min(4.0, roomRunning.speedFactor), 0.25); - - setTimesSeeked(timesSeeked + 1); - console.log('SEEKED', 'The running player time was seeked, times seeked in total: ' + timesSeeked); - } else { - console.warn('The running player is off, but we\'ve changed the time ' + - 'too often, skipping synchronizing the player.'); - } - } - - if (player.current.paused) { - player.current.play().catch(e => { - console.error('Error playing', e); - }) - } - } else { - if (player.current) { - player.current.pause(); - } - } - - return null; -} - -export default Player; \ No newline at end of file diff --git a/frontend/src/components/Player.tsx b/frontend/src/components/Player.tsx new file mode 100644 index 0000000..d77b15b --- /dev/null +++ b/frontend/src/components/Player.tsx @@ -0,0 +1,110 @@ +import {roomTime, useRoomRunningAndReadyChanged, useRoomTime, useTimelineSongFileChanged} from "../lib/Connection"; +import React, {createRef, SyntheticEvent, useRef, useState} from "react"; + +import '../css/player.sass' +import {Room} from "../types/types"; +import {parse as parseQueryString} from "query-string"; + +const Player = () => { + const room = useRoomRunningAndReadyChanged(); + const _ = useRoomTime() + const timeline = useTimelineSongFileChanged(); + + let player = useRef(null) + + const [timesSeeked, setTimesSeeked] = useState(0); + const [hadError, setHadError] = useState(false); + + // If our time synchronisation algorithm thing thinks the time is off by more + // than this value, we seek the running player to correct it. + const diffSecondsRequiredToSeekRunningPlayer = 0.20; + + // Hard cap we are allowed to seek this player. Some browsers are slow or inaccurate + // and will always be off. To avoid endless skipping of the song this cap stops seeking the + // player. + const maxTimesSeekAllow = 25; + + const query = parseQueryString(window.location.search); + if (query.nosound) { + return null; + } + + if (player.current && player.current.dataset.src != timeline!!.songFile) { + player.current.dataset.src = timeline!!.songFile; + player.current.src = timeline!!.songFile; + } + + function handlePlayerOnPlay(e: SyntheticEvent) { + e.preventDefault(); + + // For when the user manually started the player for when autoplay is off. + setHadError(false); + if (shouldPlay()) { + startPlaying(true) + } + } + + function shouldPlay() { + return player.current && timeline && room && room.running && room.readyToParticipate + } + + function startPlaying(manual: boolean) { + if (!player.current) return; + + if (player.current.paused && !hadError) { + player.current.play().then(() => { + setHadError(false); + }).catch(e => { + console.error('Error playing', e); + setHadError(true); + }) + } + + if (!hadError) { + setPlayerTime(room!!, manual); + } + } + + function setPlayerTime(room: Room, manualAdjustment: boolean) { + if (!player.current) return; + + let targetTime = roomTime() / 1000; + let diff = player.current.currentTime - targetTime; + + console.log('PLAYER DIFF', diff, + 'min req to seek: ', diffSecondsRequiredToSeekRunningPlayer); + + if (player.current && Math.abs(diff) > diffSecondsRequiredToSeekRunningPlayer) { + if (room.speedFactor != 1 || manualAdjustment || timesSeeked < maxTimesSeekAllow) { + player.current.currentTime = targetTime; + player.current.playbackRate = Math.max(Math.min(4.0, room.speedFactor), 0.25); + + if (!manualAdjustment) { + setTimesSeeked(timesSeeked + 1); + } + console.log('PLAYER SEEKED', 'Player was seeked (total: ' + timesSeeked + ')'); + } else { + console.warn('The running player is off, but we\'ve changed the time ' + + 'too often, skipping synchronizing the player.'); + } + } + } + + if (shouldPlay()) { + startPlaying(false) + } else { + if (player.current) { + player.current.pause(); + } + } + + function render() { + return ( +