refactor(asr): [PKG-ASR-03] own typed audio capture and playback lifetimes

This commit is contained in:
Harvey Zhao committed 2026-09-13 14:44:23 +08:00
1 parent 53c295819d
commit 0cf2af4840
33 files changed
+3492 -809

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,62 @@
# PKG-ASR-03:拆分 ASR 并修复音频归属
从 53c295819db004e507b35689a7bdec1955e08396 开始,将单个生产 JS 文件拆成
8 个严格 TypeScript 模块。公共声明不在本任务改写,ASYNC/旧工厂类型与实际安装
消费者仍由 PKG-ASR-04 验收。无新依赖,版本不变,正常构建生成三格式及 docs 副本。
## 结构改动
index 只承担工厂、事件和兼容门面;subtitles 管字幕和隐藏定时器;capture 管代际、
初始化、节拍和回调;audio-graph 管浏览器节点;encoding/sample-queue/worklet
分离纯数据与处理器边界。完整维护地图在包内 ARCHITECTURE.md。
## 独立列明的缺陷修正
- 链式块队列保留不足块及尾部,复制输入且避免重复 concat/shift。编码与 7 个
历史实现逐字节匹配。每个活动代际只允许一个识别回调,拒绝被捕获且后续可继续。
- 暂停/切源/停止/终止使旧结果失效;旧结果不会解锁新回调。退休 recorder 的
消息即使已经被外部保留也被身份检查拒绝。首次候选回归发现此消息竞态后修复。
- 初始化去重,取消后不晚建录音图;Worklet URL 在成功、失败和终止路径释放。
Worklet 模块先准备再绑定 video,失败不会先接管并关闭视频的播放通路。
- stop 清录音/识别任务,保持可再次播放;已有字幕保留原自动隐藏期限,与历史版一致,
并拒绝旧识别结果新建隐藏任务。直接绑定视频的 context/source/
播放 gain 由播放器持有,直到 art.destroy 才关闭;pause/stop 保持播放路由。
捕获流 fallback 属于可释放的采集资源,stop 关闭;切源时重新取得流与音轨。
- destroy 清监听器、节点、流、timer,并禁止通过保留的 append 引用复活。
- 慢回调超过队列上限时明确报错并暂停采集,播放路由保留。上限取 60 秒与两个配置块
长度的较大值,以支持原本合法的长 interval;有超过 60 秒配置块的回归。不会无限缓存,
也不声称过载时音频无损;调用者网络请求仍由调用者负责取消。
- 工厂补不可枚举的自引用 default,兼容 2.0 的 require(...).default 及 2.1 的
require(...) 函数路径;保留键顺序、同步注册、选项快照、字幕 HTML/CSS 行为。
## 为什么 stop 不再关闭 direct context
实际 Chromium 在 close 后经 capture fallback 重启时无法得到非零 PCM;两个核心
组合失败,Firefox 两组合通过。原生探测报告保留在证据文件中,没有把能力失败
抹成通过。Web Audio 规定绑定后的媒体声音走节点图,close 会忽略关联媒体输出;
关闭后不能简单重新绑定节点来恢复。用户公开 stop/play 用法需要可靠恢复,因此
修正内部生命周期,而不删除重启测试或更改公开方法。
子代理独立复核了 [Web Audio close](https://www.w3.org/TR/webaudio-1.0/#dom-audiocontext-close)、
[媒体源节点](https://www.w3.org/TR/webaudio-1.0/#MediaElementAudioSourceNode)及
[捕获流切源](https://www.w3.org/TR/mediacapture-fromelement/#html-media-element-media-capture-extensions)。
保留 direct-first,避免把采样语义和兼容范围改成尚未全面支持的 capture-first。
旧版 close 行为在 ASR-02 历史测试中保留;候选测试要求停止后有播放路由、同一
context 恢复非零 PCM,最终销毁才关闭。初始化尚未绑定 video 时仍立即完整关闭。
## 验证与剩余范围
源代码分包 strict/noUncheckedIndexedAccess、定向 ESLint、正常 main/legacy/ESM
构建通过。历史/纯模块/候选共 210 项,真实 ESM 与副本校验另 2 项;main 与 legacy
各重跑 25 项候选生命周期。浏览器源码全组 12 通过/6 Windows WebKit 能力跳过,
main/legacy 候选各 4 通过/2 能力跳过;没有 failed/flaky。
具体输入哈希、报告、构建与浏览器版本见 [验证记录](../baselines/asr-ownership-validation.json)。
浏览器实际验证:两核心、非零 PCM/WAV、本地回调字幕、暂停恢复、同视频切源、
stop 后恢复及最终 context 关闭。Windows WebKit 无 WebAudio,不能代表 macOS Safari;
真实 fallback 音轨拓扑、音量/静音、跨源媒体、设备仍归 ASR-05。ASR-04 的公共类型和
实际包安装、ASR-06 的示例及发行文档仍未完成,本记录不表示整包已可发布。
仅运行本包、类型、构建和台账检查,未重复整仓全量 CI。两次子代理承担纯音频模块/
回归与规范审查,主代理负责图与控制器集成、浏览器、文档及提交。每项职责已核对。
回退本任务提交可恢复旧源码及构建产物,但会同时恢复已复现丢样本和生命周期缺陷。
+3 -2
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 225 项,范围 22 个包及工作区/示例。
状态:todo 84 / doing 16 / blocked 0 / done 125 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 83 / doing 16 / blocked 0 / done 126 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -253,7 +253,7 @@
| --- | --- | --- | --- | --- | --- | --- |
| PKG-ASR-01 | artplayer-plugin-asr<br>核对包契约与历史用法 | BASE-05 | length/interval/sampleRate/onAudioChunk、append/hide/stop 的真实能力 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
| PKG-ASR-02 | artplayer-plugin-asr<br>建立特有行为与错误测试 | PKG-ASR-01, ENG-03, ENG-05 | PCM/WAV、chunk 时序、回调慢/拒绝、重复初始化与停止 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
| PKG-ASR-03 | artplayer-plugin-asr<br>整理内部职责与资源 | PKG-ASR-02, CORE-10, CORE-18 | AudioContext/Worklet/Stream 生命周期和背压分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo |
| PKG-ASR-03 | artplayer-plugin-asr<br>整理内部职责与资源 | PKG-ASR-02, CORE-10, CORE-18 | AudioContext/Worklet/Stream 生命周期和背压分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
| PKG-ASR-04 | artplayer-plugin-asr<br>迁移自有源码和公开类型 | PKG-ASR-03, ENG-04, ENG-06, CORE-07 | 主线程/Worklet/音频 buffer 与异步回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
| PKG-ASR-05 | artplayer-plugin-asr<br>验证新旧核心和组合 | PKG-ASR-04, CORE-22 | 真实 WebAudio 分块、播放暂停/切源/销毁,不引入网络 ASR | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-ASR-06 | artplayer-plugin-asr<br>验证分发并同步文档 | PKG-ASR-05, ENG-07 | asr.js、Worklet 资源、输出格式与声明证据 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
@@ -528,6 +528,7 @@
- PKG-JASSUB-01: [记录](baselines/jassub-release.json) [记录](baselines/jassub-vendor.json) [记录](baselines/jassub-font-metadata.json) [记录](baselines/jassub-contract.md) [记录](baselines/jassub-contract-validation.json) [记录](changes/2026-09-13-PKG-JASSUB-01-baseline.md)
- PKG-ASR-01: [记录](changes/2026-09-13-PKG-ASR-01-contracts.md) [记录](baselines/asr-contract.md) [记录](baselines/asr-release.json)
- PKG-ASR-02: [记录](changes/2026-09-13-PKG-ASR-02-audio-baseline.md) [记录](baselines/asr-audio-validation.json)
- PKG-ASR-03: [记录](changes/2026-09-13-PKG-ASR-03-audio-ownership.md) [记录](baselines/asr-ownership-validation.json)
- PKG-ADS-01: [记录](baselines/ads-release.json) [记录](baselines/ads-contract.md) [记录](baselines/ads-contract-validation.json) [记录](changes/2026-09-12-PKG-ADS-01-contract.md) [记录](scripts/ads-contract.test.mjs)
- PKG-ADS-02: [记录](changes/2026-09-12-PKG-ADS-02-tests.md) [记录](ads-validation.md) [记录](baselines/ads-validation.json)
- PKG-ADS-03: [记录](changes/2026-09-12-PKG-ADS-03-lifecycle.md) [记录](ads-validation.md) [记录](baselines/ads-lifecycle-validation.json)
+15
View File
@@ -1,5 +1,20 @@
# 进度与证据
## PKG-ASR-03 TS 拆分与音频生命周期完成
生产源码拆为 8 个严格 TS 模块;队列保留半块/尾部,识别回调背压、拒绝恢复、
初始化去重和代际清理完成。退休 Worklet 消息反例由失败转通过。
Chromium stop 后不能恢复的原生问题已修复:直接媒体路由由播放器持有到 destroy,
stop 只停 ASR 并允许重新播放;先准备 Worklet 后绑定视频,失败可真正释放未绑定 context。
定向 212 项通过,main/legacy 各重跑 25 候选项;严格分包 tsc、lint、正常三格式构建通过。
最终浏览器源码 12 过/6 能力跳过,main/legacy 各 4 过/2 能力跳过;共 20 过、10 明确
Windows WebKit 无 WebAudio 跳过。非零 PCM、暂停、切源、stop 重启与 destroy 已实测。
见[变更](changes/2026-09-13-PKG-ASR-03-audio-ownership.md)和[证据](baselines/asr-ownership-validation.json)。
225 项:126 done、16 doing、83 todo;205 风险,两项 ASR 音频风险闭环。
下一步 ASR-04 公共异步类型与安装消费者;完整设备/fallback/音量和发行仍未完成。
没有重复全量 CI、没有推送或发布。子代理承担独立模块/测试和规范审查,主代理集成验收。
## PKG-ASR-02 音频与错误基线完成
子代理交付并由主代理审查的 133 项音频历史测试通过,连同公开契约/来源共 165 项。
+2 -2
View File
@@ -207,5 +207,5 @@
| CORE-DEFAULTS-SSR-01 | resolved / 已复现 | Reading static defaults throws when navigator is absent | CORE-25 |
| ENG-DIST-PUBLIC-01 | resolved / 已复现 | Vite copied authored declarations into library distribution | ENG-12 |
| ASR-TYPE-01 | open / 源码/产物事实 | ASR declarations omit asynchronous stop and callback text results | PKG-ASR-04 |
| ASR-CHUNK-01 | open / 已复现 | ASR tick discards underfilled chunks and overrun samples in source | PKG-ASR-02, PKG-ASR-03 |
| ASR-LIFE-01 | open / 已复现 | ASR partial initialization, pause resume and stale callback cleanup need controlled evidence | PKG-ASR-02, PKG-ASR-03, PKG-ASR-05 |
| ASR-CHUNK-01 | resolved / 已复现 | ASR tick discards underfilled chunks and overrun samples in source | PKG-ASR-02, PKG-ASR-03 |
| ASR-LIFE-01 | resolved / 已复现 | ASR partial initialization, pause resume and stale callback cleanup need controlled evidence | PKG-ASR-02, PKG-ASR-03, PKG-ASR-05 |
+19 -5
View File
@@ -798,7 +798,7 @@
"EX-03"
],
"evidence": [
"packages/artplayer-plugin-asr/src/index.js",
"packages/artplayer-plugin-asr/src/index.ts",
"docs/assets/example/asr.js"
],
"compatibleResolution": "Core plugin supplies PCM to caller onAudioChunk. Example fetches an external ASR endpoint and opens its returned WebSocket; not an embedded ASR SDK or a verified service.",
@@ -4561,7 +4561,7 @@
"id": "ASR-CHUNK-01",
"title": "ASR tick discards underfilled chunks and overrun samples in source",
"confirmation": "reproduced",
"status": "open",
"status": "resolved",
"owners": [
"PKG-ASR-02",
"PKG-ASR-03"
@@ -4574,13 +4574,20 @@
"refactor/baselines/asr-audio-validation.json"
],
"compatibleResolution": "Reproduce exact sample loss and retain queue remainders with bounded, ordered callback delivery.",
"closureCriteria": "Exact PCM/WAV byte sequence and slow/rejected callback regression tests pass without losing or reordering accepted input."
"closureCriteria": "Exact PCM/WAV byte sequence and slow/rejected callback regression tests pass without losing or reordering accepted input.",
"resolutionEvidence": [
"refactor/changes/2026-09-13-PKG-ASR-03-audio-ownership.md",
"refactor/baselines/asr-ownership-validation.json",
"test/asr-lifecycle.test.js",
"test/asr-encoding.test.js"
],
"resolutionRationale": "Copied linked blocks retain underfilled input and tails; exact byte parity and FIFO tests pass. One callback per generation prevents overlap; rejection recovery and obsolete completions are covered. Exceeding the larger of 60 seconds or two configured chunks pauses capture with an explicit error; long configured intervals remain collectable."
},
{
"id": "ASR-LIFE-01",
"title": "ASR partial initialization, pause resume and stale callback cleanup need controlled evidence",
"confirmation": "reproduced",
"status": "open",
"status": "resolved",
"owners": [
"PKG-ASR-02",
"PKG-ASR-03",
@@ -4594,7 +4601,14 @@
"refactor/baselines/asr-audio-validation.json"
],
"compatibleResolution": "Own pending setup, URLs, source nodes and callbacks across pause, stop, restart and terminal destruction.",
"closureCriteria": "Failure/race regression tests plus native WebAudio playback and cleanup evidence prove resource ownership."
"closureCriteria": "Failure/race regression tests plus native WebAudio playback and cleanup evidence prove resource ownership.",
"resolutionEvidence": [
"refactor/changes/2026-09-13-PKG-ASR-03-audio-ownership.md",
"refactor/baselines/asr-ownership-validation.json",
"test/asr-lifecycle.test.js",
"test/asr-encoding.test.js"
],
"resolutionRationale": "Candidate ownership/race regression tests pass, including retired-port delivery and module failure before binding video. Actual Chromium/Firefox source/main/legacy with both cores verify pause, source change, explicit stop/restart and final close. Direct media contexts deliberately remain player-owned until destroy; disposable stream contexts close on stop. General native fallback/volume/device acceptance remains ASR-05 and SDK-11, not claimed by this specific fix."
}
]
}
+5 -2
View File
@@ -2660,11 +2660,14 @@
"CORE-10",
"CORE-18"
],
"status": "todo",
"status": "done",
"risk": "H",
"deliverable": "AudioContext/Worklet/Stream 生命周期和背压分离",
"acceptance": "结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过",
"evidence": []
"evidence": [
"changes/2026-09-13-PKG-ASR-03-audio-ownership.md",
"baselines/asr-ownership-validation.json"
]
},
{
"id": "PKG-ASR-04",
+1 -1
View File
@@ -1240,7 +1240,7 @@
"EX-03"
],
"sourceFiles": [
"packages/artplayer-plugin-asr/src/index.js",
"packages/artplayer-plugin-asr/src/index.ts",
"docs/assets/example/asr.js"
],
"contract": "Core plugin supplies PCM to caller onAudioChunk. Example fetches an external ASR endpoint and opens its returned WebSocket; not an embedded ASR SDK or a verified service.",