Skip to content

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-playerbuildXgplayerConfig 一直没消费它——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 插件 → 插件 afterCreatethis.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 原生自动检测同理需真机。