Skip to content

feat: 播放器引擎 V3 #191

@mkdir700

Description

@mkdir700

播放器引擎 V3 技术规范

📋 目录

1. 概述

1.1 项目背景

当前播放器引擎(V2)存在以下问题:

  • 复杂的意图系统导致维护困难
  • 分散的状态管理增加调试复杂度
  • 六阶段数据流造成性能开销
  • 策略系统过于抽象,难以理解

1.2 设计目标

主要目标

  • 🎯 简化架构: 使用状态机统一管理播放逻辑
  • 🔍 提高可调试性: 状态转换路径清晰,易于追踪
  • 优化性能: 减少不必要的计算和状态检查
  • 🛠 增强可维护性: 代码结构清晰,职责分离明确

次要目标

  • 保持向后兼容性
  • 支持渐进式迁移
  • 提供更好的开发体验

1.3 核心原则

  1. 单一职责原则: 每个组件只负责一个特定功能
  2. 状态驱动: 所有播放行为由状态机驱动
  3. 事件驱动: 通过事件进行组件间通信
  4. 可预测性: 相同输入产生相同输出
  5. 可测试性: 所有组件都能独立测试

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
Loading

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 数据流原则

  1. 单向数据流: 数据只能从上层组件流向下层组件
  2. 事件驱动: 组件间通过事件进行通信
  3. 状态集中: 核心状态由状态机统一管理
  4. 副作用隔离: 所有副作用在控制层处理

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 错误恢复策略

  1. 自动重试: 网络相关错误自动重试 3 次
  2. 状态回滚: 状态机错误时回滚到最后已知稳定状态
  3. 资源清理: 内存相关错误时强制清理资源
  4. 用户通知: 严重错误时通过事件通知用户

8. 性能要求

8.1 性能指标

指标 要求 测量方法
状态转换延迟 < 5ms Performance API
内存使用 < 50MB Chrome DevTools
事件处理延迟 < 10ms 自定义计时器
句子查找时间 < 1ms 二分搜索
状态机启动时间 < 100ms 初始化计时

8.2 性能优化策略

  1. 事件节流: 高频事件使用防抖和节流
  2. 状态缓存: 计算结果缓存避免重复计算
  3. 懒加载: 非核心功能按需加载
  4. 内存管理: 及时清理无用引用
  5. 索引优化: 使用索引加速句子查找

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 测试层级

  1. 单元测试: 测试单个组件的功能
  2. 集成测试: 测试组件间的协作
  3. 端到端测试: 测试完整的播放流程
  4. 性能测试: 测试性能指标
  5. 压力测试: 测试极限情况

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)

  • 直接复用: TimeMathMediaClockClockScheduler (95%代码可用)
  • 接口适配: VideoControllerStateUpdater 增强为 PlaybackController
  • 🔧 重构复用: SubtitleIndexCalculatorSentenceManager 核心算法

阶段二: 状态机实现 (Week 2)

  • 🆕 新建: 基于 XState 的 PlayerStateMachine
  • 🔧 参考重写: 从 PlayerOrchestrator 提取事件处理逻辑
  • 复用: SubtitleLockFSM 概念用于状态协调

阶段三: 功能模块迁移 (Week 3)

  • 算法复用: V2 策略的核心逻辑 → V3 功能模块
  • 🔧 架构简化: 去除复杂的意图系统,采用直接的状态驱动
  • 测试复用: V2 的测试用例和边界条件检测

阶段四: 集成与优化 (Week 4)

  • 性能对比验证 (目标: 不劣于V2)
  • 兼容性测试
  • 生产部署

10.2 兼容性策略

  1. 保持接口兼容: 新引擎实现现有的公共接口
  2. 渐进式替换: 使用适配器模式逐步替换组件
  3. 特性开关: 使用配置开关控制新旧引擎的使用
  4. 回滚机制: 出现问题时能快速回滚到旧版本

10.3 风险控制

风险 概率 影响 缓解措施
性能回退 详细的性能测试和基准对比
功能丢失 完整的功能映射和测试
稳定性问题 充分的集成测试和灰度发布
迁移延期 分阶段迁移,优先级排序

10.4 成功标准

  1. 功能完整性: 100% 功能特性覆盖
  2. 性能指标: 不劣于现有版本
  3. 稳定性: 错误率 < 0.1%
  4. 开发体验: 新增功能开发效率提升 50%
  5. 维护成本: 代码复杂度降低 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. 参考资料


注意: 本规范是一个活跃文档,随着开发进展会持续更新。所有变更都应该通过 PR 审查流程。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions