@video-lab/player-core 1.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,31 +1,34 @@
1
1
  # @video-lab/player-core
2
2
 
3
- Video Lab Player 的播放核心(L1)。包装 xgplayer 3.0.26,对外提供统一的命令 / 事件接口,把生产坑点挡在这一层。
3
+ Video Lab Player 的播放核心。它包装 xgplayer,并对外提供统一的命令与事件接口。
4
4
 
5
- 依赖:`@video-lab/protocol` + xgplayer 3.0.26(精确锁)+ xgplayer-hls.js + xgplayer-flv.js。**不依赖 React / Vue**。
5
+ 依赖 `@video-lab/protocol`、xgplayer、hls.js/light 与 xgplayer-flv.js,不依赖 React 或 Vue。业务应用通常使用 `@video-lab/react` 或 `@video-lab/vue`;仅在自定义集成时直接使用本包。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ pnpm add @video-lab/player-core
11
+ ```
6
12
 
7
13
  ## 已实现范围
8
14
 
9
- **11 个稳定性插件全部实现**(P0×5 + P1×3 + P2×3),逻辑均有单元测试覆盖:
15
+ 内置 11 个稳定性插件,逻辑均有单元测试覆盖:
10
16
 
11
17
  | 插件 | 优先级 | 解决的 pitfall |
12
18
  |:---|:---:|:---|
13
- | `safeDestroy` | P0 | #3(destroy 后监听残留)、#4(root 样式残留)、#23(反复 destroy 崩溃) |
14
- | `SourceRouter` | P0 | #22(Firefox 不原生支持 HLS)、#27/#28/#29(FLV 在 iOS / 微信 / UC / 夸克 播不了)、#34(带 query 的 HLS URL 推断失败) |
15
- | `AutoplayGuard` | P0 | #16(autoplay 被拒未告知业务) |
16
- | `Reconnect` | P0 | #1(断网无重连)、#2(换源失败无重试) |
17
- | `Visibility` | P0 | #5 / #24(iOS 后台切回卡死) |
18
- | `Compat` | P1 | #9(UC 劫持播放器)、#10(夸克控件消失) |
19
- | `WakeLock` | P1 | #15(播放期间屏幕熄灭) |
20
- | `HealthMonitor` | P1 | #13 / #14(卡顿测量,经 `stalled` 事件上报) |
21
- | `ErrorRecovery` | P2 | #17 / #18(点播坏 ts 跳过、MP4 abort 续播) |
22
- | `FullscreenGuard` | P2 | #7(iOS 微信全屏崩溃) |
19
+ | `safeDestroy` | P0 | 清理事件与根节点样式,支持重复销毁 |
20
+ | `SourceRouter` | P0 | 选择浏览器可用的 HLS、FLV 或原生播放路径 |
21
+ | `AutoplayGuard` | P0 | 上报自动播放被拒绝 |
22
+ | `Reconnect` | P0 | 处理网络中断与换源重试 |
23
+ | `Visibility` | P0 | 处理应用切回前台后的播放恢复 |
24
+ | `Compat` | P1 | 应对浏览器兼容性差异 |
25
+ | `WakeLock` | P1 | 播放时维持屏幕唤醒 |
26
+ | `HealthMonitor` | P1 | 测量卡顿并通过 `stalled` 上报 |
27
+ | `ErrorRecovery` | P2 | 尝试恢复可处理的媒体错误 |
28
+ | `FullscreenGuard` | P2 | 处理全屏兼容性差异 |
23
29
  | `ZIndexGuard` | P2 | 层级冲突(归一 player 根节点 z-index) |
24
30
 
25
- **清晰度 / ABR 全链路已实现**:`setQuality` 命令、`qualitychange` 事件、`ready.quality` 档位清单
26
- (从 hls.js 填充,单码率源为空数组)。**字幕**(`setSubtitle` / `subtitlechange` / `ready.subtitles`,
27
- ADR-027)、**弹幕**(`pushDanmaku` / `setDanmakuEnabled` / `clearDanmaku` + `config.danmaku`,ADR-028)、
28
- **LL-HLS 显式开启**(`source.hls.lowLatencyMode`,ADR-024)也已接线。
31
+ 支持清晰度与 ABR:`setQuality` 命令、`qualitychange` 事件及 `ready.quality` 档位清单(单码率源为空数组)。也支持字幕、弹幕和通过 `source.hls.lowLatencyMode` 显式开启的低延迟 HLS。
29
32
 
30
33
  ## 用法
31
34
 
@@ -60,11 +63,11 @@ player.destroy() // 幂等,反复调用安全
60
63
 
61
64
  **`SourceRouter` 不是 xgplayer 的 BasePlugin,是纯函数。** 选源必须发生在 `new Player()` **之前**——内核插件(hls.js / flv.js)得在构造时就注册进去,而 BasePlugin 的生命周期最早只到 `beforeCreate`,拿不到这个时机。纯函数也更好测:UA 直接传进来,不用为了测 iOS 去改 `navigator`。
62
65
 
63
- **MP4 永远走浏览器原生 `<video>`。** `xgplayer-mp4` 是硬阻塞(坑 #30/#31/#32,Issue #1872 卡死 / #1578 iOS 17+ 不兼容 / #964 SourceBuffer 溢出),永不引入。
66
+ **MP4 始终走浏览器原生 `<video>`。** 这样可避免额外媒体管线带来的兼容性与缓冲风险。
64
67
 
65
68
  **`destroy()` 先摘监听,再销毁 player。** 顺序反了的话,xgplayer 在销毁过程中还会抛 pause / ended,消费方会在组件已经卸载之后收到事件(坑 #3)。这个顺序有测试守着。
66
69
 
67
- **`safeDestroy` 没有 `enabled` 开关。** ARCHITECTURE § 10.2 明确它"强制,不可关"——一个能被关掉的内存泄漏防护没有意义。
70
+ **`safeDestroy` 没有 `enabled` 开关。** 销毁保护必须始终启用,才能可靠地避免监听器与样式残留。
68
71
 
69
72
  **换内核会明确报错。** hls.js / flv.js 的内核插件在构造时注册,运行时换不了。`load()` 一个需要不同内核的源时抛 `E_METHOD_NOT_SUPPORTED`,而不是悄悄播不出来。消费方需要销毁 player 用新 source 重建。
70
73
 
@@ -74,8 +77,23 @@ player.destroy() // 幂等,反复调用安全
74
77
 
75
78
  `detectEnv({ userAgent, hasMediaSource })` 是纯函数,UA 从外部注入。SSR 场景(没有 `window` / `navigator`)保守降级成"无 MSE、强制 HLS"——在服务端误判成能播 FLV 会让首屏白屏。
76
79
 
77
- 单元测试用轻量 stub,不实例化真实 Player(见 `tests/create-player.test.ts` 的 `MockPlayer`)。
80
+ 单元测试使用轻量 stub,不实例化真实播放器。
78
81
 
79
82
  ```bash
