@video-lab/player-core
v4.1.5
Published
Video Lab Player 播放核心:xgplayer 抽象、统一恢复与播放稳定性能力
Readme
@video-lab/player-core
Video Lab Player 的播放核心。它包装 xgplayer,并对外提供统一的命令与事件接口。
依赖 @video-lab/protocol、xgplayer、hls.js/light 与 xgplayer-flv.js,不依赖 React 或 Vue。业务应用通常使用 @video-lab/react 或 @video-lab/vue;仅在自定义集成时直接使用本包。
安装
pnpm add @video-lab/player-core什么时候直接使用它
| 你的场景 | 推荐入口 |
| --- | --- |
| React / Vue 业务页面,使用 SDK 默认组合 | @video-lab/react / @video-lab/vue |
| 需要 iframe 隔离 | @video-lab/react-frame / @video-lab/vue-frame |
| 自己持有 DOM、渲染覆盖层和播放器生命周期 | 本包 |
| 静态 CMS iframe | @video-lab/embed-helper |
直接使用本包意味着宿主自己负责创建容器、把 PlayerEvent 连接到 UI、处理命令 rejection,并在页面卸载时
销毁句柄。它不是“功能更全”的默认业务入口;框架宿主优先使用对应组合包。
已实现范围
生产装配以 src/create-player.ts 为准。它固定注册下面这些 SDK BasePlugin;消费方不能逐个关闭:
| 组件 | 职责 |
|:---|:---|
| SafeDestroyPlugin | 清理事件与根节点样式,支持重复销毁 |
| AutoplayGuardPlugin | 上报自动播放被拒绝 |
| VisibilityPlugin | 在适用平台处理页面切回后的恢复意图 |
| CompatPlugin | 识别 UC / 夸克等已知兼容风险并上报 |
| WakeLockPlugin | 播放时维持屏幕唤醒 |
| FullscreenGuardPlugin | 规避已知全屏崩溃入口 |
| ZIndexGuardPlugin | 归一播放器根节点层级 |
| HealthMonitorPlugin | 测量卡顿并提交观测与恢复意图 |
| PlayableStatePlugin | 聚合可播放状态并发出 playablechange |
| MediaSessionPlugin | 将媒体元信息同步给 W3C Media Session |
SourceRouter 是构造前运行的纯函数,不是 xgplayer 插件;网络与媒体恢复由
PlaybackRecovery / RecoveryController 统一调度。ReconnectPlugin 与
ErrorRecoveryPlugin 的源码只保留历史回归,不进入生产 preset。HLS 会按路由追加 SDK 自有的
OwnedHlsPlugin,字幕与弹幕插件只在对应配置启用时注册。
支持清晰度与 ABR:setQuality 命令、qualitychange 事件及 ready.quality 档位清单(单码率源为空数组)。也支持字幕、弹幕和通过 source.hls.lowLatencyMode 显式开启的低延迟 HLS。
用法
<div id="video-player"></div>import { createPlayer } from '@video-lab/player-core'
import '@video-lab/player-core/style.css'
const container = document.querySelector('#video-player')
if (!(container instanceof HTMLElement)) throw new Error('播放器容器未找到')
const player = createPlayer({
el: container,
config: {
source: {
sources: [
{ url: 'https://media.example.com/video/master.m3u8', type: 'hls' },
{ url: 'https://media.example.com/video.mp4', type: 'mp4' },
],
},
muted: true,
},
onEvent: (e) => console.log(e.event, e.payload),
})
await player.play()
player.seek(30)
window.addEventListener('pagehide', () => player.destroy(), { once: true })destroy() 是幂等的,但应在组件卸载或页面离开时调用;不要在播放器创建后立即销毁。
接入完成清单
- 宿主通过
config.source提供已授权的媒体地址;SDK 不接收请求头,也不刷新签名 URL。 - 将
onEvent用于本地 UI 和状态同步;timeupdate等事件可能高频,不能在回调里直接发送网络请求。 - 需要可排序、可去重的上报时消费带
delivery的onEvent,再交给@video-lab/telemetry;该包只归一事件, 业务方仍负责 transport 的队列、批量和失败观测。 - 所有异步命令都
await并处理 rejection;error是诊断事实,加载/重试按钮应以playablechange的playable、recoverable、action驱动。 - 组件或页面卸载时调用
destroy();需要切换 HLS/FLV 等不同内核时先销毁,再以新源重建。
设计上值得知道的几件事
SourceRouter 不是 xgplayer 的 BasePlugin,是纯函数。 选源必须发生在 new Player() 之前——内核插件(hls.js / flv.js)得在构造时就注册进去,而 BasePlugin 的生命周期最早只到 beforeCreate,拿不到这个时机。纯函数也更好测:UA 直接传进来,不用为了测 iOS 去改 navigator。
MP4 始终走浏览器原生 <video>。 这样可避免额外媒体管线带来的兼容性与缓冲风险。
destroy() 先摘监听,再销毁 player。 顺序反了的话,xgplayer 在销毁过程中还会抛 pause / ended,消费方会在组件已经卸载之后收到事件(坑 #3)。这个顺序有测试守着。
safeDestroy 没有 enabled 开关。 销毁保护必须始终启用,才能可靠地避免监听器与样式残留。
换内核会明确报错。 hls.js / flv.js 的内核插件在构造时注册,运行时换不了。load() 一个需要不同内核的源时抛 E_METHOD_NOT_SUPPORTED,而不是悄悄播不出来。消费方需要销毁 player 用新 source 重建。
新源加载失败只经 error 事件报告一次。 load() 在这次换源有结论时 resolve:新源起播、源故障已通过 error 报出、被更新的 load() 取代或播放器销毁。它只在换源前的校验失败(非法 source、换内核、改构造期配置、选不出可播放源)时 reject(ADR-136);reject 前会先暂停旧源,避免它在错误层下继续播放(ADR-137)。
直播的 duration 是 0,不是 Infinity。 Infinity 过不了 JSON 序列化(变成 null),而事件要跨 iframe 传,所以在源头就归一成 0。
环境探测与测试
detectEnv({ userAgent, hasMediaSource }) 是纯函数,UA 从外部注入。SSR 场景(没有 window / navigator)保守降级成"无 MSE、强制 HLS"——在服务端误判成能播 FLV 会让首屏白屏。
单元测试使用轻量 stub,不实例化真实播放器。
pnpm --filter @video-lab/player-core test宿主网页全屏
通过 pageFullscreen 传入宿主布局适配器(setActive(active) / dispose()),句柄 setPageFullscreen(active) 等待布局确认。实际状态事件为 pagefullscreenchange;React 使用 onPageFullscreenChange,Vue 使用 @page-fullscreen-change。
网页全屏的组件接入示例见当前版本 React/Vue 接入包随包交付的 README 与接入 Skill。iframe 需要新版宿主与 iframe 协商支持;未启用时新入口不可用。浏览器原生全屏接口保持独立。
统一恢复(契约 v2)
旧 reconnect({ resetCounter }) 和 reconnectstart/success/failed 已移除。命令入口是 retry(): Promise<void>;Promise 完成只表示接受或合并请求。恢复中的重复请求共用预算,强播放证据通过 recovery 的 recovered 回报。
宿主 UI 读取 playablechange 的 playable、recoverable、action。error 只提供诊断;预算耗尽才给出 action: 'retry',宿主无需按错误原因拼接重试状态。组合层可通过构造配置关闭默认 Error/Loading 覆盖层,事件仍保留。静态 iframe URL 没有宿主命令通道,内部按钮仍走同一调度。
旧恢复 API 的迁移背景见维护仓库的 ADR-099;当前调用以本包导出类型和上述行为为准。
业务宿主请选择 React/Vue 接入包,按其随包交付的 README 与接入 Skill 选择模式并查找功能配方。
