'use client'; import * as React from 'react'; import { AudioPlayer } from '@/lib/audio/player'; import { decodeAudioFile, formatDuration } from '@/lib/audio/decoder'; export interface UseAudioPlayerReturn { // File management loadFile: (file: File) => Promise; loadBuffer: (buffer: AudioBuffer, name?: string) => void; clearFile: () => void; // Playback controls play: () => Promise; pause: () => void; stop: () => void; seek: (time: number, autoPlay?: boolean) => Promise; // Volume control setVolume: (volume: number) => void; // State isPlaying: boolean; isPaused: boolean; currentTime: number; duration: number; volume: number; audioBuffer: AudioBuffer | null; fileName: string | null; isLoading: boolean; error: string | null; // Formatted values currentTimeFormatted: string; durationFormatted: string; } export function useAudioPlayer(): UseAudioPlayerReturn { const [player, setPlayer] = React.useState(null); const [isPlaying, setIsPlaying] = React.useState(false); const [isPaused, setIsPaused] = React.useState(false); const [currentTime, setCurrentTime] = React.useState(0); const [duration, setDuration] = React.useState(0); const [volume, setVolumeState] = React.useState(1); const [audioBuffer, setAudioBuffer] = React.useState(null); const [fileName, setFileName] = React.useState(null); const [isLoading, setIsLoading] = React.useState(false); const [error, setError] = React.useState(null); // Initialize player on client side only React.useEffect(() => { if (typeof window !== 'undefined') { setPlayer(new AudioPlayer()); } }, []); // Update current time while playing React.useEffect(() => { if (!isPlaying || !player) return; const interval = setInterval(() => { const state = player.getState(); setCurrentTime(state.currentTime); // Stop when reaching the end if (state.currentTime >= state.duration) { setIsPlaying(false); setIsPaused(false); setCurrentTime(0); } }, 50); // Update 20 times per second return () => clearInterval(interval); }, [isPlaying, player]); const loadFile = React.useCallback( async (file: File) => { if (!player) return; setIsLoading(true); setError(null); try { const buffer = await decodeAudioFile(file); player.loadBuffer(buffer); setAudioBuffer(buffer); setFileName(file.name); setDuration(buffer.duration); setCurrentTime(0); setIsPlaying(false); setIsPaused(false); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load audio file'); console.error('Error loading audio file:', err); } finally { setIsLoading(false); } }, [player] ); const loadBuffer = React.useCallback( (buffer: AudioBuffer, name?: string) => { if (!player) return; player.loadBuffer(buffer); setAudioBuffer(buffer); if (name) setFileName(name); setDuration(buffer.duration); setCurrentTime(0); setIsPlaying(false); setIsPaused(false); }, [player] ); const clearFile = React.useCallback(() => { if (!player) return; player.stop(); setAudioBuffer(null); setFileName(null); setDuration(0); setCurrentTime(0); setIsPlaying(false); setIsPaused(false); setError(null); }, [player]); const play = React.useCallback(async () => { if (!player) return; try { await player.play(); setIsPlaying(true); setIsPaused(false); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to play audio'); console.error('Error playing audio:', err); } }, [player]); const pause = React.useCallback(() => { if (!player) return; player.pause(); setIsPlaying(false); setIsPaused(true); }, [player]); const stop = React.useCallback(() => { if (!player) return; player.stop(); setIsPlaying(false); setIsPaused(false); setCurrentTime(0); }, [player]); const seek = React.useCallback( async (time: number, autoPlay: boolean = false) => { if (!player) return; await player.seek(time, autoPlay); setCurrentTime(time); // Update state based on what actually happened const state = player.getState(); setIsPlaying(state.isPlaying); setIsPaused(state.isPaused); }, [player] ); const setVolume = React.useCallback( (vol: number) => { if (!player) return; player.setVolume(vol); setVolumeState(vol); }, [player] ); // Cleanup on unmount React.useEffect(() => { return () => { if (player) { player.dispose(); } }; }, [player]); return { loadFile, loadBuffer, clearFile, play, pause, stop, seek, setVolume, isPlaying, isPaused, currentTime, duration, volume, audioBuffer, fileName, isLoading, error, currentTimeFormatted: formatDuration(currentTime), durationFormatted: formatDuration(duration), }; }