import { useCallback, useEffect, useRef } from "react" import Hls from "hls.js" export function useAudioPlayer() { const audioRef = useRef(null) const hlsRef = useRef(null) const networkRetryCount = useRef(0) const onStateChange = useRef<((state: "playing" | "paused" | "stopped" | "error") => void) | null>(null) const play = useCallback((streamUrl: string, streamType: "hls" | "direct" | null) => { if (!audioRef.current) return if (hlsRef.current) { hlsRef.current.destroy() hlsRef.current = null } if (streamType === "hls" && Hls.isSupported()) { const hls = new Hls({ maxBufferLength: 30, maxMaxBufferLength: 60, }) hls.loadSource(streamUrl) hls.attachMedia(audioRef.current) hls.on(Hls.Events.MANIFEST_PARSED, () => { audioRef.current?.play() onStateChange.current?.("playing") }) hls.on(Hls.Events.ERROR, (_event, data) => { if (data.fatal) { if (data.type === Hls.ErrorTypes.NETWORK_ERROR) { networkRetryCount.current++ if (networkRetryCount.current > 3) { hls.destroy() hlsRef.current = null onStateChange.current?.("error") } else { const backoff = Math.min(2 ** networkRetryCount.current * 1000, 10000) setTimeout(() => hls.startLoad(), backoff) } } else { hls.destroy() hlsRef.current = null onStateChange.current?.("error") } } }) networkRetryCount.current = 0 hlsRef.current = hls } else { audioRef.current.src = streamUrl audioRef.current.play().then(() => { onStateChange.current?.("playing") }).catch(() => { onStateChange.current?.("error") }) } }, []) const pause = useCallback(() => { audioRef.current?.pause() onStateChange.current?.("paused") }, []) const stop = useCallback(() => { audioRef.current?.pause() if (hlsRef.current) { hlsRef.current.destroy() hlsRef.current = null } if (audioRef.current) { audioRef.current.src = "" } onStateChange.current?.("stopped") }, []) const setVolume = useCallback((volume: number) => { if (audioRef.current) { audioRef.current.volume = volume } }, []) const setStateChange = useCallback((handler: (state: "playing" | "paused" | "stopped" | "error") => void) => { onStateChange.current = handler }, []) useEffect(() => { return () => { if (hlsRef.current) { hlsRef.current.destroy() hlsRef.current = null } } }, []) return { audioRef, play, pause, stop, setVolume, setStateChange } }