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.master
parent
9a564e9844
commit
e8453967a8
@ -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; |
@ -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<HTMLAudioElement>(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 ( |
||||
<audio ref={player} className='player' hidden={!hadError} controls={true} onPlay={handlePlayerOnPlay}/> |
||||
) |
||||
} |
||||
|
||||
return render(); |
||||
} |
||||
|
||||
export default Player; |
@ -0,0 +1,4 @@ |
||||
.player |
||||
position: fixed |
||||
left: 0 |
||||
bottom: 0 |
Loading…
Reference in new issue