# Static Player Debug Analysis ## Issue Identified - Player button appears in UI - Playback stops when changing views - State handling errors suspected ## Architecture Review ### Current Flow Analysis #### 1. State Initialization - `useWaveform.ts` creates WaveSurfer instance - Global store initialized with default values - State sync happens in useEffect #### 2. Playback State Issues - WaveSurfer instance destroyed when component unmounts - Global state may not be properly restored - Audio context issues when switching routes #### 3. Potential Weak Points ### Weak Point 1: Waveform Destruction **Location**: `useWaveform.ts` cleanup function ```typescript return () => { ws.destroy(); // This destroys the audio context wsRef.current = null; }; ``` **Issue**: When navigating away, the WaveSurfer instance is destroyed, stopping playback completely. ### Weak Point 2: State Restoration Logic **Location**: `useWaveform.ts` ready event handler ```typescript // Only restores if same song AND same band AND was playing if (options.songId && options.bandId && currentSongId === options.songId && globalBandId === options.bandId && globalIsPlaying) { ws.play(); // This may not work if audio context is suspended } ``` **Issue**: Audio context may be suspended after route change, requiring user interaction to resume. ### Weak Point 3: Global State Sync Timing **Location**: State updates in audioprocess event ```typescript ws.on("audioprocess", (time) => { setCurrentTime(time); setGlobalCurrentTime(time); options.onTimeUpdate?.(time); }); ``` **Issue**: Local state updates may not properly sync with global state during route transitions. ### Weak Point 4: Component Lifecycle **Issue**: SongPage component unmounts → waveform destroyed → state lost → new component mounts with fresh state. ## Root Cause Analysis ### Primary Issue: Audio Context Lifecycle 1. WaveSurfer creates an AudioContext 2. When component unmounts, AudioContext is destroyed 3. New component creates new AudioContext 4. Browser requires user interaction to resume suspended audio contexts 5. Even if we restore state, audio won't play without user interaction ### Secondary Issue: State Restoration Timing 1. Global state may be updated after component unmounts 2. New component may mount before global state is fully updated 3. Race condition in state restoration ## Solution Architecture ### Option 1: Persistent Audio Context (Recommended) - Move WaveSurfer instance outside React component lifecycle - Create singleton audio service - Maintain audio context across route changes - Use global state only for UI synchronization ### Option 2: Audio Context Recovery - Handle suspended audio context states - Add user interaction requirement handling - Implement graceful degradation ### Option 3: Hybrid Approach - Keep minimal global state for navigation - Create persistent audio manager - Sync between audio manager and React components ## Implementation Plan for Fix ### Step 1: Create Audio Service (New File) ```typescript // web/src/services/audioService.ts class AudioService { private static instance: AudioService; private wavesurfer: WaveSurfer | null = null; private audioContext: AudioContext | null = null; private constructor() {} public static getInstance() { if (!this.instance) { this.instance = new AudioService(); } return this.instance; } public initialize(container: HTMLElement, url: string) { // Create wavesurfer with persistent audio context } public play() { // Handle suspended audio context if (this.audioContext?.state === 'suspended') { this.audioContext.resume(); } this.wavesurfer?.play(); } public cleanup() { // Don't destroy audio context, just disconnect nodes } } ``` ### Step 2: Modify Waveform Hook - Use audio service instead of local WaveSurfer instance - Sync service state with global store - Handle component mount/unmount gracefully ### Step 3: Update Global State Management - Separate audio state from UI state - Add audio context status tracking - Implement proper error handling ### Step 4: Add User Interaction Handling - Detect suspended audio context - Provide UI feedback - Handle resume on user interaction ## Debugging Steps ### 1. Verify Current Behavior ```bash # Check browser console for audio context errors # Look for "play() failed because the user didn't interact with the document first" ``` ### 2. Add Debug Logging ```typescript // Add to useWaveform.ts console.log('Waveform ready, attempting to restore state:', { currentSongId, globalBandId, globalIsPlaying, globalCurrentTime }); // Add audio context state logging console.log('Audio context state:', ws.backend.getAudioContext().state); ``` ### 3. Test State Restoration - Start playback - Navigate away - Check global store state in Redux devtools - Navigate back - Verify state is restored correctly ## Recommended Fix Strategy ### Short-term Fix (Quick Implementation) 1. Modify `useWaveform.ts` to handle suspended audio context 2. Add user interaction requirement detection 3. Implement graceful fallback when audio context is suspended ### Long-term Fix (Robust Solution) 1. Create persistent audio service 2. Separate audio management from React components 3. Implement proper audio context lifecycle management 4. Add comprehensive error handling ## Next Steps 1. Add debug logging to identify exact failure point 2. Implement suspended audio context handling 3. Test state restoration with debug logs 4. Implement persistent audio service if needed