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

@@ -54,7 +54,7 @@ export function useAudio() {
globalAudioContext = new AudioContext()
audioContext.value = globalAudioContext
}
if (globalAudioContext.state === 'suspended') {
try {
await globalAudioContext.resume()
@@ -62,6 +62,20 @@ export function useAudio() {
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
@@ -94,8 +108,7 @@ export function useAudio() {
try {
console.log('Starting to load all sounds...')
soundsLoaded = true
// Load basic sounds
const basicSounds = {
intro: '/sounds/intro.wav',
@@ -135,22 +148,30 @@ export function useAudio() {
}
}
soundsLoaded = true
console.log('All sounds loaded and ready to play')
} catch (error) {
console.error('Error loading sounds:', error)
// Don't set soundsLoaded so a retry can happen on next play attempt
}
}
// Play a sound buffer
const playSoundBuffer = async (buffer: AudioBuffer) => {
if (!appStore.settings.soundEnabled) return
try {
await initAudioContext()
if (!globalAudioContext) {
console.error('AudioContext not initialized')
return
}
// If AudioContext exists but sounds never loaded successfully, retry
if (!soundsLoaded) {
await loadAllSounds()
}
const source = globalAudioContext.createBufferSource()
source.buffer = buffer
source.connect(globalAudioContext.destination)
@@ -411,17 +432,22 @@ export function useAudio() {
audioSystemInitialized = true
// 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 () => {
// 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...')
await initAudioOnUserGesture()
await loadAllSounds() // Load sounds after user interaction
console.log('Audio system initialized')
document.removeEventListener('click', initializeAudio)
document.removeEventListener('keydown', initializeAudio)
}
document.addEventListener('click', initializeAudio, { once: true })
document.addEventListener('keydown', initializeAudio, { once: true })
for (const event of gestureEvents) {
document.addEventListener(event, initializeAudio)
}
// Initialize voices for speech synthesis
if ('speechSynthesis' in window) {