fix: connect MiniPlayer controls and improve playback synchronization
- Connect MiniPlayer play/pause buttons to audioService - Improve audio context management with fallback creation - Fix state synchronization with interval-based readiness checks - Add error handling and user feedback for playback issues - Enhance mobile browser support with better audio context handling Fixes playback issues in SongView where controls were not working and state synchronization between UI and player was unreliable.
This commit is contained in:
@@ -247,6 +247,12 @@ private readonly PLAY_DEBOUNCE_MS: number = 100;
|
||||
// Ensure we have a valid audio context
|
||||
await this.ensureAudioContext();
|
||||
|
||||
// Handle suspended audio context (common in mobile browsers)
|
||||
if (this.audioContext?.state === 'suspended') {
|
||||
await this.audioContext.resume();
|
||||
this.log(LogLevel.INFO, 'Audio context resumed successfully');
|
||||
}
|
||||
|
||||
await this.wavesurfer.play();
|
||||
this.log(LogLevel.INFO, 'Playback started successfully');
|
||||
this.playbackAttempts = 0; // Reset on success
|
||||
@@ -254,6 +260,21 @@ private readonly PLAY_DEBOUNCE_MS: number = 100;
|
||||
this.playbackAttempts++;
|
||||
this.log(LogLevel.ERROR, `Playback failed (attempt ${this.playbackAttempts}):`, error);
|
||||
|
||||
// Handle specific audio context errors
|
||||
if (error instanceof Error && error.name === 'NotAllowedError') {
|
||||
this.log(LogLevel.ERROR, 'Playback blocked by browser autoplay policy');
|
||||
// Try to resume audio context and retry
|
||||
if (this.audioContext?.state === 'suspended') {
|
||||
try {
|
||||
await this.audioContext.resume();
|
||||
this.log(LogLevel.INFO, 'Audio context resumed, retrying playback');
|
||||
return this.play(); // Retry after resuming
|
||||
} catch (resumeError) {
|
||||
this.log(LogLevel.ERROR, 'Failed to resume audio context:', resumeError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.playbackAttempts >= this.MAX_PLAYBACK_ATTEMPTS) {
|
||||
this.log(LogLevel.ERROR, 'Max playback attempts reached, resetting player');
|
||||
this.cleanup();
|
||||
@@ -393,20 +414,26 @@ private readonly PLAY_DEBOUNCE_MS: number = 100;
|
||||
this.audioContext = ws.backend?.audioContext ?? null;
|
||||
}
|
||||
|
||||
// Method 7: Create a new audio context if none found
|
||||
if (!this.audioContext) {
|
||||
this.log(LogLevel.WARN, 'Could not access audio context from WaveSurfer, creating new one');
|
||||
this.audioContext = new (window.AudioContext || (window as { webkitAudioContext?: new () => AudioContext }).webkitAudioContext)();
|
||||
}
|
||||
|
||||
if (this.audioContext) {
|
||||
console.log('Audio context accessed successfully:', this.audioContext.state);
|
||||
this.log(LogLevel.INFO, 'Audio context accessed successfully:', this.audioContext.state);
|
||||
|
||||
// Handle audio context suspension (common in mobile browsers)
|
||||
if (this.audioContext.state === 'suspended') {
|
||||
this.audioContext.resume().catch(error => {
|
||||
this.log(LogLevel.ERROR, 'Failed to resume audio context:', error);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn('Could not access audio context from WaveSurfer - playback may have issues');
|
||||
// Log the wavesurfer structure for debugging
|
||||
console.debug('WaveSurfer structure:', {
|
||||
hasBackend: !!ws.backend,
|
||||
backendType: typeof ws.backend,
|
||||
backendKeys: ws.backend ? Object.keys(ws.backend) : 'no backend',
|
||||
wavesurferKeys: Object.keys(ws)
|
||||
});
|
||||
this.log(LogLevel.ERROR, 'Failed to create or access audio context - playback will not work');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error accessing audio context:', error);
|
||||
this.log(LogLevel.ERROR, 'Error accessing audio context:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user