80
83
  pnpm --filter @video-lab/player-core test
81
84
  ```
85
+
86
+ ## 宿主网页全屏
87
+
88
+ 通过 `pageFullscreen` 传入宿主布局适配器(`setActive(active)` / `dispose()`),句柄 `setPageFullscreen(active)` 等待布局确认。实际状态事件为 `pagefullscreenchange`;React 使用 `onPageFullscreenChange`,Vue 使用 `@page-fullscreen-change`。
89
+
90
+ 详见[网页全屏接入与完整参考实现](../../docs/guides/PAGE-FULLSCREEN.md)。iframe 需要新版宿主与 iframe 协商支持;未启用时新入口不可用。浏览器原生全屏接口保持独立。
91
+
92
+
93
+ ### 统一恢复(契约 v2)
94
+
95
+ 旧 `reconnect({ resetCounter })` 和 `reconnectstart/success/failed` 已移除。命令入口是 `retry(): Promise<void>`;Promise 完成只表示接受或合并请求。恢复中的重复请求共用预算,强播放证据通过 `recovery` 的 `recovered` 回报。
96
+
97
+ 宿主 UI 读取 `playablechange` 的 `playable`、`recoverable`、`action`。`error` 只提供诊断;预算耗尽才给出 `action: 'retry'`,宿主无需按错误原因拼接重试状态。组合层可通过构造配置关闭默认 Error/Loading 覆盖层,事件仍保留。静态 iframe URL 没有宿主命令通道,内部按钮仍走同一调度。
98
+
99
+ 更多迁移语义见 [ADR-099](../../docs/adr/ADR-099-unified-recovery-contract.md)。