fix(voice): audio unlock на тапе → TTS играет на Android
All checks were successful
Deploy / deploy (push) Successful in 2m1s

Android Chrome требует user-gesture для <audio>.play(). Wake-word
триггерит TTS «сам», без тапа, поэтому play() тихо отвергался.

При тапе на кнопку микрофона теперь проигрываем 1мс silent WAV →
браузер помечает страницу как разрешённую для autoplay в текущей
сессии. Дальше TTS-ответы Cosmo/Lusya играют без проблем.

В VoiceOverlay логируем причину если play() всё ещё отвергнут.
This commit is contained in:
Cosmo
2026-04-27 11:12:27 +00:00
parent f74b10ba38
commit 6c3992bb4e
2 changed files with 17 additions and 1 deletions

View File

@@ -178,6 +178,21 @@ export default function VoiceController() {
if (state !== 'idle' && state !== 'error') return
setState('loading')
// 0. «Audio unlock» — Android Chrome не даёт <audio>.play() без user-gesture.
// Wake-word срабатывает сам, поэтому позже play() будет тихо отвергнут.
// Проигрываем 1мс silent WAV прямо сейчас (user тапнул кнопку → есть gesture).
try {
const silent = new Audio(
'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA',
)
silent.volume = 0
await silent.play()
silent.pause()
console.log('[voice] audio unlock ok')
} catch (e: any) {
console.warn('[voice] audio unlock failed:', e?.message)
}
// 1. Запрос разрешения на микрофон отдельно
try {
const probe = await navigator.mediaDevices.getUserMedia({ audio: true })

View File

@@ -93,7 +93,8 @@ export default function VoiceOverlay() {
audioRef.current = audio
try {
await audio.play()
} catch {
} catch (e: any) {
console.warn('[voice] audio.play() rejected:', e?.name || e?.message || e)
finish()
}
} catch {