Attempt to fix audio playing on iOS

This commit is contained in:
2026-02-17 11:19:51 +01:00
parent 9ea94e0e31
commit b5d4a6ab76

View File

@@ -62,6 +62,20 @@ export function useAudio() {
console.warn('AudioContext resume failed, user interaction required:', error) console.warn('AudioContext resume failed, user interaction required:', error)
} }
} }
// Play a silent buffer to truly unlock AudioContext on iOS PWA
// On iOS, resume() alone is insufficient — audio must be routed through the context during a user gesture
if (globalAudioContext.state === 'running') {
try {
const silentBuffer = globalAudioContext.createBuffer(1, 1, 22050)
const source = globalAudioContext.createBufferSource()
source.buffer = silentBuffer
source.connect(globalAudioContext.destination)
source.start(0)
} catch (error) {
console.warn('Silent buffer unlock failed:', error)
}
}
} }
// Load a single sound file // Load a single sound file
@@ -94,7 +108,6 @@ export function useAudio() {
try { try {
console.log('Starting to load all sounds...') console.log('Starting to load all sounds...')
soundsLoaded = true
// Load basic sounds // Load basic sounds
const basicSounds = { const basicSounds = {
@@ -135,9 +148,11 @@ export function useAudio() {
} }
} }
soundsLoaded = true
console.log('All sounds loaded and ready to play') console.log('All sounds loaded and ready to play')
} catch (error) { } catch (error) {
console.error('Error loading sounds:', error) console.error('Error loading sounds:', error)
// Don't set soundsLoaded so a retry can happen on next play attempt
} }
} }
@@ -151,6 +166,12 @@ export function useAudio() {
console.error('AudioContext not initialized') console.error('AudioContext not initialized')
return return
} }
// If AudioContext exists but sounds never loaded successfully, retry
if (!soundsLoaded) {
await loadAllSounds()
}
const source = globalAudioContext.createBufferSource() const source = globalAudioContext.createBufferSource()
source.buffer = buffer source.buffer = buffer
source.connect(globalAudioContext.destination) source.connect(globalAudioContext.destination)
@@ -411,17 +432,22 @@ export function useAudio() {
audioSystemInitialized = true audioSystemInitialized = true
// Set up user gesture listeners to initialize audio and load sounds // Set up user gesture listeners to initialize audio and load sounds
// Include touchstart for iOS PWA standalone mode where it fires before click
const gestureEvents = ['click', 'keydown', 'touchstart'] as const
const initializeAudio = async () => { const initializeAudio = async () => {
// Remove all gesture listeners immediately so this only fires once
for (const event of gestureEvents) {
document.removeEventListener(event, initializeAudio)
}
console.log('User interaction detected, initializing audio system...') console.log('User interaction detected, initializing audio system...')
await initAudioOnUserGesture() await initAudioOnUserGesture()
await loadAllSounds() // Load sounds after user interaction await loadAllSounds() // Load sounds after user interaction
console.log('Audio system initialized') console.log('Audio system initialized')
document.removeEventListener('click', initializeAudio)
document.removeEventListener('keydown', initializeAudio)
} }
document.addEventListener('click', initializeAudio, { once: true }) for (const event of gestureEvents) {
document.addEventListener('keydown', initializeAudio, { once: true }) document.addEventListener(event, initializeAudio)
}
// Initialize voices for speech synthesis // Initialize voices for speech synthesis
if ('speechSynthesis' in window) { if ('speechSynthesis' in window) {