From 6dac14e0c14b6ca7fd45eb1bc3ab3c4d178ce8f5 Mon Sep 17 00:00:00 2001 From: Mikhail Kiselev Date: Tue, 10 Feb 2026 17:48:34 +0300 Subject: [PATCH] fix: add delay after AudioContext resume and schedule offset --- frontend/src/App.svelte | 20 +++++++++++++++----- frontend/src/components/Settings.svelte | 12 ++++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 8050b49..28a4720 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -124,6 +124,8 @@ const ctx = getAudioContext() if (ctx.state === 'suspended') { await ctx.resume() + // Wait a frame for currentTime to update after resume + await new Promise(resolve => setTimeout(resolve, 50)) } const oscillator = ctx.createOscillator() const gainNode = ctx.createGain() @@ -134,11 +136,13 @@ oscillator.frequency.value = frequency oscillator.type = type - gainNode.gain.setValueAtTime(0.3, ctx.currentTime) - gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + duration) + // Use small offset to ensure sound is scheduled in the future + const startTime = ctx.currentTime + 0.01 + gainNode.gain.setValueAtTime(0.3, startTime) + gainNode.gain.exponentialRampToValueAtTime(0.01, startTime + duration) - oscillator.start(ctx.currentTime) - oscillator.stop(ctx.currentTime + duration) + oscillator.start(startTime) + oscillator.stop(startTime + duration) } catch (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 currentView = 'main' } diff --git a/frontend/src/components/Settings.svelte b/frontend/src/components/Settings.svelte index 1e921c7..c6374f8 100644 --- a/frontend/src/components/Settings.svelte +++ b/frontend/src/components/Settings.svelte @@ -46,6 +46,8 @@ // Resume context if suspended (required by browsers on first interaction) if (ctx.state === 'suspended') { await ctx.resume() + // Wait a frame for currentTime to update after resume + await new Promise(resolve => setTimeout(resolve, 50)) } const oscillator = ctx.createOscillator() const gainNode = ctx.createGain() @@ -56,11 +58,13 @@ oscillator.frequency.value = frequency oscillator.type = type - gainNode.gain.setValueAtTime(0.3, ctx.currentTime) - gainNode.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + duration) + // Use small offset to ensure sound is scheduled in the future + const startTime = ctx.currentTime + 0.01 + gainNode.gain.setValueAtTime(0.3, startTime) + gainNode.gain.exponentialRampToValueAtTime(0.01, startTime + duration) - oscillator.start(ctx.currentTime) - oscillator.stop(ctx.currentTime + duration) + oscillator.start(startTime) + oscillator.stop(startTime + duration) } catch (e) { console.error('Failed to play sound:', e) alert('Sound error: ' + e.message)