This commit is contained in:
2026-10-12 14:58:24 +07:00
parent 8f54434757
commit 4a89dd1d74
2 changed files with 20 additions and 19 deletions
Binary file not shown.
+20 -19
View File
@@ -44,6 +44,7 @@ import type {
TeamResult,
Ticket,
} from '@/api/generated/crabs/evening_detective_server'
import notificationSoundURL from '@/assets/icq-uh-oh.wav'
import GameMapPanel from '@/components/GameMapPanel.vue'
import GameScreensPanel from '@/components/GameScreensPanel.vue'
import GameStatePanel from '@/components/GameStatePanel.vue'
@@ -134,6 +135,7 @@ let appliedGameRequestVersion = 0
let hasLoadedGame = false
let isDisposed = false
let notificationAudio: AudioContext | undefined
let notificationSound: Promise<AudioBuffer> | undefined
let hasReportedSoundError = false
const canViewState = computed(
() =>
@@ -239,30 +241,29 @@ async function enableNotificationSound() {
try {
notificationAudio ??= new AudioContext()
if (notificationAudio.state === 'suspended') await notificationAudio.resume()
const audio = notificationAudio
notificationSound ??= fetch(notificationSoundURL).then(async (response) => {
if (!response.ok) throw new Error('Не удалось загрузить звук уведомления')
return audio.decodeAudioData(await response.arrayBuffer())
})
await notificationSound
} catch (error) {
notificationSound = undefined
reportSoundError(error)
}
}
function playApplicationNotification() {
async function playApplicationNotification() {
// До первого взаимодействия браузер блокирует звук; пропущенные сигналы не накапливаем.
if (!notificationAudio || notificationAudio.state !== 'running') return
if (!notificationAudio || notificationAudio.state !== 'running' || !notificationSound) return
try {
const oscillator = notificationAudio.createOscillator()
const gain = notificationAudio.createGain()
const now = notificationAudio.currentTime
oscillator.frequency.value = 880
gain.gain.setValueAtTime(0, now)
gain.gain.linearRampToValueAtTime(0.1, now + 0.02)
gain.gain.linearRampToValueAtTime(0, now + 0.3)
oscillator.connect(gain)
gain.connect(notificationAudio.destination)
oscillator.onended = () => {
oscillator.disconnect()
gain.disconnect()
}
oscillator.start(now)
oscillator.stop(now + 0.3)
const buffer = await notificationSound
if (isDisposed || notificationAudio.state !== 'running') return
const source = notificationAudio.createBufferSource()
source.buffer = buffer
source.connect(notificationAudio.destination)
source.onended = () => source.disconnect()
source.start()
} catch (error) {
reportSoundError(error)
}
@@ -270,7 +271,7 @@ function playApplicationNotification() {
async function testNotificationSound() {
await enableNotificationSound()
playApplicationNotification()
await playApplicationNotification()
}
onMounted(() => {
@@ -303,7 +304,7 @@ async function getGame(id: number) {
hasLoadedGame &&
hasNewTeamApplications(game.value.teams || [], res.game?.teams || [])
) {
playApplicationNotification()
void playApplicationNotification()
}
hasLoadedGame = true
game.value = res.game!