-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
播放器引擎 V3 技术规范
📋 目录
1. 概述
1.1 项目背景
当前播放器引擎(V2)存在以下问题:
- 复杂的意图系统导致维护困难
- 分散的状态管理增加调试复杂度
- 六阶段数据流造成性能开销
- 策略系统过于抽象,难以理解
1.2 设计目标
主要目标:
- 🎯 简化架构: 使用状态机统一管理播放逻辑
- 🔍 提高可调试性: 状态转换路径清晰,易于追踪
- ⚡ 优化性能: 减少不必要的计算和状态检查
- 🛠 增强可维护性: 代码结构清晰,职责分离明确
次要目标:
- 保持向后兼容性
- 支持渐进式迁移
- 提供更好的开发体验
1.3 核心原则
- 单一职责原则: 每个组件只负责一个特定功能
- 状态驱动: 所有播放行为由状态机驱动
- 事件驱动: 通过事件进行组件间通信
- 可预测性: 相同输入产生相同输出
- 可测试性: 所有组件都能独立测试
2. 架构设计
2.1 整体架构
┌─────────────────────────────────────────────────────────────┐
│ 播放器引擎 V3 │
├─────────────────────────────────────────────────────────────┤
│ 用户接口层 (Public API) │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ PlayEngine │ │ EventEmitter │ │
│ └─────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 核心状态层 (Core State Layer) │
│ ┌────────────────────┐ ┌─────────────────┐ │
│ │ PlayerStateMachine │ │ StateManager │ │
│ └────────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 功能模块层 (Feature Modules) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
│ │ SentenceManager │ │ LoopManager │ │ AutoController ││
│ └─────────────────┘ └─────────────────┘ └─────────────────┘│
├─────────────────────────────────────────────────────────────┤
│ 控制层 (Control Layer) │
│ ┌──────────────────┐ ┌─────────────────┐ │
│ │PlaybackController│ │ EventHandler │ │
│ └──────────────────┘ └─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 基础设施层 (Infrastructure) │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐│
│ │ MediaClock │ │ Logger │ │ TypeDefs ││
│ └─────────────────┘ └─────────────────┘ └─────────────────┘│
└─────────────────────────────────────────────────────────────┘
2.2 分层职责
| 层级 | 职责 | 组件 |
|---|---|---|
| 用户接口层 | 对外提供统一API | PlayEngine, EventEmitter |
| 核心状态层 | 状态管理和转换 | PlayerStateMachine, StateManager |
| 功能模块层 | 具体业务逻辑 | SentenceManager, LoopManager, AutoController |
| 控制层 | 设备控制和事件处理 | PlaybackController, EventHandler |
| 基础设施层 | 公共服务和工具 | MediaClock, Logger, TypeDefs |
2.3 依赖关系
graph TD
A[PlayEngine] --> B[PlayerStateMachine]
A --> C[EventHandler]
B --> D[StateManager]
B --> E[SentenceManager]
B --> F[LoopManager]
B --> G[AutoController]
C --> H[PlaybackController]
E --> I[MediaClock]
F --> I
G --> I
H --> I
3. 状态机设计
3.1 状态定义
基于提供的状态图,定义以下状态:
enum PlayerState {
// 主要播放状态
PLAYING = 'playing',
PAUSED = 'paused',
USER_PAUSED = 'userPaused',
// 句子生命周期状态
SENTENCE_COMPLETED = 'sentenceCompleted',
// 循环控制状态
CHECK_LOOP = 'checkLoop',
SEEK_TO_START = 'seekToStart',
DECREMENT_LOOP = 'decrementLoop',
CHECK_AUTO_PAUSE_AFTER_LOOP = 'checkAutoPauseAfterLoop',
// 暂停和恢复状态
CHECK_AUTO_PAUSE = 'checkAutoPause',
WAITING_FOR_RESUME = 'waitingForResume',
CHECK_AUTO_RESUME = 'checkAutoResume',
AUTO_RESUMING = 'autoResuming',
MANUAL_RESUMING = 'manualResuming',
CHECK_LOOP_AFTER_RESUME = 'checkLoopAfterResume',
SEEK_TO_START_AFTER_RESUME = 'seekToStartAfterResume',
// 间隙跳跃状态
CHECK_GAP_SKIP = 'checkGapSkip',
DETECT_GAP = 'detectGap',
SKIP_GAP = 'skipGap',
// 用户交互状态
USER_SEEKED = 'userSeeked',
// 终态
COMPLETED = 'completed',
ERROR = 'error'
}3.2 事件定义
enum PlayerEvent {
// 播放控制事件
PLAY = 'PLAY',
PAUSE = 'PAUSE',
TOGGLE_PLAY = 'TOGGLE_PLAY',
SEEK = 'SEEK',
USER_SEEK = 'USER_SEEK',
// 句子生命周期事件
SENTENCE_ENDED = 'SENTENCE_ENDED',
LAST_SENTENCE_ENDED = 'LAST_SENTENCE_ENDED',
// 循环控制事件
LOOP_ENABLED = 'LOOP_ENABLED',
LOOP_DISABLED = 'LOOP_DISABLED',
LOOP_COUNT_ZERO = 'LOOP_COUNT_ZERO',
LOOP_COUNT_POSITIVE = 'LOOP_COUNT_POSITIVE',
INFINITE_LOOP = 'INFINITE_LOOP',
// 自动暂停事件
AUTO_PAUSE_ENABLED = 'AUTO_PAUSE_ENABLED',
AUTO_PAUSE_DISABLED = 'AUTO_PAUSE_DISABLED',
// 自动恢复事件
AUTO_RESUME_ENABLED = 'AUTO_RESUME_ENABLED',
AUTO_RESUME_DISABLED = 'AUTO_RESUME_DISABLED',
AUTO_RESUME_TIMEOUT = 'AUTO_RESUME_TIMEOUT',
MANUAL_RESUME = 'MANUAL_RESUME',
USER_PAUSE_AFTER_RESUME = 'USER_PAUSE_AFTER_RESUME',
// 间隙跳跃事件
GAP_SKIP_ENABLED = 'GAP_SKIP_ENABLED',
GAP_SKIP_DISABLED = 'GAP_SKIP_DISABLED',
LARGE_GAP_DETECTED = 'LARGE_GAP_DETECTED',
NO_GAP_DETECTED = 'NO_GAP_DETECTED',
// 错误和完成事件
PLAYBACK_ERROR = 'PLAYBACK_ERROR',
FILE_ENDED = 'FILE_ENDED'
}3.3 状态转换表
| 当前状态 | 事件 | 下一状态 | 条件 | 动作 |
|---|---|---|---|---|
| PLAYING | SENTENCE_ENDED | SENTENCE_COMPLETED | 当前句播放完成 | updateCurrentSentence |
| SENTENCE_COMPLETED | - | CHECK_LOOP | 自动 | - |
| CHECK_LOOP | LOOP_ENABLED & (LOOP_COUNT_POSITIVE | INFINITE_LOOP) | SEEK_TO_START | 单句循环开启 | - |
| CHECK_LOOP | LOOP_DISABLED | LOOP_COUNT_ZERO | CHECK_AUTO_PAUSE | 循环关闭或次数为0 | - |
| SEEK_TO_START | - | DECREMENT_LOOP | seek完成 | seekToSentenceStart |
| DECREMENT_LOOP | - | CHECK_AUTO_PAUSE_AFTER_LOOP | 次数递减 | decrementLoopCount |
| CHECK_AUTO_PAUSE_AFTER_LOOP | AUTO_PAUSE_ENABLED | PAUSED | 自动暂停开启 | pausePlayback |
| CHECK_AUTO_PAUSE_AFTER_LOOP | AUTO_PAUSE_DISABLED | PLAYING | 自动暂停关闭 | resumePlayback |
| CHECK_AUTO_PAUSE | AUTO_PAUSE_ENABLED | PAUSED | 自动暂停开启 | pausePlayback |
| CHECK_AUTO_PAUSE | AUTO_PAUSE_DISABLED | CHECK_GAP_SKIP | 自动暂停关闭 | - |
| PAUSED | - | WAITING_FOR_RESUME | 自动 | - |
| WAITING_FOR_RESUME | - | CHECK_AUTO_RESUME | 自动 | - |
| CHECK_AUTO_RESUME | AUTO_RESUME_ENABLED | AUTO_RESUMING | 自动恢复开启 | startAutoResumeTimer |
| CHECK_AUTO_RESUME | MANUAL_RESUME | MANUAL_RESUMING | 用户手动恢复 | cancelAutoResumeTimer |
| CHECK_AUTO_RESUME | USER_PAUSE_AFTER_RESUME | USER_PAUSED | 用户暂停 | - |
| AUTO_RESUMING | AUTO_RESUME_TIMEOUT | CHECK_LOOP_AFTER_RESUME | 等待时间到 | - |
| MANUAL_RESUMING | - | CHECK_LOOP_AFTER_RESUME | 自动 | - |
| CHECK_LOOP_AFTER_RESUME | LOOP_ENABLED | SEEK_TO_START_AFTER_RESUME | 需要回到句子开头 | - |
| CHECK_LOOP_AFTER_RESUME | LOOP_DISABLED | CHECK_GAP_SKIP | 不需要循环 | - |
| SEEK_TO_START_AFTER_RESUME | - | PLAYING | seek完成 | seekToSentenceStart, resumePlayback |
| CHECK_GAP_SKIP | GAP_SKIP_ENABLED | DETECT_GAP | 间隙跳跃开启 | - |
| CHECK_GAP_SKIP | GAP_SKIP_DISABLED | PLAYING | 间隙跳跃关闭 | playNextSentence |
| DETECT_GAP | LARGE_GAP_DETECTED | SKIP_GAP | 检测到大间隙 | - |
| DETECT_GAP | NO_GAP_DETECTED | PLAYING | 无大间隙 | playNextSentence |
| SKIP_GAP | - | PLAYING | 跳转完成 | seekToNextSentence, resumePlayback |
| PLAYING | PAUSE | USER_PAUSED | 用户手动暂停 | pausePlayback |
| USER_PAUSED | PLAY | PLAYING | 用户恢复播放 | resumePlayback |
| PLAYING | USER_SEEK | USER_SEEKED | 用户手动跳转 | seekToTime |
| USER_SEEKED | - | PLAYING | 跳转完成 | resumePlayback |
| PLAYING | LAST_SENTENCE_ENDED | COMPLETED | 最后一句结束 | completePlayback |
| SENTENCE_COMPLETED | LAST_SENTENCE_ENDED | COMPLETED | 当前句是最后一句 | completePlayback |
| * | PLAYBACK_ERROR | ERROR | 播放错误 | handleError |
3.4 状态机配置
// XState 状态机配置
const playerStateMachineConfig = {
id: 'playerEngine',
initial: 'playing',
context: {
currentTime: 0,
duration: 0,
currentSentenceIndex: -1,
loopCount: 0,
loopRemaining: 0,
autoResumeTimer: null
// ...其他上下文数据
},
states: {
playing: {
on: {
SENTENCE_ENDED: 'sentenceCompleted',
PAUSE: 'userPaused',
USER_SEEK: 'userSeeked',
LAST_SENTENCE_ENDED: 'completed',
PLAYBACK_ERROR: 'error'
},
entry: ['resumePlayback'],
exit: ['clearPlaybackState']
},
sentenceCompleted: {
always: 'checkLoop',
entry: ['updateCurrentSentence']
},
checkLoop: {
always: [
{
target: 'seekToStart',
cond: 'shouldLoop'
},
{
target: 'checkAutoPause'
}
]
}
// ...其他状态定义
}
}4. 核心组件规范
4.1 PlayEngine (主入口)
职责: 对外提供统一的播放器API
interface PlayEngine {
// 生命周期管理
init(config: PlayEngineConfig): Promise<void>
dispose(): Promise<void>
// 播放控制
play(): Promise<void>
pause(): void
togglePlay(): Promise<void>
seek(time: number): void
userSeek(time: number): void
// 状态查询
getState(): PlayerState
getContext(): PlaybackContext
isPlaying(): boolean
getCurrentTime(): number
// 配置管理
updateConfig(config: Partial<PlayEngineConfig>): void
getConfig(): PlayEngineConfig
// 事件监听
on(event: string, listener: Function): void
off(event: string, listener: Function): void
// 调试支持
getDebugInfo(): DebugInfo
exportStateMachine(): string
}实现要求:
- 必须使用 TypeScript 严格模式
- 所有公共方法必须有 JSDoc 注释
- 错误处理必须通过 Promise reject 或事件形式
- 必须支持异步初始化和清理
4.2 PlayerStateMachine (状态机)
职责: 管理播放器的核心状态和转换逻辑
interface PlayerStateMachine {
// 状态管理
getCurrentState(): PlayerState
getContext(): StateMachineContext
// 事件发送
send(event: PlayerEvent, payload?: any): void
// 状态监听
onStateChange(listener: StateChangeListener): UnsubscribeFunction
onTransition(listener: TransitionListener): UnsubscribeFunction
// 调试支持
getStateHistory(): StateTransition[]
exportStateChart(): string
// 生命周期
start(): void
stop(): void
}技术要求:
- 使用 XState 库实现
- 状态转换必须是确定性的
- 必须支持状态历史记录
- 必须提供可视化调试支持
4.3 SentenceManager (句子管理)
职责: 管理字幕句子的生命周期和边界检测
interface SentenceManager {
// 句子查询 (复用 V2 SubtitleIndexCalculator 算法)
getCurrentSentence(): SubtitleItem | null
getSentenceByIndex(index: number): SubtitleItem | null
getSentenceByTime(time: number): SubtitleItem | null
// 句子导航 (基于 V2 索引计算逻辑)
goToSentence(index: number): void
goToNextSentence(): void
goToPreviousSentence(): void
// 边界检测 (复用 V2 TimeMath 边界检测)
checkSentenceEnd(currentTime: number): boolean
getSentenceProgress(currentTime: number): number
// 配置管理
updateSubtitles(subtitles: SubtitleItem[]): void
setCurrentIndex(index: number): void
// 事件发送
onSentenceChange: EventEmitter<SentenceChangeEvent>
onSentenceEnd: EventEmitter<SentenceEndEvent>
}实现要求:
- 必须支持高精度时间比较 (复用 V2 TimeMath.EPS 和边界检测算法)
- 句子边界检测必须稳定,避免抖动 (复用 V2 的边界抖动检测逻辑)
- 必须支持空字幕场景
- 性能要求:O(log n) 时间复杂度查找 (复用 V2 SubtitleIndexCalculator 的二分搜索)
4.4 LoopManager (循环管理)
职责: 处理单句循环的所有逻辑
interface LoopManager {
// 循环控制
enable(count?: number): void
disable(): void
isEnabled(): boolean
// 循环状态
getRemainingCount(): number
decrementCount(): number
resetCount(count: number): void
// 循环模式
setMode(mode: LoopMode): void
getMode(): LoopMode
// 循环执行
shouldLoop(): boolean
executeLoop(sentenceIndex: number): Promise<void>
// 事件发送
onLoopStateChange: EventEmitter<LoopStateChangeEvent>
onLoopExecution: EventEmitter<LoopExecutionEvent>
}实现要求:
- 支持有限循环和无限循环
- 循环计数必须持久化
- 必须与 SentenceManager 协同工作
- 循环执行必须是原子操作
4.5 AutoController (自动控制)
职责: 处理自动暂停、自动恢复和间隙跳跃
interface AutoController {
// 自动暂停
enableAutoPause(): void
disableAutoPause(): void
isAutoPauseEnabled(): boolean
// 自动恢复
enableAutoResume(delay: number): void
disableAutoResume(): void
isAutoResumeEnabled(): boolean
startAutoResumeTimer(): void
cancelAutoResumeTimer(): void
// 间隙跳跃
enableGapSkip(threshold: number): void
disableGapSkip(): void
isGapSkipEnabled(): boolean
detectGap(currentTime: number, nextSentenceTime: number): boolean
executeGapSkip(targetTime: number): Promise<void>
// 事件发送
onAutoResumeTimer: EventEmitter<AutoResumeTimerEvent>
onGapDetection: EventEmitter<GapDetectionEvent>
}实现要求:
- 定时器必须可取消和重置
- 间隙检测必须可配置阈值
- 所有自动操作必须可手动中断
- 必须处理组件销毁时的清理
4.6 PlaybackController (播放控制)
职责: 封装视频元素的底层操作
interface PlaybackController {
// 连接管理 (从 V2 VideoController 扩展)
connect(videoElement: HTMLVideoElement): void
disconnect(): void
isConnected(): boolean
// 播放控制 (复用 V2 VideoController 接口)
play(): Promise<void>
pause(): void
seek(time: number): void
// 状态查询 (复用 V2 VideoController 接口)
getCurrentTime(): number
getDuration(): number
isPaused(): boolean
getPlaybackRate(): number
getVolume(): number
// 属性设置 (复用 V2 VideoController 接口)
setPlaybackRate(rate: number): void
setVolume(volume: number): void
setMuted(muted: boolean): void
// 事件监听 (基于 V2 MediaClock 事件系统设计)
onTimeUpdate: EventEmitter<TimeUpdateEvent>
onPlay: EventEmitter<PlayEvent>
onPause: EventEmitter<PauseEvent>
onSeeking: EventEmitter<SeekingEvent>
onSeeked: EventEmitter<SeekedEvent>
onEnded: EventEmitter<EndedEvent>
onError: EventEmitter<ErrorEvent>
}实现要求:
- 必须处理视频元素的所有异常情况
- 播放操作必须返回 Promise
- 必须支持连接状态检查
- 所有事件必须去重和节流 (复用 V2 MediaClock 的去重逻辑)
5. 数据流设计
5.1 数据流架构
用户交互 ──┐
├─→ EventHandler ──→ PlayerStateMachine ──→ 功能模块 ──→ PlaybackController ──→ 视频元素
媒体事件 ──┘ ↓
状态变更
↓
StateManager ──→ 外部状态 (Zustand)
5.2 数据流原则
- 单向数据流: 数据只能从上层组件流向下层组件
- 事件驱动: 组件间通过事件进行通信
- 状态集中: 核心状态由状态机统一管理
- 副作用隔离: 所有副作用在控制层处理
5.3 状态同步策略
interface StateManager {
// 状态同步
syncToExternal(state: InternalState): void
syncFromExternal(externalState: ExternalState): void
// 状态订阅
subscribeToExternal(callback: StateChangeCallback): UnsubscribeFunction
// 状态验证
validateState(state: any): boolean
reconcileState(internal: InternalState, external: ExternalState): InternalState
}6. 接口定义
6.1 配置接口
interface PlayEngineConfig {
// 播放设置
autoPlay: boolean
playbackRate: number
volume: number
muted: boolean
// 循环设置
loopEnabled: boolean
loopMode: LoopMode
loopCount: number
// 自动控制设置
autoPauseEnabled: boolean
pauseOnSubtitleEnd: boolean
autoResumeEnabled: boolean
autoResumeDelay: number
// 间隙跳跃设置
gapSkipEnabled: boolean
gapSkipThreshold: number
// 调试设置
enableDebugLogs: boolean
enableStateLogging: boolean
// 性能设置
clockThrottleMs: number
maxStateHistorySize: number
}6.2 事件接口
interface PlayEngineEvents {
// 播放状态事件
'state:change': (state: PlayerState, previousState: PlayerState) => void
'playback:play': () => void
'playback:pause': () => void
'playback:seek': (time: number) => void
'playback:ended': () => void
// 句子事件
'sentence:change': (sentence: SubtitleItem, index: number) => void
'sentence:end': (sentence: SubtitleItem, index: number) => void
// 循环事件
'loop:start': (count: number) => void
'loop:end': () => void
'loop:count-change': (remaining: number) => void
// 自动控制事件
'auto:pause': () => void
'auto:resume-start': (delay: number) => void
'auto:resume-cancel': () => void
'auto:resume-complete': () => void
// 错误事件
error: (error: PlayEngineError) => void
}6.3 数据类型定义
// 循环模式
enum LoopMode {
SINGLE = 'single', // 单句循环
PLAYLIST = 'playlist', // 列表循环 (预留)
RANDOM = 'random' // 随机循环 (预留)
}
// 播放上下文
interface PlaybackContext {
// 播放器状态
currentTime: number
duration: number
playbackRate: number
volume: number
muted: boolean
// 句子状态
currentSentenceIndex: number
sentences: SubtitleItem[]
// 循环状态
loopEnabled: boolean
loopMode: LoopMode
loopCount: number
loopRemaining: number
// 自动控制状态
autoPauseEnabled: boolean
autoResumeEnabled: boolean
autoResumeDelay: number
gapSkipEnabled: boolean
gapSkipThreshold: number
}
// 字幕项
interface SubtitleItem {
id: string
startTime: number
endTime: number
text: string
confidence?: number
}
// 状态转换记录
interface StateTransition {
from: PlayerState
to: PlayerState
event: PlayerEvent
timestamp: number
payload?: any
}
// 错误类型
class PlayEngineError extends Error {
code: string
severity: 'low' | 'medium' | 'high' | 'critical'
context?: any
constructor(message: string, code: string, severity: PlayEngineError['severity'], context?: any) {
super(message)
this.name = 'PlayEngineError'
this.code = code
this.severity = severity
this.context = context
}
}7. 错误处理
7.1 错误分类
| 错误类型 | 严重级别 | 处理策略 |
|---|---|---|
| 网络错误 | Medium | 重试机制 |
| 视频格式错误 | High | 用户提示 |
| 字幕解析错误 | Low | 静默处理 |
| 状态机错误 | Critical | 重置状态机 |
| 内存泄漏 | High | 强制清理 |
7.2 错误处理流程
interface ErrorHandler {
handleError(error: PlayEngineError): void
registerErrorRecovery(errorCode: string, recovery: ErrorRecoveryFunction): void
getErrorHistory(): PlayEngineError[]
clearErrorHistory(): void
}
type ErrorRecoveryFunction = (error: PlayEngineError) => Promise<boolean>7.3 错误恢复策略
- 自动重试: 网络相关错误自动重试 3 次
- 状态回滚: 状态机错误时回滚到最后已知稳定状态
- 资源清理: 内存相关错误时强制清理资源
- 用户通知: 严重错误时通过事件通知用户
8. 性能要求
8.1 性能指标
| 指标 | 要求 | 测量方法 |
|---|---|---|
| 状态转换延迟 | < 5ms | Performance API |
| 内存使用 | < 50MB | Chrome DevTools |
| 事件处理延迟 | < 10ms | 自定义计时器 |
| 句子查找时间 | < 1ms | 二分搜索 |
| 状态机启动时间 | < 100ms | 初始化计时 |
8.2 性能优化策略
- 事件节流: 高频事件使用防抖和节流
- 状态缓存: 计算结果缓存避免重复计算
- 懒加载: 非核心功能按需加载
- 内存管理: 及时清理无用引用
- 索引优化: 使用索引加速句子查找
8.3 性能监控
interface PerformanceMonitor {
startTiming(label: string): void
endTiming(label: string): number
getMetrics(): PerformanceMetrics
resetMetrics(): void
}
interface PerformanceMetrics {
stateTransitions: {
count: number
averageTime: number
maxTime: number
}
eventProcessing: {
count: number
averageTime: number
maxTime: number
}
memoryUsage: {
current: number
peak: number
leaks: MemoryLeak[]
}
}9. 测试策略
9.1 测试层级
- 单元测试: 测试单个组件的功能
- 集成测试: 测试组件间的协作
- 端到端测试: 测试完整的播放流程
- 性能测试: 测试性能指标
- 压力测试: 测试极限情况
9.2 测试覆盖率要求
| 组件 | 覆盖率要求 |
|---|---|
| 核心状态机 | 95% |
| 功能模块 | 90% |
| 控制层 | 85% |
| 工具函数 | 95% |
9.3 测试工具
- 单元测试: Vitest + Testing Library
- 状态机测试: @xstate/test
- 端到端测试: Playwright
- 性能测试: 自定义性能套件
9.4 测试用例设计
// 状态机测试用例示例
describe('PlayerStateMachine', () => {
describe('循环播放流程', () => {
it('应该在句子结束后检查循环设置', async () => {
// Given: 启用单句循环
// When: 句子播放结束
// Then: 应该转换到 CHECK_LOOP 状态
})
it('应该在循环次数为0时停止循环', async () => {
// Given: 循环次数为1的循环播放
// When: 循环执行一次后
// Then: 应该停止循环并继续播放下一句
})
})
})10. 迁移计划
10.1 迁移阶段
阶段一: 基础架构复用 (Week 1)
- ✅ 直接复用:
TimeMath、MediaClock、ClockScheduler(95%代码可用) - ✅ 接口适配:
VideoController、StateUpdater增强为PlaybackController - 🔧 重构复用:
SubtitleIndexCalculator→SentenceManager核心算法
阶段二: 状态机实现 (Week 2)
- 🆕 新建: 基于 XState 的
PlayerStateMachine - 🔧 参考重写: 从
PlayerOrchestrator提取事件处理逻辑 - ✅ 复用:
SubtitleLockFSM概念用于状态协调
阶段三: 功能模块迁移 (Week 3)
- ✅ 算法复用: V2 策略的核心逻辑 → V3 功能模块
- 🔧 架构简化: 去除复杂的意图系统,采用直接的状态驱动
- ✅ 测试复用: V2 的测试用例和边界条件检测
阶段四: 集成与优化 (Week 4)
- 性能对比验证 (目标: 不劣于V2)
- 兼容性测试
- 生产部署
10.2 兼容性策略
- 保持接口兼容: 新引擎实现现有的公共接口
- 渐进式替换: 使用适配器模式逐步替换组件
- 特性开关: 使用配置开关控制新旧引擎的使用
- 回滚机制: 出现问题时能快速回滚到旧版本
10.3 风险控制
| 风险 | 概率 | 影响 | 缓解措施 |
|---|---|---|---|
| 性能回退 | 中 | 高 | 详细的性能测试和基准对比 |
| 功能丢失 | 低 | 高 | 完整的功能映射和测试 |
| 稳定性问题 | 中 | 中 | 充分的集成测试和灰度发布 |
| 迁移延期 | 高 | 中 | 分阶段迁移,优先级排序 |
10.4 成功标准
- 功能完整性: 100% 功能特性覆盖
- 性能指标: 不劣于现有版本
- 稳定性: 错误率 < 0.1%
- 开发体验: 新增功能开发效率提升 50%
- 维护成本: 代码复杂度降低 30%
附录
A. V2 到 V3 组件映射表
| V2 组件 | V3 组件 | 复用度 | 迁移策略 |
|---|---|---|---|
TimeMath |
TimeMath |
95% | 直接复用,已完美符合V3需求 |
MediaClock |
MediaClock |
85% | 直接复用,具备所有V3要求的特性 |
ClockScheduler |
调度功能 | 90% | 直接复用,集成到基础设施层 |
SubtitleIndexCalculator |
SentenceManager 核心 |
80% | 算法复用,接口重新设计 |
VideoController |
PlaybackController |
70% | 接口扩展,增加连接管理 |
StateUpdater |
状态同步接口 | 70% | 接口适配,保持兼容性 |
SubtitleLockFSM |
状态协调机制 | 60% | 概念复用,简化实现 |
PlayerOrchestrator |
PlayEngine |
30% | 参考事件处理,简化架构 |
Intent/Strategy 系统 |
功能模块 | 20% | 提取核心逻辑,去除复杂抽象 |
B. 词汇表
| 术语 | 定义 |
|---|---|
| 状态机 | 有限状态机,用于管理播放器的状态转换 |
| 句子 | 字幕中的一个完整语句单元 |
| 循环 | 重复播放当前句子的功能 |
| 间隙跳跃 | 自动跳过字幕间的空白时间 |
| 自动暂停 | 在句子结束后自动暂停播放 |
| 自动恢复 | 在暂停后自动恢复播放 |
C. 参考资料
- XState 官方文档
- TypeScript 编码规范
- React 性能最佳实践
- Web Audio API
- V2 引擎源码: 可复用组件的具体实现参考
注意: 本规范是一个活跃文档,随着开发进展会持续更新。所有变更都应该通过 PR 审查流程。
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels