Skip to content

Commit

Permalink
Temporary fix for firefox desync/laggy
Browse files Browse the repository at this point in the history
  • Loading branch information
solstice23 committed Oct 17, 2024
1 parent 2108445 commit 94b7743
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 15 deletions.
29 changes: 26 additions & 3 deletions src/contexts/PlayStateContext.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createContext, useState, useRef, useContext, useEffect } from "react";
import { createContext, useState, useRef, useContext, useEffect, useCallback } from "react";
import { MapPackContext } from "./MapPackContext";
import { BeatmapsContext } from "./BeatmapsContext";
import { SettingsContext } from "./SettingsContext";
Expand All @@ -7,6 +7,8 @@ export const PlayStateContext = createContext(null);

const clamp = (val, min, max) => Math.min(Math.max(val, min), max);

const isFirefox = navigator.userAgent.toLowerCase().includes("firefox");

export const PlayStateProvider = ({children}) => {
const [playing, _setPlaying] = useState(false);
const [duration, _setDuration] = useState(0);
Expand Down Expand Up @@ -53,13 +55,33 @@ export const PlayStateProvider = ({children}) => {
useEffect(() => {
playerRef.current.playbackRate = actualSpeed;
}, [actualSpeed]);


const performanceNowRef = useRef(-1);
const lastPlayerTimeRef = useRef(-1000);

const getPreciseTime = useCallback(() => {
if (!playerRef.current?.currentTime) return 0;
// Firefox's audio.currentTime is not precise
if (!isFirefox) return playerRef.current.currentTime * 1000;
const playerTime = playerRef.current.currentTime * 1000;
if (playerRef.current.paused) {
return playerTime;
}
if (Math.abs(playerTime - lastPlayerTimeRef.current) > 1) {
lastPlayerTimeRef.current = playerTime;
performanceNowRef.current = performance.now();
//console.log(playerTime);
return playerTime;
}
//console.log(playerTime + performance.now() - performanceNowRef.current);
return playerTime + performance.now() - performanceNowRef.current;
}, [playing]);

return (
<PlayStateContext.Provider value={{
playing,
duration,
time,
time, // not precise, for display only
playbackRate,
volume,
playerRef,
Expand All @@ -79,6 +101,7 @@ export const PlayStateProvider = ({children}) => {
playerRef.current.volume = value;
_setVolume(value);
},
getPreciseTime
}}>
{children}
<audio
Expand Down
11 changes: 6 additions & 5 deletions src/modules/ControlBar/ProgressBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,22 @@ function ProgressBarSlider({startTween, stopTween, extendTween}) {
const {
playing,
duration,
playerRef
playerRef,
getPreciseTime,
} = useContext(PlayStateContext);

const sliderRef = useRef(null);
const handleRef = useRef(null);

const [dragging, setDragging] = useState(false);

const persent = playerRef.current?.currentTime / duration * 100;
const present = getPreciseTime() / (duration * 1000) * 100;

const getDurationByEvent = useCallback((e) => {
const rect = sliderRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const persent = Math.min(1, Math.max(0, x / rect.width));
return persent * duration;
const present = Math.min(1, Math.max(0, x / rect.width));
return present * duration;
}, [duration]);

const seek = (time) => {
Expand Down Expand Up @@ -146,7 +147,7 @@ function ProgressBarSlider({startTween, stopTween, extendTween}) {
<div
className="progress-bar-slider-handle"
ref={handleRef}
style={{left: `${persent}%`}}
style={{left: `${present}%`}}
/>
</div>
)
Expand Down
3 changes: 2 additions & 1 deletion src/modules/ControlBar/TimeIndicator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function TimeIndicator() {
const beatmap = useContext(BeatmapsContext).beatmaps?.at(-1);

const playerRef = useContext(PlayStateContext).playerRef;
const getPreciseTime = useContext(PlayStateContext).getPreciseTime;

const [currentTime, setCurrentTime] = useState(0);
const totalTime = (beatmap?.totalLength) ?? playerRef?.current?.duration * 1000 ?? 0; // TODO: we need to make the length more accurate for VBR audios
Expand All @@ -27,7 +28,7 @@ export function TimeIndicator() {
const [totalMin, totalSec, totalMs] = parseTime(totalTime);

const [start, stop] = useRequestAnimationFrame((time) => {
setCurrentTime(playerRef.current.currentTime * 1000);
setCurrentTime(getPreciseTime());
});

useEffect(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/modules/Main/Playfield/AutoCatcher.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function AutoCatcher({ beatmap, catcherPath }) {
}, [beatmap.difficulty.circleSize, width, hardRock, easy]);


const {playing, playerRef} = useContext(PlayStateContext);
const {playing, playerRef, getPreciseTime} = useContext(PlayStateContext);

// TODO: use svg or canvas for better performance
const lastTime = useRef(-1000000); // Last time of the song
Expand All @@ -80,7 +80,7 @@ export function AutoCatcher({ beatmap, catcherPath }) {
const update = () => {
const path = catcherPathRef.current;
if (!path?.length) return;
const currentTime = playerRef.current.currentTime * 1000;
const currentTime = getPreciseTime();
if (currentTime === lastTime.current) return;
let newIndex = index.current;
if (Math.abs(currentTime - lastTime.current) > 20000) {
Expand Down
7 changes: 4 additions & 3 deletions src/modules/Main/Playfield/ObjectsCanvas.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function ObjectsCanvas({
easy, easyRef,
} = useContext(SettingsContext);

const {playing, playerRef} = useContext(PlayStateContext);
const {playing, playerRef, getPreciseTime} = useContext(PlayStateContext);

const managerRef = useRef();

Expand All @@ -36,6 +36,7 @@ export function ObjectsCanvas({
manager.setApproachRate(beatmap.difficulty.approachRate);
manager.setCircleSize(beatmap.difficulty.circleSize);
manager.setPlayer(playerRef);
manager.setTimeGetter(getPreciseTime);
return () => managerRef.current.destory();
}, []);

Expand Down Expand Up @@ -183,8 +184,8 @@ class PixiManager {
setPlayer(playerRef) {
this.playerRef = playerRef.current;
}
getTime() {
return this.playerRef.currentTime * 1000;
setTimeGetter(getTime) {
this.getTime = getTime;
}
setObjects(objects) {
this.objects = objects;
Expand Down
1 change: 0 additions & 1 deletion src/parser/MapPackParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export async function parseMapPackFromZipFile(zipFile, fileName, preferredDiffic
if (!preferredDifficulty) {
return beatmap;
}
console.log(beatmap.metadata.beatmapId, preferredDifficulty, parseInt(preferredDifficulty));
if (beatmap.metadata.beatmapId == parseInt(preferredDifficulty)) {
beatmap.preferredDifficulty = true;
}
Expand Down

0 comments on commit 94b7743

Please sign in to comment.