fix: add delay after AudioContext resume and schedule offset

This commit is contained in:
Mikhail Kiselev
2026-02-10 17:48:34 +03:00
parent 482786a34b
commit 6dac14e0c1
2 changed files with 23 additions and 9 deletions

View File

@@ -124,6 +124,8 @@
const ctx = getAudioContext() const ctx = getAudioContext()
if (ctx.state === 'suspended') { if (ctx.state === 'suspended') {
await ctx.resume() await ctx.resume()
// Wait a frame for currentTime to update after resume
await new Promise(resolve => setTimeout(resolve, 50))
} }
const oscillator = ctx.createOscillator() const oscillator = ctx.createOscillator()
const gainNode = ctx.createGain() const gainNode = ctx.createGain()
@@ -134,11 +136,13 @@
oscillator.frequency.value = frequency oscillator.frequency.value = frequency
oscillator.type = type oscillator.type = type
gainNode.gain.setValueAtTime(0.3, ctx.currentTime) // Use small offset to ensure sound is scheduled in the future
gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + duration) const startTime = ctx.currentTime + 0.01
gainNode.gain.setValueAtTime(0.3, startTime)
gainNode.gain.exponentialRampToValueAtTime(0.01, startTime + duration)
oscillator.start(ctx.currentTime) oscillator.start(startTime)
oscillator.stop(ctx.currentTime + duration) oscillator.stop(startTime + duration)
} catch (e) { } catch (e) {
console.error('Failed to play sound:', e) console.error('Failed to play sound:', e)
} }
@@ -166,7 +170,13 @@
} }
} }
function handleMeetingStarted() { async function handleMeetingStarted() {
// Pre-initialize AudioContext on user gesture (meeting start click)
// This is required because AudioContext can only be resumed during user interaction
const ctx = getAudioContext()
if (ctx.state === 'suspended') {
await ctx.resume()
}
meetingActive = true meetingActive = true
currentView = 'main' currentView = 'main'
} }

View File

@@ -46,6 +46,8 @@
// Resume context if suspended (required by browsers on first interaction) // Resume context if suspended (required by browsers on first interaction)
if (ctx.state === 'suspended') { if (ctx.state === 'suspended') {
await ctx.resume() await ctx.resume()
// Wait a frame for currentTime to update after resume
await new Promise(resolve => setTimeout(resolve, 50))
} }
const oscillator = ctx.createOscillator() const oscillator = ctx.createOscillator()
const gainNode = ctx.createGain() const gainNode = ctx.createGain()
@@ -56,11 +58,13 @@
oscillator.frequency.value = frequency oscillator.frequency.value = frequency
oscillator.type = type oscillator.type = type
gainNode.gain.setValueAtTime(0.3, ctx.currentTime) // Use small offset to ensure sound is scheduled in the future
gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + duration) const startTime = ctx.currentTime + 0.01
gainNode.gain.setValueAtTime(0.3, startTime)
gainNode.gain.exponentialRampToValueAtTime(0.01, startTime + duration)
oscillator.start(ctx.currentTime) oscillator.start(startTime)
oscillator.stop(ctx.currentTime + duration) oscillator.stop(startTime + duration)
} catch (e) { } catch (e) {
console.error('Failed to play sound:', e) console.error('Failed to play sound:', e)
alert('Sound error: ' + e.message) alert('Sound error: ' + e.message)