[bugfix]: web player edge cases

Two bugs addressed in response to Safari changes:
1. Only handle `onEnded` for real streams, preventing `autoNext()` spam when the last track finishes
2. `.play()` is not necessarily a safe operation (if empty wave was started, can cause exception later). Catch this exception and discard it. This also only occurred when playing the last track
This commit is contained in:
Kendall Garner 2024-01-28 01:50:51 -08:00
parent 47ce0ed47b
commit 5cc2276781
No known key found for this signature in database
GPG Key ID: 18D2767419676C87
3 changed files with 26 additions and 7 deletions

View File

@ -176,9 +176,18 @@ export const AudioPlayer = forwardRef(
useEffect(() => { useEffect(() => {
if (status === PlayerStatus.PLAYING) { if (status === PlayerStatus.PLAYING) {
if (currentPlayer === 1) { if (currentPlayer === 1) {
player1Ref.current?.getInternalPlayer()?.play(); // calling play() is not necessarily a safe option (https://developer.chrome.com/blog/play-request-was-interrupted)
// In practice, this failure is only likely to happen when using the 0-second wav:
// play() + play() in rapid succession will cause problems as the frist one ends the track.
player1Ref.current
?.getInternalPlayer()
?.play()
.catch(() => {});
} else { } else {
player2Ref.current?.getInternalPlayer()?.play(); player2Ref.current
?.getInternalPlayer()
?.play()
.catch(() => {});
} }
} else { } else {
player1Ref.current?.getInternalPlayer()?.pause(); player1Ref.current?.getInternalPlayer()?.pause();
@ -340,7 +349,8 @@ export const AudioPlayer = forwardRef(
url={player1?.streamUrl || EMPTY_SOURCE} url={player1?.streamUrl || EMPTY_SOURCE}
volume={webAudio ? 1 : volume} volume={webAudio ? 1 : volume}
width={0} width={0}
onEnded={handleOnEnded} // If there is no stream url, we do not need to handle when the audio finishes
onEnded={player1?.streamUrl ? handleOnEnded : undefined}
onProgress={ onProgress={
playbackStyle === PlaybackStyle.GAPLESS ? handleGapless1 : handleCrossfade1 playbackStyle === PlaybackStyle.GAPLESS ? handleGapless1 : handleCrossfade1
} }
@ -359,7 +369,7 @@ export const AudioPlayer = forwardRef(
url={player2?.streamUrl || EMPTY_SOURCE} url={player2?.streamUrl || EMPTY_SOURCE}
volume={webAudio ? 1 : volume} volume={webAudio ? 1 : volume}
width={0} width={0}
onEnded={handleOnEnded} onEnded={player2?.streamUrl ? handleOnEnded : undefined}
onProgress={ onProgress={
playbackStyle === PlaybackStyle.GAPLESS ? handleGapless2 : handleCrossfade2 playbackStyle === PlaybackStyle.GAPLESS ? handleGapless2 : handleCrossfade2
} }

View File

@ -23,7 +23,10 @@ export const gaplessHandler = (args: {
const durationPadding = isFlac ? 0.065 : 0.116; const durationPadding = isFlac ? 0.065 : 0.116;
if (currentTime + durationPadding >= duration) { if (currentTime + durationPadding >= duration) {
return nextPlayerRef.current.getInternalPlayer()?.play(); return nextPlayerRef.current
.getInternalPlayer()
?.play()
.catch(() => {});
} }
return null; return null;
@ -61,7 +64,10 @@ export const crossfadeHandler = (args: {
if (shouldBeginTransition) { if (shouldBeginTransition) {
setIsTransitioning(true); setIsTransitioning(true);
return nextPlayerRef.current.getInternalPlayer().play(); return nextPlayerRef.current
.getInternalPlayer()
?.play()
.catch(() => {});
} }
return null; return null;
} }

View File

@ -138,7 +138,10 @@ export const useCenterControls = (args: { playersRef: any }) => {
mpvPlayer?.volume(usePlayerStore.getState().volume); mpvPlayer?.volume(usePlayerStore.getState().volume);
mpvPlayer!.play(); mpvPlayer!.play();
} else { } else {
currentPlayerRef.getInternalPlayer().play(); currentPlayerRef
.getInternalPlayer()
?.play()
.catch(() => {});
} }
play(); play();