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; 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); } } 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 (