fix: critical AudioContext and setStartTime

This commit is contained in:
Xavier Araque 2025-11-07 17:11:47 +01:00
parent 4bbcbc17f1
commit f0c0e804fa
3 changed files with 16 additions and 11 deletions

View File

@ -63,6 +63,7 @@ const Player = () => {
const { const {
startTime, startTime,
setStartTime,
scrobbled, scrobbled,
onAudioProgress, onAudioProgress,
onAudioPlayTrackChange, onAudioPlayTrackChange,
@ -74,7 +75,6 @@ const Player = () => {
const { audioInstance, setAudioInstance, onAudioPlay } = useAudioInstance( const { audioInstance, setAudioInstance, onAudioPlay } = useAudioInstance(
isMobilePlayer, isMobilePlayer,
null, // context will be managed separately
) )
const { context } = useReplayGain(audioInstance, playerState, gainInfo) const { context } = useReplayGain(audioInstance, playerState, gainInfo)
@ -172,12 +172,13 @@ const Player = () => {
const handleAudioPlay = useCallback( const handleAudioPlay = useCallback(
(info) => { (info) => {
onAudioPlay( onAudioPlay(
context,
info, info,
(info) => dispatchCurrentPlaying(info), (info) => dispatchCurrentPlaying(info),
showNotifications, showNotifications,
sendNotification, sendNotification,
startTime, startTime,
(time) => {}, // setStartTime is handled in hook setStartTime,
resetPreloading, resetPreloading,
config, config,
ReactGA, ReactGA,
@ -185,9 +186,11 @@ const Player = () => {
}, },
[ [
onAudioPlay, onAudioPlay,
context,
dispatchCurrentPlaying, dispatchCurrentPlaying,
showNotifications, showNotifications,
startTime, startTime,
setStartTime,
resetPreloading, resetPreloading,
], ],
) )

View File

@ -1,25 +1,26 @@
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import subsonic from '../../subsonic'
/** /**
* Custom hook for managing the audio instance and related effects. * Custom hook for managing the audio instance and related effects.
* Handles audio element setup, mobile volume adjustments, and context resumption. * Handles audio element setup and mobile volume adjustments.
* *
* @param {boolean} isMobilePlayer - Whether the player is running on a mobile device. * @param {boolean} isMobilePlayer - Whether the player is running on a mobile device.
* @param {AudioContext|null} context - Web Audio API context from replay gain hook.
* @returns {Object} Audio instance-related state and handlers. * @returns {Object} Audio instance-related state and handlers.
* @returns {HTMLAudioElement|null} audioInstance - The audio element instance. * @returns {HTMLAudioElement|null} audioInstance - The audio element instance.
* @returns {Function} setAudioInstance - Setter for the audio instance. * @returns {Function} setAudioInstance - Setter for the audio instance.
* @returns {Function} onAudioPlay - Handler for audio play events. * @returns {Function} onAudioPlay - Handler for audio play events.
* *
* @example * @example
* const { audioInstance, setAudioInstance, onAudioPlay } = useAudioInstance(isMobilePlayer, context); * const { audioInstance, setAudioInstance, onAudioPlay } = useAudioInstance(isMobilePlayer);
*/ */
export const useAudioInstance = (isMobilePlayer, context) => { export const useAudioInstance = (isMobilePlayer) => {
const [audioInstance, setAudioInstance] = useState(null) const [audioInstance, setAudioInstance] = useState(null)
/** /**
* Handles audio play events, resuming context if needed and updating document title. * Handles audio play events, resuming context if needed and updating document title.
* *
* @param {AudioContext|null} audioContext - Web Audio API context from replay gain hook.
* @param {Object} info - Audio play information. * @param {Object} info - Audio play information.
* @param {Object} info.song - Song metadata. * @param {Object} info.song - Song metadata.
* @param {number} info.duration - Track duration. * @param {number} info.duration - Track duration.
@ -37,6 +38,7 @@ export const useAudioInstance = (isMobilePlayer, context) => {
*/ */
const onAudioPlay = useCallback( const onAudioPlay = useCallback(
( (
audioContext,
info, info,
dispatchCurrentPlaying, dispatchCurrentPlaying,
showNotifications, showNotifications,
@ -48,9 +50,9 @@ export const useAudioInstance = (isMobilePlayer, context) => {
ReactGA, ReactGA,
) => { ) => {
// Resume audio context if suspended // Resume audio context if suspended
if (context && context.state !== 'running') { if (audioContext && audioContext.state !== 'running') {
try { try {
context.resume() audioContext.resume()
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error('Error resuming audio context:', error) console.error('Error resuming audio context:', error)
@ -69,9 +71,8 @@ export const useAudioInstance = (isMobilePlayer, context) => {
if (!info.isRadio) { if (!info.isRadio) {
const pos = startTime === null ? null : Math.floor(info.currentTime) const pos = startTime === null ? null : Math.floor(info.currentTime)
// Assuming subsonic.nowPlaying is imported or passed
try { try {
// subsonic.nowPlaying(info.trackId, pos) // Uncomment if subsonic is available subsonic.nowPlaying(info.trackId, pos)
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error('Error updating now playing:', error) console.error('Error updating now playing:', error)
@ -107,7 +108,7 @@ export const useAudioInstance = (isMobilePlayer, context) => {
} }
} }
}, },
[context], [],
) )
// Mobile volume adjustment effect // Mobile volume adjustment effect

View File

@ -110,6 +110,7 @@ export const useScrobbling = (playerState, dispatch, dataProvider) => {
return { return {
startTime, startTime,
setStartTime,
scrobbled, scrobbled,
onAudioProgress, onAudioProgress,
onAudioPlayTrackChange, onAudioPlayTrackChange,