docs(audio): [PKG-AUDIO-01] freeze released synchronization contract

This commit is contained in:
Harvey Zhao committed 2026-09-12 01:48:42 +08:00
1 parent 26b2983daf
commit 8c0a2feed3
12 files changed
+418 -5

No files matched your search

+4
View File
@@ -35,6 +35,10 @@ BASE-01 于 2026-09-10 固定核心与 chapter 的 npm 发布内容,数据在
## 公共 API 报告
Audio Track 的后续包基线由 PKG-AUDIO-01 独立冻结,见
[契约和重跑](audio-track-contract.md) 及 [1.1.0 归档来源](audio-track-release.json)。
它不改写本目录初始 BASE 快照,媒体/类型/设备通过范围由后续任务提供。
BASE-02 已在内置浏览器取得核心/chapter 的同步 API 和描述符快照,见 [覆盖与重跑](api-coverage.md) 和 [冻结报告](public-api.json)。事件/生命周期、DOM、类型、分发和其他包仍由各自任务补齐。
## 事件与生命周期报告
@@ -0,0 +1,94 @@
# Audio Track 1.1.0 兼容基线
PKG-AUDIO-01;源码起点 26b2983daf9edf9c798ce6a1638deeb3c36ba778。
固定来源、逐文件 SHA-256、npm SRI、历史源码及比较结果见
[audio-track-release.json](audio-track-release.json)。不覆盖 BASE-01 的历史快照。
## 来源与范围
npm 观察到 1.0.0、1.1.0,采集时 latest 为 1.1.0。本次实际归档范围为 **1.1.0**,
不是所有历史版本。六文件归档完整性通过,manifest、README、公开声明与起点源码
在 LF 规范化后相同,发布 ESM 与源码工厂经 AST 提取/esbuild 规范化后相同。
这证明比较范围内的逻辑一致,不能代替真实媒体行为测试。
registry gitHead daf133b22630b4a0eecfa3336bbddab0e9119d96 对应本地包版本 1.0.2,
不是该 npm 1.1.0 源码的充分证明;因此保留归档完整性和独立工厂比较。
manifest 无 runtime/peer 依赖、无核心/浏览器/TS 最低版本承诺。
旧核心对照使用现有冻结的 5.4.0;这只是具体检查点,不宣称最低支持版本为 5.4.0。
## 公开形状及调用
```js
const attach = artplayerPluginAudioTrack({ url: '/audio.aac', offset: 0, sync: 0.3 })
// ArtPlayer 注册时调用 attach(art)
const result = art.plugins.artplayerPluginAudioTrack
result.update({ url: '/next.aac', offset: 0.2 })
const audio = result.audio // 同一 HTMLAudioElement,可直接操作
```
工厂配置为必传对象;工厂同步返回安装函数,安装同步返回 `{ name, audio, update }`。
name 固定为 `artplayerPluginAudioTrack`,update 同步返回 undefined。没有额外公开 destroy、
事件、UI、CSS、静态版本或 SDK。插件创建独立 Audio 元素,不替换主视频,也不自动静音主视频;
因此含原音轨的主视频可能与外部音频同时播放,这是现有行为,不静默改变音量策略。
每次安装创建独立状态;配置在安装时解构,调用工厂后、安装前的对象修改会生效。
| 输入或行为 | 1.1.0 源码/发布实现事实 | 兼容与后续验证 |
| --- | --- | --- |
| url | 初始仅 truthy 时赋给 audio.src,preload 为 auto | URL 字符串交给浏览器解析,无 SDK |
| offset | 默认 0,目标 audio 时间是 art.currentTime + offset | 正数音频领先、负数滞后;负目标/超时长在 02 实测 |
| sync | 默认 0.3,仅绝对偏差严格大于阈值才 seek | 等于阈值不写;未校验负数、NaN、Infinity,不能凭猜测新增拒绝规则 |
| update | truthy 且不同 URL 才赋 src;playing 时调用 play;之后才更新 offset/sync | 同 URL 不重载,空 URL 不清源;JS 允许只传 offset/sync,且不立即同步 |
| audio | 公开真实元素,同一引用贯穿安装/更新/销毁 | 不换为不可访问封装,不用新元素实现每次切源 |
| 音量/倍率 | 初始 volume/muted 来自 art;倍率 video?.playbackRate 或 1 | 后续 video:volumechange/ratechange 同步,无自有主视频 mute |
| play 拒绝 | 三个调用点各自 catch 并 console.warn 原错误 | 没有返回给调用者的 play Promise、没有自定义错误事件 |
| ArtPlayer 事件 | 外部音频行为 |
| --- | --- |
| play | 有 URL 才同步目标时间,随后 audio.play |
| pause | audio.pause |
| seek | 有 video/URL 才同步时间 |
| video:timeupdate | art.playing 时同步时间 |
| video:ratechange | 读 art.video.playbackRate |
| video:volumechange | 同步 art.volume 和 art.muted |
| video:waiting | audio.pause |
| video:playing | 有 URL 且 art.playing 才 audio.play,不主动 sync |
| destroy | pause、src = ''、load,按此顺序 |
没有定时器或自建请求;浏览器拥有媒体加载。当前九个 emitter 回调没有插件自身解绑,
依赖核心销毁清空事件。没有 closed 状态,外部保留的 update 可在销毁后写入新 src。
这些是源码观察,02 用受控复现及真实媒体验证;不能只凭观察称内存泄漏已复现。
## 类型和分发
公开默认导出为 `(option: Option) => (art: Artplayer) => Result`,Option.url 必需、
offset/sync 可选;Result.audio 为 HTMLAudioElement,update(option: Option): void。
Option/Result 未具名导出,消费者可用 Parameters/ReturnType 提取;04 保留这些旧合法调用。
JS 的 update({ offset: 1 }) 与声明不一致,允许拓宽 update 为部分配置,但不弱化字段类型。
docs 编辑器声明还同时包含 export default/export =,由 04 做语义验证及生成修正,
本步不声称编辑器或 TS 消费已经通过。
root exports 使用 types + import(mjs)/require(js),legacy import/require 都指向 legacy.js;
main/module/types/legacy 的完整值冻结在 manifest。UMD 全局名与默认导出一致。
保留 `/legacy`、旧文件路径、同步注册和未加载 DOM 时的导入边界;实际各格式消费由 02/04/06 验证。
当前版本保持 1.1.0,REL-09 按用户要求准备 2.0.0,未获 npm 发布授权。
## 文档、样本与差异归属
README 仅说明插件名、Demo 和 MIT;其 `example=audio-track` 与真实
`docs/assets/example/audio.track.js` 不一致。common.js 直接拼接名称,无连字符转换。
实际示例使用本地 sprite-fight.mp4 + sprite-fight.aac,二者存在;没有演示 update、
偏移边界或销毁。06 应修链接并以正式 8082 demo 验证,不能拿静态文件存在作为播放通过。
| 风险 | 当前证据等级 | 负责任务 |
| --- | --- | --- |
| AUDIO-LIFE-01:销毁后 update 可写 src,监听/异步播放归属缺少终止守卫 | 源码事实,未作浏览器泄漏结论 | 02/03/05 |
| AUDIO-SYNC-01:偏移边界及切源/缓冲恢复缺少媒体时序证据 | 待取证,不预设所有当前行为是缺陷 | 02/03/05 |
| AUDIO-TYPE-01:update 部分配置和编辑器声明不一致 | 源码/声明事实 | 04 |
| AUDIO-DEMO-01:README 示例名不匹配、维护说明缺失 | 源码/文件事实 | 06 |
## 重跑
`node refactor/scripts/audio-contract.mjs`:重验固定归档、六文件、manifest、历史 Git 内容与工厂。
首次仅从固定 npm URL 下载至忽略缓存;不安装、不执行归档脚本、不覆盖基线。
`node --test refactor/scripts/audio-contract.test.mjs`:包含该验证及规范化工具的有意行为变化检查。
本步不改生产代码/声明/构建产物;所有媒体、类型和设备验收仍是后续任务。
+113
View File
@@ -0,0 +1,113 @@
{
"schemaVersion": 1,
"task": "PKG-AUDIO-01",
"capturedAt": "2026-09-11T17:44:31.880Z",
"sourceCommit": "26b2983daf9edf9c798ce6a1638deeb3c36ba778",
"registryObservation": {
"registryUrl": "https://registry.npmjs.org/artplayer-plugin-audio-track",
"distTags": {
"latest": "1.1.0"
},
"versions": [
"1.0.0",
"1.1.0"
],
"publishedAt": "2026-03-12T14:21:57.424Z",
"note": "Observed metadata; not a promise of future latest version or support for every older release."
},
"release": {
"name": "artplayer-plugin-audio-track",
"version": "1.1.0",
"metadataUrl": "https://registry.npmjs.org/artplayer-plugin-audio-track/1.1.0",
"tarball": "https://registry.npmjs.org/artplayer-plugin-audio-track/-/artplayer-plugin-audio-track-1.1.0.tgz",
"integrity": "sha512-pvvHvTSqC2+sBelwYyjAv2CVmaQgG9KpX+i96t/e8oyZRX/JuepC9iSVIp7GzB3AtliFzhVamksT+8lXvD3RCg==",
"sha256": "7e84f6a2f4bfada428a77ef04b749bf3db53e0149fa1afe7bf5749d925e801ff",
"archiveBytes": 2205,
"registryGitHead": "daf133b22630b4a0eecfa3336bbddab0e9119d96",
"files": {
"package/README.md": "9a03352433ae90cb9d3198e17571c9bb598334b84a77a3a1df2c4b000ce8347d",
"package/dist/artplayer-plugin-audio-track.js": "473f39f1d750f0722cca7e857c12c3c978ebe3c3b2352e325f1248318e508683",
"package/dist/artplayer-plugin-audio-track.legacy.js": "d8dc74bce76112d7430c98e3165605e32fde5d3c603be4b496eac58f574576cb",
"package/dist/artplayer-plugin-audio-track.mjs": "4ac599bc5a1a6ecb0cb1942d4269528bfb2cd9d047f988de61fe671a77ad14cd",
"package/package.json": "c466ae55c40e8f6bdd97bec20fcf916c8c4f44eef3e47694638be005eb445df7",
"package/types/artplayer-plugin-audio-track.d.ts": "27bc0dfedacb7e0188cb668ac8708874a86b00d489f1636037c2465d3344437e"
},
"manifest": {
"name": "artplayer-plugin-audio-track",
"version": "1.1.0",
"description": "audio-track plugin for ArtPlayer",
"author": "Harvey Zhao <laozhaochaguan@gmail.com>",
"license": "MIT",
"homepage": "https://artplayer.org",
"repository": {
"type": "git",
"url": "git+https://github.com/zhw2590582/ArtPlayer.git"
},
"bugs": {
"url": "https://github.com/zhw2590582/ArtPlayer/issues"
},
"keywords": [
"html5",
"video",
"player"
],
"exports": {
".": {
"types": "./types/artplayer-plugin-audio-track.d.ts",
"import": "./dist/artplayer-plugin-audio-track.mjs",
"require": "./dist/artplayer-plugin-audio-track.js"
},
"./legacy": {
"types": "./types/artplayer-plugin-audio-track.d.ts",
"import": "./dist/artplayer-plugin-audio-track.legacy.js",
"require": "./dist/artplayer-plugin-audio-track.legacy.js"
}
},
"main": "dist/artplayer-plugin-audio-track.js",
"module": "./dist/artplayer-plugin-audio-track.mjs",
"types": "types/artplayer-plugin-audio-track.d.ts",
"legacy": "dist/artplayer-plugin-audio-track.legacy.js",
"browserslist": "last 1 Chrome version"
}
},
"source": {
"packages/artplayer-plugin-audio-track/package.json": "c466ae55c40e8f6bdd97bec20fcf916c8c4f44eef3e47694638be005eb445df7",
"packages/artplayer-plugin-audio-track/README.md": "9a03352433ae90cb9d3198e17571c9bb598334b84a77a3a1df2c4b000ce8347d",
"packages/artplayer-plugin-audio-track/types/artplayer-plugin-audio-track.d.ts": "27bc0dfedacb7e0188cb668ac8708874a86b00d489f1636037c2465d3344437e",
"packages/artplayer-plugin-audio-track/src/index.js": "470237ebd62e8fb8537e809db03fd02871844d41c03d422a22956bd2756ac28e",
"docs/assets/example/audio.track.js": "9ed26b2ee006e1a430db68b2a1b308c4801dd3a4cc87c74e8a8f5ccf3456ac8d",
"docs/assets/ts/artplayer-plugin-audio-track.d.ts": "e0815cb05be2366957df77f0de81a46f863c4d8e0a0697fac1258c4f48da85ea"
},
"comparisons": [
{
"file": "package.json",
"publishedLF": "c466ae55c40e8f6bdd97bec20fcf916c8c4f44eef3e47694638be005eb445df7",
"workspaceLF": "c466ae55c40e8f6bdd97bec20fcf916c8c4f44eef3e47694638be005eb445df7",
"equal": true
},
{
"file": "README.md",
"publishedLF": "9a03352433ae90cb9d3198e17571c9bb598334b84a77a3a1df2c4b000ce8347d",
"workspaceLF": "9a03352433ae90cb9d3198e17571c9bb598334b84a77a3a1df2c4b000ce8347d",
"equal": true
},
{
"file": "types/artplayer-plugin-audio-track.d.ts",
"publishedLF": "27bc0dfedacb7e0188cb668ac8708874a86b00d489f1636037c2465d3344437e",
"workspaceLF": "27bc0dfedacb7e0188cb668ac8708874a86b00d489f1636037c2465d3344437e",
"equal": true
}
],
"functionComparison": {
"sha256": "6a758f0a88567283ae44bc9d1fa0906161f6ce9d384803637d7124c2dc1b87da",
"typescript": "5.9.3",
"esbuild": "0.27.7",
"scope": [
"artplayerPluginAudioTrack"
],
"excludes": [
"bundler wrappers"
],
"note": "Historical source at sourceCommit; normalized factory comparison is not runtime acceptance."
}
}
@@ -0,0 +1,41 @@
# PKG-AUDIO-01:Audio Track 发布契约
状态:本步契约验收完成。起点为 HLS 诊断检查点 26b2983d;后者仍未完成,不构成依赖阻塞。
范围:固定 audio-track 1.1.0 的 npm 归档、声明、源码和 demo 差异,记录同步、
暴露 audio、update 和事件契约。本步不修改生产行为。后续 02 建行为测试,03 整理
同步与资源,04 迁移严格 TS 和兼容声明,05/06 完成组合、设备与分发验收。
## 来源和结果
真实 npm 1.1.0 归档 2205 字节、六文件,SHA-512 SRI、SHA-256、成员哈希及入口存在性通过。
manifest、README、声明与历史源码 LF 内容一致,完整工厂 AST 规范化比较一致。
registry gitHead 对应包版本 1.0.2,故没有把该字段当成 1.1.0 源码证明。
来源和范围见 [冻结输入](../baselines/audio-track-release.json),
详细旧行为与映射见 [契约](../baselines/audio-track-contract.md)。
识别出 AUDIO-LIFE-01/SYNC-01/TYPE-01/DEMO-01,分别交由 02~06;都是源码事实或待取证,
没有声称已复现真实音频泄漏或已修复。包括公开 audio、严格同步阈值、无自动主视频静音、
update 部分配置、错误警告、源更新及销毁顺序,旧合法接口均维持原状。
修正文档环境矩阵对本包的能力描述:它同步独立外部 Audio,不负责 HLS 轨道拓扑选择。
## 验证与范围
- `node refactor/scripts/audio-contract.mjs`:六文件归档及历史源码检查通过。
- `node --test refactor/scripts/audio-contract.test.mjs`:两项通过;额外验证格式变化不误判,
真实函数行为变化不能获得相同规范化指纹,缺失工厂明确失败。
- 定向 ESLint:首次报告对象换行三处,修正格式后复验通过。
- 计划与风险表生成/校验、Git diff 空白检查通过:216 任务、126 风险,没有豁免未解决项。
新增一个只读契约检查入口及其 Node 测试,复用已有 esbuild/TypeScript/tar 依赖,
无新安装依赖或 lock 变更。首次会下载已冻结归档至忽略缓存;不会安装/执行归档代码,
不会更新持久基线。`yarn test:baseline` 的既有文件模式自动纳入这两项。
生产源码、声明、demo、构建产物完全未改,因此本步不重建、不声称浏览器或类型消费者通过。
## 提交、回退与接续
独立完成提交主题:`docs(audio): [PKG-AUDIO-01] freeze released synchronization contract`。
仅回退本任务新增基线/检查及任务文档即可恢复先前状态;无生产行为回退需求。
基线本身长期不可覆盖,后续修改另建证据。下一步 PKG-AUDIO-02 建立可重跑的旧版行为、
边界与错误测试,03/04 按证据拆分、修复、迁移 TS;包内实际模块地图随实现交付。
剩余所有包、设备、CI/CD、major 及三轮复盘继续保留。未 push/tag/publish/merge。
+1 -1
View File
@@ -36,7 +36,7 @@ Node10 是 TS 模块解析模式名,不代表支持 Node.js 10。现代 es2020
| artplayer-plugin-ads / 2.1.0 | 广告图片/视频、本片恢复、跳过、错误/销毁;本地短广告和主片 | 发布范围及所有浏览器场景待;无需借 IMA 结果代替自有广告逻辑 | PKG-ADS-01/02/05/06 |
| artplayer-plugin-ambilight / 1.1.0 | Canvas 采样、CORS、resize、后台/销毁;同源及受控跨源 MP4 | 待真实画布和资源测量 | PKG-AMBILIGHT-01/02/05/06 |
| artplayer-plugin-asr / 2.1.0 | PCM 音频输出/暂停/销毁;AudioContext + 调用方服务 | 待音频环境与调用方 WebSocket 验证;示例服务版本未知,不在 PR 调线上服务 | PKG-ASR-01/02/05/06、EX-03 |
| artplayer-plugin-audio-track / 1.1.0 | 音轨切换与同步;固定双音轨/单音轨/无音轨样本 | 待轨道来源和支持窗口确认、Safari/桌面实测 | PKG-AUDIO-01/02/05/06 |
| artplayer-plugin-audio-track / 1.1.0 | 独立外部 Audio 与主视频时钟同步;本地 MP4+AAC,偏移/切源/缓冲/失败样本 | 1.1.0 发布及调用契约见 [包基线](baselines/audio-track-contract.md);旧核心 5.4.0 为具体对照点,桌面/Safari 实测待完成 | PKG-AUDIO-01/02/05/06 |
| artplayer-plugin-auto-thumbnail / 1.1.0 | 帧提取/跳转、CORS、回收;本地 MP4+跨源失败 | 待 Canvas/seek/移动内存行为 | PKG-AUTO-THUMB-01/02/05/06 |
| artplayer-plugin-chapter / 1.1.0 | 区间、边界/重叠、hover/update、进度条组合;MP4+固定章节 | 发布 1.1.0 已冻结;最小注册/两段 DOM 已验,边界和新旧组合待 | PKG-CHAPTER-01/02/04/05/06、PILOT-01 |
| artplayer-plugin-chromecast / 1.1.0 | Cast SDK、发送/接收会话、取消/断线、本机恢复;接收端可访问媒体 | SDK 动态地址已记录;真实接收设备和 sender 版本未知、待运行 | PKG-CAST-01/02/05/06 |
+3 -2
View File
@@ -4,7 +4,7 @@
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 216 项,范围 22 个包及工作区/示例。
状态:todo 150 / doing 1 / blocked 0 / done 65 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 149 / doing 1 / blocked 0 / done 66 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -155,7 +155,7 @@
| ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 |
| --- | --- | --- | --- | --- | --- | --- |
| PKG-AUDIO-01 | artplayer-plugin-audio-track<br>核对包契约与历史用法 | BASE-05 | url/offset/sync、audio 实例暴露、update 与音量语义 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | todo |
| PKG-AUDIO-01 | artplayer-plugin-audio-track<br>核对包契约与历史用法 | BASE-05 | url/offset/sync、audio 实例暴露、update 与音量语义 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
| PKG-AUDIO-02 | artplayer-plugin-audio-track<br>建立特有行为与错误测试 | PKG-AUDIO-01, ENG-03, ENG-05 | 偏移、倍率、seek、waiting/playing、加载错误和 autoplay 拒绝 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo |
| PKG-AUDIO-03 | artplayer-plugin-audio-track<br>整理内部职责与资源 | PKG-AUDIO-02, CORE-10 | 外部 audio 的同步策略、监听与源更新生命周期 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo |
| PKG-AUDIO-04 | artplayer-plugin-audio-track<br>迁移自有源码和公开类型 | PKG-AUDIO-03, ENG-04, ENG-06, CORE-07 | Option/Result/audio、update 输入和事件类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
@@ -466,6 +466,7 @@
- PKG-CHAPTER-02: [记录](changes/2026-09-10-PKG-CHAPTER-02-tests.md) [记录](baselines/chapter-validation.json)
- PKG-CHAPTER-03: [记录](changes/2026-09-10-PKG-CHAPTER-03-typescript-modules.md) [记录](baselines/chapter-migration-validation.json)
- PKG-CHAPTER-04: [记录](changes/2026-09-10-PKG-CHAPTER-04-public-types.md) [记录](baselines/chapter-types-validation.json)
- PKG-AUDIO-01: [记录](changes/2026-09-12-PKG-AUDIO-01-contract.md) [记录](baselines/audio-track-contract.md) [记录](baselines/audio-track-release.json)
- PKG-HLS-01: [记录](baselines/hls-control-contract.md) [记录](baselines/hls-control-release.json) [记录](changes/2026-09-11-PKG-HLS-01-contract.md)
- PKG-HLS-02: [记录](hls-validation.md) [记录](baselines/hls-sdk.json) [记录](baselines/hls-validation.json) [记录](changes/2026-09-11-PKG-HLS-02-tests.md)
- PKG-HLS-03: [记录](changes/2026-09-12-PKG-HLS-03-modules.md) [记录](baselines/hls-modules-validation.json) [记录](hls-validation.md)
+12
View File
@@ -1,5 +1,17 @@
# 进度与证据
## 最新完成:PKG-AUDIO-01 外部音轨发布契约
冻结 npm audio-track 1.1.0 六文件及完整性,manifest/README/声明和起点一致,
发布工厂与源码规范化比较通过。两项可重跑检查通过;音频同步、update 部分配置、
销毁后引用和示例链接差异已分别登记,实际行为与媒体测试由 02 接续。
源码/声明/产物未改,本步不代表音频浏览器或类型验收通过。
HLS 诊断检查点已提交 26b2983d,HLS-SDK-01 仍 doing,两项 Firefox 风险仍 open。
当前 216 项、66 done、1 doing、149 todo。Audio-01 按任务独立本地提交后核实,
继续 Audio-02,避免未归因的 HLS 平台问题阻塞无依赖的其他包。
详见 [契约](baselines/audio-track-contract.md) 和 [记录](changes/2026-09-12-PKG-AUDIO-01-contract.md)。
## HLS 诊断 checkpoint:已缩小范围,尚未关闭风险
独立诊断 runner 已加入直接 Hls、发布核心、候选核心对照,以及 HTTP/route、worker/观察器、
+4
View File
@@ -126,3 +126,7 @@
| HLS-ENV-01 | open / 已复现 | Windows WebKit 缺失 MSE,HLS 播放矩阵尚缺 Safari 证据 | PKG-HLS-05, REL-09, REVIEW-02 |
| HLS-CRASH-01 | open / 已复现 | Firefox Hls 1.5.17 worker 销毁可在原生 video 与候选核心复现崩溃 | PKG-HLS-SDK-01, PKG-HLS-05, REVIEW-02 |
| HLS-PLAYBACK-01 | open / 已复现 | Firefox 旧核心与 Hls 1.7.2 切组后视频档位未完成切换 | PKG-HLS-SDK-01, PKG-HLS-05, REVIEW-02 |
| AUDIO-LIFE-01 | open / 源码/产物事实 | Audio Track 销毁后 update 与媒体/订阅缺少终止守卫 | PKG-AUDIO-02, PKG-AUDIO-03, PKG-AUDIO-05 |
| AUDIO-SYNC-01 | open / 待取证 | Audio Track 偏移边界和切源/缓冲恢复尚缺真实时序证据 | PKG-AUDIO-02, PKG-AUDIO-03, PKG-AUDIO-05 |
| AUDIO-TYPE-01 | open / 源码/产物事实 | Audio Track update 部分配置与公开/编辑器声明不一致 | PKG-AUDIO-04 |
| AUDIO-DEMO-01 | open / 源码/产物事实 | Audio Track README 示例链接名称不匹配且缺维护说明 | PKG-AUDIO-06 |
+64
View File
@@ -2643,6 +2643,70 @@
],
"compatibleResolution": "区分 SDK、测试媒体/时序和宿主问题,保留真实档位/解码断言及 trace;不扩大等待或只验证菜单。",
"closureCriteria": "直接 Hls 与新旧核心对照定位切换停滞,验证处置和正常/连续组切换,不能以重复通过关闭。"
},
{
"id": "AUDIO-LIFE-01",
"title": "Audio Track 销毁后 update 与媒体/订阅缺少终止守卫",
"confirmation": "source-observed",
"status": "open",
"owners": [
"PKG-AUDIO-02",
"PKG-AUDIO-03",
"PKG-AUDIO-05"
],
"evidence": [
"refactor/baselines/audio-track-contract.md",
"refactor/baselines/audio-track-release.json"
],
"compatibleResolution": "保留公开 audio 和同步 update,封闭销毁后的资源写入并管理插件订阅,验证待决播放拒绝。",
"closureCriteria": "受控复现和新旧核心真实媒体切源/销毁验证通过,不以源码观察代替泄漏证据。"
},
{
"id": "AUDIO-SYNC-01",
"title": "Audio Track 偏移边界和切源/缓冲恢复尚缺真实时序证据",
"confirmation": "unverified",
"status": "open",
"owners": [
"PKG-AUDIO-02",
"PKG-AUDIO-03",
"PKG-AUDIO-05"
],
"evidence": [
"refactor/baselines/audio-track-contract.md",
"refactor/baselines/audio-track-release.json"
],
"compatibleResolution": "固定严格阈值、偏移正负、倍率和音量语义;实测负目标/超时长及连续切源,按证据修复。",
"closureCriteria": "正常/边界/失败/缓冲恢复有媒体与受控断言,实际支持环境缺口明确处理。"
},
{
"id": "AUDIO-TYPE-01",
"title": "Audio Track update 部分配置与公开/编辑器声明不一致",
"confirmation": "source-observed",
"status": "open",
"owners": [
"PKG-AUDIO-04"
],
"evidence": [
"refactor/baselines/audio-track-contract.md",
"refactor/baselines/audio-track-release.json"
],
"compatibleResolution": "拓宽已有 JS 合法部分 update,保留 url/offset/sync 字段精度和 Parameters/ReturnType 提取,生成语义正确编辑器声明。",
"closureCriteria": "当前与旧编译器的正反例、CJS/ESM/legacy 入口及实际编辑器通过。"
},
{
"id": "AUDIO-DEMO-01",
"title": "Audio Track README 示例链接名称不匹配且缺维护说明",
"confirmation": "source-observed",
"status": "open",
"owners": [
"PKG-AUDIO-06"
],
"evidence": [
"refactor/baselines/audio-track-contract.md",
"refactor/baselines/audio-track-release.json"
],
"compatibleResolution": "修正 audio.track 示例路径,补真实模块地图及 update/生命周期说明。",
"closureCriteria": "README、示例、公开声明一致,8082 正式 demo 和包分发验证通过。"
}
]
}
+62
View File
@@ -0,0 +1,62 @@
import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { transform } from 'esbuild'
import ts from 'typescript'
import { archiveFiles, ensureArchive, hash, readMember, refactorDir } from './releases.mjs'
const root = path.resolve(refactorDir, '..')
export const normalizeLF = value => value.toString().replace(/\r\n/g, '\n')
export async function audioFunctionHash(code) {
const source = ts.createSourceFile('audio.js', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS)
assert.equal(source.parseDiagnostics.length, 0, 'Invalid audio source')
const functions = source.statements.filter(item => ts.isFunctionDeclaration(item) && item.name?.text === 'artplayerPluginAudioTrack')
assert.equal(functions.length, 1, 'Expected exactly one audio factory')
const normalized = await transform(functions[0].getText(source).replace(/^export\s+default\s+/, ''), {
loader: 'js',
target: 'es2020',
minifySyntax: true,
minifyWhitespace: true,
})
return hash(normalized.code)
}
export async function verifyAudioContract() {
const baseline = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/audio-track-release.json'), 'utf8'))
const { release } = baseline
const archive = await ensureArchive(release)
assert.deepEqual(archiveFiles(archive), Object.keys(release.files).sort())
for (const [member, expected] of Object.entries(release.files))
assert.equal(hash(readMember(archive, member)), expected, `Changed release member: ${member}`)
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
assert.deepEqual(manifest, release.manifest)
for (const entry of [manifest.main, manifest.module, manifest.types, manifest.legacy])
assert(Object.hasOwn(release.files, `package/${entry.replace(/^\.\//, '')}`))
assert(/^[a-f\d]{40}$/.test(baseline.sourceCommit))
const historical = new Map()
for (const [file, expected] of Object.entries(baseline.source)) {
const content = normalizeLF(execFileSync('git', ['show', `${baseline.sourceCommit}:${file}`], { cwd: root }))
assert.equal(hash(content), expected, `Changed historical source: ${file}`)
historical.set(file, content)
}
for (const comparison of baseline.comparisons) {
const published = hash(normalizeLF(readMember(archive, `package/${comparison.file}`)))
const source = hash(historical.get(`packages/${release.name}/${comparison.file}`))
assert.equal(published, comparison.publishedLF)
assert.equal(source, comparison.workspaceLF)
assert.equal(published === source, comparison.equal)
}
const sourceHash = await audioFunctionHash(historical.get(`packages/${release.name}/src/index.js`))
const publishedHash = await audioFunctionHash(readMember(archive, `package/${manifest.module.replace(/^\.\//, '')}`).toString())
assert.equal(sourceHash, baseline.functionComparison.sha256)
assert.equal(publishedHash, sourceHash)
console.log(`Verified ${release.name}@${release.version}: archive, ${Object.keys(release.files).length} members, historical sources and normalized factory`)
return { baseline, archive }
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url))
await verifyAudioContract()
+14
View File
@@ -0,0 +1,14 @@
import assert from 'node:assert/strict'
// eslint-disable-next-line test/no-import-node-test -- Frozen baseline checks run in Node.
import test from 'node:test'
import { audioFunctionHash, verifyAudioContract } from './audio-contract.mjs'
test('Audio Track 1.1.0 archive and historical contract remain immutable', verifyAudioContract)
test('audio factory comparison ignores formatting but detects changed behavior', async () => {
const original = 'export default function artplayerPluginAudioTrack(option) { return option.offset + 1 }'
const formatted = 'function artplayerPluginAudioTrack(option) {\n return option.offset + 1;\n }'
assert.equal(await audioFunctionHash(original), await audioFunctionHash(formatted))
assert.notEqual(await audioFunctionHash(original), await audioFunctionHash(original.replace('+ 1', '+ 2')))
await assert.rejects(audioFunctionHash('function unrelated() {}'), /exactly one audio factory/)
})
+6 -2
View File
@@ -1468,11 +1468,15 @@
"dependsOn": [
"BASE-05"
],
"status": "todo",
"status": "done",
"risk": "H",
"deliverable": "url/offset/sync、audio 实例暴露、update 与音量语义",
"acceptance": "源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结",
"evidence": []
"evidence": [
"changes/2026-09-12-PKG-AUDIO-01-contract.md",
"baselines/audio-track-contract.md",
"baselines/audio-track-release.json"
]
},
{
"id": "PKG-AUDIO-02",