import { ref, readonly } from 'vue' const VOLUME_KEY = 'fa_voice_volume' // Shared volume across all instances — persisted to localStorage per device const _volume = ref(parseFloat(localStorage.getItem(VOLUME_KEY) ?? '1.0')) export function useVoiceAudio() { const playing = ref(false) const isSupported = typeof AudioContext !== 'undefined' || typeof (window as unknown as Record).webkitAudioContext !== 'undefined' let audioCtx: AudioContext | null = null let currentSource: AudioBufferSourceNode | null = null function _getCtx(): AudioContext { if (!audioCtx || audioCtx.state === 'closed') { const Ctx = window.AudioContext ?? (window as unknown as Record).webkitAudioContext audioCtx = new Ctx() } return audioCtx } async function play(blob: Blob): Promise { stop() const ctx = _getCtx() if (ctx.state === 'suspended') await ctx.resume() const arrayBuffer = await blob.arrayBuffer() const audioBuffer = await ctx.decodeAudioData(arrayBuffer) const source = ctx.createBufferSource() source.buffer = audioBuffer const gain = ctx.createGain() gain.gain.value = _volume.value source.connect(gain) gain.connect(ctx.destination) currentSource = source playing.value = true return new Promise((resolve) => { source.onended = () => { playing.value = false currentSource = null resolve() } source.start(0) }) } function stop(): void { if (currentSource) { try { currentSource.stop() } catch { /* already stopped */ } currentSource = null } playing.value = false } return { playing: readonly(playing), volume: _volume, isSupported, play, stop, } } export function setVoiceVolume(v: number) { _volume.value = Math.max(0, Math.min(1, v)) localStorage.setItem(VOLUME_KEY, String(_volume.value)) }