import { onUnmounted } from 'vue' const VOICE_BASE = '/static/training/voice' export type VoicePromptKey = | 'start' | 'ready' | 'rest' | 'next-set' | 'last-rep' | 'keep-it-up' | 'good-job' | 'breathe-in' | 'breathe-out' export interface UseVoiceCoachOptions { enabled?: boolean volume?: number } export function useVoiceCoach(options: UseVoiceCoachOptions = {}) { const { enabled = true, volume = 1 } = options let ctx: UniApp.InnerAudioContext | null = null let queue: string[] = [] let isPlayingQueue = false const ensureCtx = () => { if (ctx) return ctx = uni.createInnerAudioContext() ctx.volume = volume ctx.obeyMuteSwitch = false ctx.onEnded(() => { playNextInQueue() }) ctx.onError(() => { playNextInQueue() }) } const playNextInQueue = () => { if (!ctx || queue.length === 0) { isPlayingQueue = false return } const nextSrc = queue.shift()! ctx.src = nextSrc ctx.play() } const enqueue = (src: string) => { if (!enabled) return ensureCtx() queue.push(src) if (!isPlayingQueue) { isPlayingQueue = true playNextInQueue() } } const speakNumber = (n: number) => { if (n < 1 || n > 30) return enqueue(`${VOICE_BASE}/numbers/${n}.mp3`) } const speakPrompt = (key: VoicePromptKey) => { enqueue(`${VOICE_BASE}/prompts/${key}.mp3`) } const stop = () => { queue = [] isPlayingQueue = false ctx?.stop() } onUnmounted(() => { stop() ctx?.destroy?.() ctx = null }) return { speakNumber, speakPrompt, stop, } }