- 音视频
- 直播
- 移动开发
【免费下载链接】pure_live
纯粹直播:哔哩哔哩/虎牙/斗鱼/快手/抖音/网易cc/YY直播/Twitch直播/SOOP直播/M38自定义源应有尽有。
导读
虎牙直播间在一次取流失败或主动“下一线路”后,客户端需要重新拉取房间线路快照并续签播放地址;此时旧会话保存的currentLineIndex(旧列表序号)在新列表里已经失去线路身份含义,按序号盲选会把恢复动作引向错误 CDN 甚至短连接协议。本篇以 pure_live 于 2026-09-05 完成的“虎牙续签线路身份审计”为主线,说明该缺陷的确定性成因、七条修复合同,并结合 player_controller.dart、huya_transport_policy.dart 与 huya_site.dart 的源码级实现,讲解如何按“活动 URL 的 CDN、端口、媒体路径与凭据家族”重新匹配线路,以及对应的测试与外部复验记录。读完可掌握虎牙续签场景下线路身份匹配的完整修复方案与回滚边界。
冻结范围与问题来源:这是一次 fork-regression
审计首先明确了观察窗口与取证边界:
- 本地起点提交为
427839a9176a642ea711ddf22fc43294b062b331;本轮通过git ls-remote upstream refs/heads/master核实上游 master 为c6c9bd70aedc503c003110dae10a83ad0bb891d8,仅做只读比较,没有合并上游。 - 缺陷被归类为
fork-regression:PlayerController._buildSourceResolver的旧序号选择逻辑源自提交db7d0df33,而冻结的上游 PlayerController 并不存在这套续签 resolver,因此不是上游本轮又改坏了播放器。 - 本轮没有连接手机做设备验证;旧 Android 安装包不等同于当前 master,结论只针对本次冻结的源码快照。
这一判断的意义在于:修复面被严格限定在本地 fork 引入的“续签选线”逻辑,不扩散到播放器内核、弹幕、录制等其他模块。
从取流到呈现的重新分层
审计把虎牙播放链路按职责重新分层,逐层给出证据与处置结论,原文结论如下表:
| 层 | 证据与结论 | 处置 |
|---|---|---|
| 取令牌 | 上游c5944dd5使用 WUPgetCdnTokenInfoEx、原生身份与sFlvToken;本地早期优先网页模板 | 当前本地已适配原生 FLV 优先,保留 HLS 独立令牌合同 |
| 连续传输 | 先前受控样本网页连接 120.841 秒 EOF,原生 AL/TX 各读到 420 秒主动结束 | 不再把网页短连接结论套用全部虎牙线路,也不把凭据过期等同于现存连接截止 |
| 客户端重开 | 本地旧 Windows 40 秒提前换播放器制造交接成本 | 健康原生 FLV 只预取;真实故障才恢复,原生缓存有界 |
| 本次新增:续签选线 | 旧列表序号在新列表失去线路身份含义 | 按活动 URL 的 CDN、格式和凭据家族匹配,不按旧序号盲选 |
| 异步所有权 | 前序审计已复现暂停、关闭、快速重进后旧请求仍提交 | 保留 session/intent fence;新增活动 URL 只属于当前请求,不重新引入轮询或重开 |
| 实际呈现 | 之前 Windows 候选 11 分 16 秒没有自动恢复记录;不是逐帧/音频缺口全覆盖 | 本轮确定性验证与外部探针单独记账,不声称所有网络零卡顿 |
两个关键结论贯穿全篇:网页短连接结论不得套用到全部虎牙线路(原生 FLV 的连续传输明显更长),凭据过期不等于现存连接截止(连接可存活于凭据之后)。上述两处证据的完整旧样本见 原生取流对照 与 Windows 实际候选。
新错误的第一发生点与确定性成因
审计给出了真实调用链,这也是理解修复动机的核心:
PlayerManager 预取/错误恢复 → PlaybackSourceRefreshRequest → PlayerController._buildSourceResolver → HuyaSite.resolvePlayUrlsForRecoveryRaw (重新加载房间线路、逐条生成 URL、过滤失败项) → 旧 currentLineIndex 直接用于新列表对应源码可见 player_controller.dart:resolvePlayUrlsForRecovery返回的新 URL 列表进入 resolver 后,原先直接以request.currentLineIndex.clamp(0, urls.length - 1)计算下标;而 huya_site.dart 的resolvePlayUrlsForRecoveryRaw会重新获取房间快照、重取清晰度列表,并逐条getPlayUrl生成 URL、过滤失败项——列表已经重排或缩水。
文档给出了具体反例:
原来
[AL FLV, TX FLV, TX HLS],正在播放序号 1 的 TX FLV;AL 模板失败被过滤后,新列表为[TX FLV, TX HLS]。旧算法仍选序号 1,即 TX HLS。
此外,显式“下一线路”还会在重排后从错误位置前进,可能跳过健康 FLV,或再次选中失败 CDN。文档明确这是源选择的确定性错误,并强调:它可能把后续恢复带回短连接协议,但不把它冒充本次用户每一次停顿的现场证据——即修复针对的是选线逻辑本身,不夸大覆盖面。
修复合同:七条选线契约
审计沉淀为七条可执行的修复合同:
- 管理器发送请求时附带此刻活动 URL,覆盖预取与故障恢复两条入口;URL 只在内存传递,不输出签名查询。
- 虎牙优先匹配相同 CDN、端口、媒体路径,忽略续签查询参数变化;主播重新开播导致流名变化时,按同 CDN/格式匹配。
- 原先使用原生 FLV 时优先保留有效原生 FLV 候选;原生全部失败后仍允许网页 FLV/HLS 后备,不删用户可选项。
- 用户原来选 HLS 则保留 HLS 格式;只有实际失败、触发“下一线路”或对应格式缺失,才按候选降级。
- “下一线路”从匹配后的身份前进;当前 CDN 已被删除时,直接使用首个合适后备,不额外跳过一个。
- 新列表顺序不重排,选线后的
refreshAt/invalidAt从实际选中的 URL读取。 - 其他平台维持原行为;没有当前身份的旧调用兼容有界序号选择。普通、横屏、小窗、音频共用同一管理器合同。
同时明确本次不修改播放器内核、图像比例、弹幕布局、硬件解码和定时器时长,也不存在为改选线而主动暂停健康连接的步骤。
源码级实现:按身份匹配而非按序号
请求侧:活动 URL 随刷新请求一起传递
sourceRefreshRequestFor在构造续签请求时,把提交快照中的currentUrl一并携带(playback_source_refresh.dart):
return PlaybackSourceRefreshRequest( currentLineIndex: commit.currentLineIndex, advanceLine: false, // 恢复场景不预前进,由刷新后的计划自己扫描 currentUrl: commit.currentUrl.isEmpty ? null : commit.currentUrl, currentSource: commit.ownedSource, currentQuality: quality, );测试用例同步锁定了该行为:恢复请求必须问“当前在播的线路”,而非“下一条”(见 playback_source_refresh_test.dart)。
策略侧:HuyaTransportPolicy 的层级匹配
核心策略类 huya_transport_policy.dart 的selectRefreshedLine按以下优先级组织候选池:
- 先把新列表中的 URL 解析为媒体 URI(仅接受 huya.com 及其子域、
.flv/.m3u8路径,见_mediaUri),得到有效候选池all; - 按格式过滤出
sameFormat(当前是 FLV 就只看 FLV); - 若当前是原生 FLV(
wasNative),进一步过滤出仍带原生凭据的native池; - 按
[native, sameFormat, all]顺序扫描:池内先精确匹配「同 CDN 主机、同端口、同原生凭据、且媒体路径相同」;路径匹配失败(主播重开导致流名轮换)则降级为同 CDN 匹配;仍失败则取池内首个; advanceLine(显式“下一线路”)时在匹配到的池内位置前进一位;当前 CDN 已从新列表消失时,直接取首个合适后备,不额外跳过一个。
原生凭据的判定函数hasNativeFlvCredential检查 URL 是否满足ctype=huya_pc_exe且t=100(huya_transport_policy.dart),这正是 WUP 原生取流签名在查询串中的标志。
传输侧:原生 FLV 优先的令牌合同
getPlayUrl(huya_site.dart)在 FLV 线路优先走原生 WUP:
- 通过
getNativeCdnTokenInfoEx调用getCdnTokenInfoEx获取HuyaCdnTokenLease,用line.streamName加buildAntiCode生成新签名;令牌过期立即抛错并转后备; - 原生失败时才回退网页模板(legacy 静态 token),且 HLS 走独立 AntiCode 合同,绝不复用 FLV 令牌到 HLS;
- 请求构造与客户端见
buildNativePlaybackTokenRequest(huya_site.dart)与createCdnTokenClient(huya_site.dart),后者面向https://wup.huya.com的liveui服务,超时 6 秒。
resolvePlayUrlsForRecoveryRaw逐条生成 URL 时还会对失败项返回空串并过滤(huya_site.dart),这正是“列表缩水”的来源,也是必须以身份而非序号匹配的原因。
租约侧:从实际选中 URL 读取续签时间
LivePlayLeaseMetadata接口将getPlayUrlRefreshAt与getPlayUrlInvalidAt分离(live_site.dart)。修复后 resolver 在 player_controller.dart 中从最终选中的urls[preferredIndex]读取refreshAt/invalidAt,与合同第 6 条一致,避免继续沿用旧位置的租约时间。
验证记录:单元回归、接口探测与外部复验
审计留下三层验证证据:
- 生产控制器新增测试先行失败:三项真实场景的期望序号分别为
0/1/0,旧实现实际得到1/2/1,记录20260905T135606921Z-quality-focused.json;前置格式检查/夹具漏参失败被判定为测试准备错误,不计入根因复现。 - 修复后目标文件 149/149 通过(记录
20260905T140021141Z-quality-focused.json):其中新增 3 项真实控制器场景、12 项纯策略边界;旧管理器测试补查预取/故障恢复携带的实际活动 URL;覆盖所选 URL 租约时间、重排、缺线、流名轮换、native/web/HLS 后备、单线路、无身份、外部域名等场景。 - 完整门禁 1070/1070 单元/Widget 回归、42/42 接口探测(记录
20260905T140742695Z-quality-full.json):唯一一次 analyze(46.8 秒)无问题,总耗时 236.278 秒;结束后活跃重型进程为 0;并发 12、保留缓存、无 clean;资源峰值工作集 13,262,209,024 B、CPU 10.15% 为验证工具开销而非客户端实测占用。结构审计扫描 4,029 个文件 0 错误,保留 31 处 empty-catch 盘点警告(该扫描不是逐字语义证明)。 - 外部复验(记录
20260905T141154951Z-quality-focused.json):以实际 Dart HuyaSite 取流、PlaybackHeaderResolver请求头与LiveBufferPolicy属性,供给本地锁定的 Windows libmpv;房间 660000、TX CDN、请求码率 10000(请求值,不冒充实际平均码率),持续 180.064 秒主动结束。解码尺寸 1920×1080、估计帧率 60,EOF=0、暂停采样=0、缓存暂停采样=0、native 丢帧计数=0;播放时钟推进 178.678 秒,首次时钟 1377 ms,200 ms 级轮询观察的最大时钟进度间隔 414 ms(该数值不是视频帧间隔,也不据此判定可见掉帧或零卡顿)。请求头经 native typed-node 回读一致,且没有保存 token/Cookie/签名 URL。
该 libmpv 进程 SHA-256 为24e848f59c047c9442501fdbe619ad39b98be7d4dd402691f79931c852c0070a,使用软件解码、vo=null/ao=null,不测 Flutter 纹理、硬解、屏幕合成或实际可听输出;进程 CPU 整机归一平均 0.699%,停止/销毁后私有字节从 222,363,648 B 回落至 43,827,200 B / 35,446,784 B,只验证本探针的资源释放,不代表完整客户端或 Android 的内存上界。原始脱敏输出位于local-artifacts/huya-current-native-tx-20260905.log。
回滚与发布边界
- 独立回滚本次线路身份提交即可恢复旧选择行为,且不会撤销前序的 WUP、缓存、播放意图和录制排空修复;但回滚会重新暴露本节三项可复现错误。
- 3.2.0 仍按总体验收推进,源码推送与 APK 构建/签名/上传分别确认。
- 本轮只有串行本地验证,没有新 APK 构建、签名或上传;项目公开最新发布仍为 2026-09-01 的
v3.1.8,不得把该版本附件称为包含本次源码修复的新安装包。
相关文档
- 虎牙原生取流对照(完整旧样本)
- Windows 虎牙候选复检
- 播放源刷新领域实现与测试 / 播放源刷新测试
- 虎牙站点取流实现 / 虎牙传输策略
- 音视频
- 直播
- 移动开发
【免费下载链接】pure_live
纯粹直播:哔哩哔哩/虎牙/斗鱼/快手/抖音/网易cc/YY直播/Twitch直播/SOOP直播/M38自定义源应有尽有。
相关推荐
pure_live 虎牙连续播放恢复队列审计:错误排队放大、看门狗时序与 WUP 凭据超时的修复实践
pure_live 虎牙连续播放恢复队列审计:错误排队放大、看门狗时序与 WUP 凭据超时的修复实践 导读 本文基于 pure_live 仓库的《虎牙连续播放:
音视频直播移动开发pure_live 虎牙持续播放二次审计:FLV 原生 WUP 凭据与播放器交接修复实录
pure_live 虎牙持续播放二次审计:FLV 原生 WUP 凭据与播放器交接修复实录 导读 本文基于 pure_live 仓库的《虎牙持续播放二次审计(20
音视频直播移动开发pure_live 虎牙双端短暂停顿审计:短租约取证、mpv 缓存预算与换源竞态修复路线
pure_live 虎牙双端短暂停顿审计:短租约取证、mpv 缓存预算与换源竞态修复路线 本篇以 pure_live 仓库中 2026 09 05 的虎牙连续性
音视频直播移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考