UNPKG

web-asr-core

Version:

WebASR Core - Browser-based speech processing with VAD, WakeWord and Whisper - Unified all-in-one version

363 lines 9.95 kB
/** * TimerService - 計時器服務類別(Event Architecture v2) * * 提供事件驅動的計時器管理服務 * 支援多個計時器的並行管理和事件通知 */ import { EventEmitter } from '../core/EventEmitter'; import { Timer } from './timer'; /** * TimerService - 事件驅動的計時器服務 * * @example * ```typescript * const timerService = new TimerService(); * * // 訂閱事件 * timerService.on('timeout', ({ id, duration }) => { * console.log(`Timer ${id} timeout after ${duration}ms`); * }); * * timerService.on('tick', ({ id, remaining, progress }) => { * console.log(`Timer ${id}: ${remaining}ms remaining (${progress}%)`); * }); * * // 創建並啟動計時器 * timerService.createTimer('speech-timeout', 5000); * timerService.start('speech-timeout'); * * // 暫停和恢復 * timerService.pause('speech-timeout'); * timerService.resume('speech-timeout'); * * // 重置計時器 * timerService.reset('speech-timeout', 10000); * ``` */ export class TimerService extends EventEmitter { timers = new Map(); constructor() { super(); // 發射 ready 事件 setTimeout(() => { this.emit('ready', { timestamp: Date.now() }); }, 0); } /** * 創建新的計時器 * @param id 計時器 ID * @param duration 持續時間(毫秒) * @param tickInterval tick 間隔(毫秒,預設 100) * @param onTimeout 超時回調函數(可選) */ createTimer(id, duration, tickInterval = 100, onTimeout) { try { // 如果計時器已存在,先停止它 if (this.timers.has(id)) { this.stop(id); } // 創建新的計時器狀態 const state = Timer.createState(duration); this.timers.set(id, { state, tickInterval, onTimeout }); } catch (error) { this.emit('error', { error: error, context: 'createTimer', timerId: id, timestamp: Date.now() }); throw error; } } /** * 啟動計時器 * @param id 計時器 ID */ start(id) { const timer = this.timers.get(id); if (!timer) { throw new Error(`Timer not found: ${id}`); } try { // 啟動計時器 timer.state = Timer.start(timer.state); // 發射 start 事件 this.emit('start', { id, duration: timer.state.totalTime, timestamp: Date.now() }); // 清除舊的 interval(如果存在) if (timer.interval) { clearInterval(timer.interval); } // 設置新的 tick interval timer.interval = setInterval(() => { this.processTick(id); }, timer.tickInterval); } catch (error) { this.emit('error', { error: error, context: 'start', timerId: id, timestamp: Date.now() }); throw error; } } /** * 處理計時器 tick * @param id 計時器 ID */ processTick(id) { const timer = this.timers.get(id); if (!timer || !timer.state.isRunning) { return; } try { // 更新計時器狀態 const result = Timer.tick(timer.state); timer.state = result.state; // 計算相關數值 const remaining = Timer.getRemainingTime(timer.state); const progress = Timer.getProgress(timer.state); const elapsed = timer.state.totalTime - remaining; // 發射 tick 事件 this.emit('tick', { id, remaining, progress, elapsed, timestamp: Date.now() }); // 檢查是否超時 if (result.timeout) { this.emit('timeout', { id, duration: timer.state.totalTime, timestamp: Date.now() }); // 呼叫超時回調 timer.onTimeout?.(); // 停止計時器 this.stop(id); } } catch (error) { this.emit('error', { error: error, context: 'tick', timerId: id, timestamp: Date.now() }); } } /** * 暫停計時器 * @param id 計時器 ID */ pause(id) { const timer = this.timers.get(id); if (!timer) { return; } try { // 暫停計時器 timer.state = Timer.pause(timer.state); // 清除 interval if (timer.interval) { clearInterval(timer.interval); timer.interval = undefined; } // 發射 pause 事件 this.emit('pause', { id, remaining: Timer.getRemainingTime(timer.state), timestamp: Date.now() }); } catch (error) { this.emit('error', { error: error, context: 'pause', timerId: id, timestamp: Date.now() }); } } /** * 恢復計時器 * @param id 計時器 ID */ resume(id) { const timer = this.timers.get(id); if (!timer) { return; } try { // 發射 resume 事件 this.emit('resume', { id, remaining: Timer.getRemainingTime(timer.state), timestamp: Date.now() }); // 重新啟動計時器 this.start(id); } catch (error) { this.emit('error', { error: error, context: 'resume', timerId: id, timestamp: Date.now() }); } } /** * 重置計時器 * @param id 計時器 ID * @param duration 新的持續時間(可選) */ reset(id, duration) { const timer = this.timers.get(id); if (!timer) { return; } try { // 清除 interval if (timer.interval) { clearInterval(timer.interval); timer.interval = undefined; } // 重置計時器狀態 timer.state = Timer.reset(timer.state, duration); // 發射 reset 事件 this.emit('reset', { id, duration: timer.state.totalTime, timestamp: Date.now() }); } catch (error) { this.emit('error', { error: error, context: 'reset', timerId: id, timestamp: Date.now() }); } } /** * 停止並移除計時器 * @param id 計時器 ID */ stop(id) { const timer = this.timers.get(id); if (!timer) { return; } try { // 清除 interval if (timer.interval) { clearInterval(timer.interval); } // 發射 stop 事件 const elapsed = timer.state.totalTime - Timer.getRemainingTime(timer.state); this.emit('stop', { id, elapsed, timestamp: Date.now() }); // 移除計時器 this.timers.delete(id); } catch (error) { this.emit('error', { error: error, context: 'stop', timerId: id, timestamp: Date.now() }); } } /** * 獲取計時器狀態 * @param id 計時器 ID * @returns 計時器狀態或 undefined */ getTimerState(id) { return this.timers.get(id)?.state; } /** * 獲取計時器剩餘時間 * @param id 計時器 ID * @returns 剩餘時間(毫秒)或 undefined */ getRemainingTime(id) { const timer = this.timers.get(id); if (!timer) return undefined; return Timer.getRemainingTime(timer.state); } /** * 獲取計時器進度 * @param id 計時器 ID * @returns 進度(0-100)或 undefined */ getProgress(id) { const timer = this.timers.get(id); if (!timer) return undefined; return Timer.getProgress(timer.state); } /** * 檢查計時器是否活動 * @param id 計時器 ID * @returns 是否活動 */ isActive(id) { const timer = this.timers.get(id); return timer ? timer.state.isRunning : false; } /** * 檢查計時器是否暫停 * @param id 計時器 ID * @returns 是否暫停 */ isPaused(id) { const timer = this.timers.get(id); return timer ? (timer.state.pausedAt !== undefined) : false; } /** * 獲取所有計時器 ID * @returns 計時器 ID 陣列 */ getAllTimerIds() { return Array.from(this.timers.keys()); } /** * 停止所有計時器 */ stopAll() { for (const id of this.timers.keys()) { this.stop(id); } } /** * 清理資源 */ dispose() { // 停止所有計時器 this.stopAll(); // 清除所有監聽器 this.removeAllListeners(); } } export default TimerService; //# sourceMappingURL=TimerService.js.map