Appearance
ADR-024: LL-HLS 显式开启
Status: Accepted Date: 2026-07-13
Context
低延迟 HLS(LL-HLS)在不同浏览器行为不同:
- Safari 自动检测 EXT-X-PART-INF 标签
- 其他浏览器需要显式开启
Decision
移除顶层 lowLatency 字段,改成 source.hls.lowLatencyMode。
- Safari: 自动检测,不需要显式开启
- Chrome / Firefox / Edge / Android: 必须显式
hls.lowLatencyMode: true
前置条件:
- 后端流带 EXT-X-PART-INF 标签
- CDN 支持 HTTP/2 chunked transfer
Rationale
- 显式开启避免误配置(顶层字段容易忽略平台差异)
- source.hls 命名和其他 hls 配置项聚合
- 前置条件明确,后端 / CDN 不达标时不该开启
Consequences
好:
- 配置语义清晰
- 平台差异明确
- 不达标时降级为普通 HLS
代价:
- 消费方需要理解 LL-HLS 前置
- 需要文档说明后端 / CDN 要求
实现落地(2026-07-16 · M2.3.1)
契约字段 source.hls.lowLatencyMode 早就在 HlsConfigSchema 里,但 create-player 的 buildXgplayerConfig 一直没消费它——source-normalize 把 hls 带过来了,建 player 时却丢弃, 字段是个 no-op。M2.3.1 补上接线。
关键坑(和本 ADR 的"显式 opt-in"语义直接冲突):xgplayer-hls.js 打包的 hls.js 默认 lowLatencyMode: true。若不显式透传,未 opt-in 的流也会隐式开启低延迟——正好违反本 ADR "非 Safari 必须显式开启"。所以接线不是"true 时才传",而是把契约字段解析成确定布尔 (normalized.hls?.lowLatencyMode === true:unset/false→false、true→true)显式喂给内核, 让契约真正掌控行为、矫正 hls.js 的隐式默认。
透传路径(读 xgplayer 源码确认):xgplayer 按 pluginName 大小写不敏感匹配 player 顶层配置键 → HlsJsPlugin 命中 xgplayer-hls.js 插件 → 插件 afterCreate 读 this.config.hlsOpts → _adaptHlsJsConfig 原样转发 → new Hls(hlsOpts)。故 buildXgplayerConfig 产出 { HlsJsPlugin: { hlsOpts: { lowLatencyMode } } },仅 hls.js 内核(Safari/iOS 走 native 自动检测、 flv.js 无关,SourceRouter 已按平台路由)。
验证边界(诚实):
- ✅ 配置发射:player-core 单测两分支(未 opt-in→false 矫正默认、显式 true→透传;非 hls.js 内核不带键)。
- ✅ 路由正确性:xgplayer(pluginsManager 大小写不敏感匹配)+ xgplayer-hls.js(
_adaptHlsJsConfig原样转发)源码逐层确认;create-player 既有getPlugin('HlsJsPlugin')已证注册名一致。 - ✅ 无回归:chromium e2e 实播真 m3u8(subtitle-switch + 四模式 parity)全绿,新增配置键不破坏播放。
- ⏳ 端到端低延迟播放:需真 LL-HLS 流(EXT-X-PART-INF 分片 + HTTP/2 chunked CDN,即本 ADR 的"前置条件"), 本地 fixture 无此能力 → 留后端就绪后灰度实测(同"需真机"的 pitfall 处理)。Safari 原生自动检测同理需真机。