From 803e87252e62a3aa8b09694f361378fe17d46e4f Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Sat, 12 Sep 2026 02:08:57 +0800 Subject: [PATCH] test(audio): [PKG-AUDIO-02] cover released behavior and real media --- .gitattributes | 1 + package.json | 2 +- refactor/audio-validation.md | 61 + refactor/baselines/audio-validation.json | 7871 +++++++++++++++++ .../changes/2026-09-12-PKG-AUDIO-02-tests.md | 43 + refactor/plan.md | 5 +- refactor/progress.md | 13 + refactor/risk-table.md | 4 +- refactor/risks.json | 16 +- refactor/tasks.json | 8 +- test/README.md | 5 + test/audio-track.test.js | 167 + test/browser/README.md | 5 + test/browser/audio-track.spec.js | 206 + test/browser/media/audio-tone.json | 23 + test/browser/media/audio-tone.m4a | Bin 0 -> 132436 bytes test/browser/server.mjs | 3 +- test/helpers/audio-track.js | 99 + 18 files changed, 8519 insertions(+), 13 deletions(-) create mode 100644 refactor/audio-validation.md create mode 100644 refactor/baselines/audio-validation.json create mode 100644 refactor/changes/2026-09-12-PKG-AUDIO-02-tests.md create mode 100644 test/audio-track.test.js create mode 100644 test/browser/audio-track.spec.js create mode 100644 test/browser/media/audio-tone.json create mode 100644 test/browser/media/audio-tone.m4a create mode 100644 test/helpers/audio-track.js diff --git a/.gitattributes b/.gitattributes index c3cf27cad..35b817f6f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ test/browser/media/hls/*.m3u8 text eol=lf test/browser/fixtures/hls-grouped.m3u8 text eol=lf test/browser/media/hls/*.mpegts binary +test/browser/media/*.m4a binary refactor/baselines/core-vendor/*.txt text eol=lf diff --git a/package.json b/package.json index 1000c8575..92b5b7398 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports", "test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js", "typecheck": "node scripts/typecheck.mjs", - "test:unit": "node --test test/playback.test.js test/dash-control.test.js test/hls-control.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js", + "test:unit": "node --test test/playback.test.js test/dash-control.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js", "test:coverage": "node --test test/coverage.test.js && node scripts/coverage.mjs", "test": "yarn test:node && yarn test:baseline", "test:browser": "playwright test", diff --git a/refactor/audio-validation.md b/refactor/audio-validation.md new file mode 100644 index 000000000..29d0a9665 --- /dev/null +++ b/refactor/audio-validation.md @@ -0,0 +1,61 @@ +# Audio Track 行为与媒体测试 + +PKG-AUDIO-02;公开来源见 [1.1.0 契约](baselines/audio-track-contract.md), +固定执行结果及失败保留见 [验证记录](baselines/audio-validation.json)。 + +## 已实现命令 + +```sh +node --test test/audio-track.test.js +yarn ci:check +yarn test:browser test/browser/audio-track.spec.js --trace on +``` + +Node 专项 38 项:源码和真实发布 main/legacy/module,初始化/延迟安装、暴露 audio、 +严格阈值、正负偏移、seek/播放前同步、playing 条件、waiting/pause、音量/静音/倍率、 +同/空/新 URL、三处 play 拒绝、销毁和多实例隔离。Audio 是记录调用的受控对象,不模拟解码。 +工厂输入跨 realm 检查使用冻结归档,源码使用既有 JS/TS loader,可随迁移继续回归。 + +真实浏览器最终 36 项通过,无重试、跳过:每引擎 8 项新旧核心/插件播放及失败恢复, +1 项原生 WAV 诊断、1 项旧插件空 src 销毁问题、2 项不同核心的原生暂停/结束缺陷观察。 +因此 36 通过不代表 36 项无缺陷的候选功能验收:9 项复现历史问题,3 项是原生能力诊断。 +旧核心固定 5.4.0、旧插件固定 1.1.0;候选来自源码构建,非隔离安装包。 + +播放证据包括主视频实际解码颜色、媒体时钟、AAC 音频加载/时钟、偏移 seek、倍率/音量、 +音频切源后的同一元素及同步、503 加载失败后换源恢复。公开 audio 的事件、状态、 +原始 warning、代码/媒体/核心产物指纹随测试附件保存。不声称已经测得扬声器输出或音画主观同步。 +Node 控制 waiting/playing 与 play 拒绝;实际浏览器网络缓冲/自动播放策略和移动环境由 05 补充。 + +## 样本与失败归因 + +test/browser/media/audio-tone.m4a 是本地生成的 16 秒 440 Hz 单声道 AAC。 +生成命令、FFmpeg 版本、ffprobe 及哈希见旁边 audio-tone.json,测试重验哈希。 +服务器沿用已有 GET/HEAD/Range,增加 audio/mp4 MIME;无外网音频依赖。 +WAV 诊断使用整数方波,完整参数/哈希冻结。直接原生 Audio(未创建 ArtPlayer)在 +Windows WebKit 也给出错误 4;AAC 矩阵通过不能覆盖该 WAV 或真实 Safari 的能力。 + +初轮 24 失败及后续诊断均保存,没有覆盖成绿灯: + +1. 测试先用了 currentTime setter;它不发 seek 事件。修正为已有公开 art.seek,未修改核心。 +2. 旧插件 src='' 后 readyState=0、paused=true,但 currentSrc 可能保留且 error=4。 + 正常基线清理检查属性/暂停/就绪状态,另立发布版缺陷断言,不把旧错误当作已修复。 +3. WAV 在 Windows WebKit 失败;用无播放器原生 Audio 对照隔离,并增加独立 AAC 测试输入。 +4. 最初 AAC route 固定返回 200 全文件,seek 返回 0;改用现有 Range 服务器,验证 seekable + 覆盖目标再 seek。没有增加超时或移除实际 seek 断言。 +5. Windows WebKit 视频尺寸可能反映布局,既有 browser/README.md 已说明;播放证据改为 + 固定样本的真实解码像素,保留已知尺寸限制,未改媒体实现。 + +最终源码/夹具都无生产行为变动。一次完整 CI 577 项(534+11+32)、254 个生产 TS 通过, +最终新增的浏览器观察经定向 lint 和三引擎验证。所有失败报告/trace 均复制到独立 cache 目录, +冻结 JSON 保存摘要、输入和关键状态;cache 丢失时应重跑,不能称旧 trace 仍存在。 + +## 后续修复与交接 + +- AUDIO-LIFE-01 已由旧版受控/实际媒体复现:保留的 update 可复活 src;src='' 触发新媒体错误。 + 03 应使用关闭守卫、插件自身订阅清理和无错误的媒体释放;保留同一公开 audio 及同步 update。 +- AUDIO-SYNC-01 部分已复现:主视频直接 pause 或播放结束,外部音频仍播放;03 修复原生事件同步。 + 负偏移起点/时长边界、真实缓冲和快速切源仍须在 03/05 接续,不能以本次通过关闭全部条目。 +- AUDIO-TYPE-01/DEMO-01 继续由 04/06 处理。归档分发、Monaco/8082 与设备验收尚未完成。 + +浏览器测试均共用端口 8084 和输出目录;不要同时执行多个 suite。开始下一次前复制报告 +和结果目录(包含 trace),并记录对应测试输入。Node CI 可独立并行执行。 diff --git a/refactor/baselines/audio-validation.json b/refactor/baselines/audio-validation.json new file mode 100644 index 000000000..dc92a4a03 --- /dev/null +++ b/refactor/baselines/audio-validation.json @@ -0,0 +1,7871 @@ +{ + "schemaVersion": 1, + "task": "PKG-AUDIO-02", + "capturedAt": "2026-09-11T18:08:30.994Z", + "sourceCommit": "8c0a2feed303a692fc9b37a65c116644f204429a", + "sourceHashesLF": { + "test/helpers/audio-track.js": "712ae0712e73f05843a7fac77631b31cb6fba5709b4ec195a4777c3edc21c971", + "test/audio-track.test.js": "ed54d64043e245ececf4c727512f5e33cc2268929d9b578da9b1069fdcda62a7", + "test/browser/audio-track.spec.js": "1738514af977ce4905342835a542bec3f58f49b548ff52861710bc9c81b866e7", + "test/browser/server.mjs": "4cc07efc3d5b84aa16ce691caf082b737bc704286716b321cc77a5927c77980c", + "test/browser/media/audio-tone.json": "3c87ff43501c48b984c42d6f161085f11a81099f0a38f7505d3ef3464accc330", + "packages/artplayer-plugin-audio-track/src/index.js": "470237ebd62e8fb8537e809db03fd02871844d41c03d422a22956bd2756ac28e" + }, + "media": { + "schemaVersion": 1, + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "command": "ffmpeg -hide_banner -loglevel error -f lavfi -i sine=frequency=440:sample_rate=48000:duration=16 -ac 1 -c:a aac -b:a 64k -map_metadata -1 -movflags +faststart test/browser/media/audio-tone.m4a", + "ffmpeg": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "probe": { + "programs": [], + "stream_groups": [], + "streams": [ + { + "codec_name": "aac", + "codec_type": "audio", + "sample_rate": "48000", + "channels": 1 + } + ], + "format": { + "duration": "16.000000" + } + } + }, + "node": { + "file": "refactor/.cache/audio02-node.log", + "sha256": "af97002191be56cf33a2ec0756879645487f94f86c3f74de29e373a1a5c44320", + "passed": 38, + "failed": 0, + "scope": "Source plus published main/legacy/module; controlled Audio intent, not decoding" + }, + "ci": { + "file": "refactor/.cache/audio02-ci.log", + "sha256": "516f07c5a0834c0642be3e0d632c5736e8e3dcc4fd453524f3295c22f28880e5", + "groups": [ + 534, + 11, + 32 + ], + "productionTS": 254, + "result": "passed", + "note": "Final browser-only additions subsequently passed targeted lint and browser execution; no production sources changed." + }, + "sharedInputs": { + "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881": { + "kind": "artplayer-browser-test", + "resources": { + "/candidate/artplayer.js": { + "source": { + "kind": "workspace-build", + "entry": "packages\\artplayer\\src\\index.ts" + }, + "sha256": "32f3dc22e296dcc569dc1227f0b0cad92bd0dd7e74d747e19759ac5997443e92", + "bytes": 376744 + }, + "/compiled/artplayer.js": { + "source": { + "kind": "workspace-build", + "entry": "packages\\artplayer\\src\\index.ts" + }, + "sha256": "32f3dc22e296dcc569dc1227f0b0cad92bd0dd7e74d747e19759ac5997443e92", + "bytes": 376744, + "aliasOf": "/candidate/artplayer.js" + }, + "/uncompiled/artplayer/index.js": { + "source": { + "kind": "workspace-build", + "entry": "packages\\artplayer\\src\\index.ts" + }, + "sha256": "32f3dc22e296dcc569dc1227f0b0cad92bd0dd7e74d747e19759ac5997443e92", + "bytes": 376744, + "aliasOf": "/candidate/artplayer.js" + }, + "/candidate/artplayer-plugin-chapter.js": { + "source": { + "kind": "workspace-build", + "entry": "packages\\artplayer-plugin-chapter\\src\\index.ts" + }, + "sha256": "3e8d0b7e7a90b5dbadf4cb108fd770d294f8a8a92ea089c41d0766c98bbc8230", + "bytes": 8433 + }, + "/compiled/artplayer-plugin-chapter.js": { + "source": { + "kind": "workspace-build", + "entry": "packages\\artplayer-plugin-chapter\\src\\index.ts" + }, + "sha256": "3e8d0b7e7a90b5dbadf4cb108fd770d294f8a8a92ea089c41d0766c98bbc8230", + "bytes": 8433, + "aliasOf": "/candidate/artplayer-plugin-chapter.js" + }, + "/uncompiled/artplayer-plugin-chapter/index.js": { + "source": { + "kind": "workspace-build", + "entry": "packages\\artplayer-plugin-chapter\\src\\index.ts" + }, + "sha256": "3e8d0b7e7a90b5dbadf4cb108fd770d294f8a8a92ea089c41d0766c98bbc8230", + "bytes": 8433, + "aliasOf": "/candidate/artplayer-plugin-chapter.js" + }, + "/published/artplayer.js": { + "source": { + "kind": "npm-release", + "version": "5.4.0", + "integrity": "sha512-2B+plbx8N2yNsjK4nJU3+EOG8TULm1LRZk/QPkWRAMEX2Ee/MSnZG/WJYz8kcoZxZuLKcQ3uXifqLuPxZOH29A==", + "member": "package/dist/artplayer.js" + }, + "sha256": "f1db1fa3406aa6d41baa7c554749429a8e79f99d56a794bde23345eb9c07573f", + "bytes": 134037 + }, + "/published/artplayer-plugin-chapter.js": { + "source": { + "kind": "npm-release", + "version": "1.1.0", + "integrity": "sha512-ji66Lr2K2S+OjFMuMby3yq+pefWlOC51Sbpop/DIr2N6w3F0smrF+YZbshN1Dy8/Tx1TYpT7N6WkkZWy5Jix1w==", + "member": "package/dist/artplayer-plugin-chapter.js" + }, + "sha256": "c2aaee11bf1db765433b01d9f8dd3978e41fa4d39655db00ebd03fc0be3e35e0", + "bytes": 4973 + }, + "/test/pattern.mp4": { + "source": { + "kind": "generated-media", + "file": "test/browser/media/pattern.mp4" + }, + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538 + }, + "/test/pattern.webm": { + "source": { + "kind": "generated-media", + "file": "test/browser/media/pattern.webm" + }, + "sha256": "9d3c2b3dec9581a599de2d6732992ef7846790e0d1368e6e131bd339b39e984f", + "bytes": 162073 + }, + "/test/audio-tone.m4a": { + "source": { + "kind": "generated-media", + "file": "test/browser/media/audio-tone.m4a" + }, + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436 + }, + "/test/declaration-cues.vtt": { + "source": { + "kind": "test-subtitles", + "file": "test/browser/media/declaration-cues.vtt" + }, + "sha256": "5d149d4e641ce41cbb83376835c03daf1fb89f3b9f568fa59e064d51e2b57704", + "bytes": 54 + }, + "/test/thumbnail-grid.svg": { + "source": { + "kind": "test-thumbnail-grid", + "file": "test/browser/media/thumbnail-grid.svg" + }, + "sha256": "bb3f1ec9895d37def77ca4b192d3cd73577a2668558cc99de1588f511d65d3e6", + "bytes": 14969 + }, + "/test/legacy-safe-area.js": { + "source": { + "kind": "frozen-own-source", + "file": "test/helpers/legacy-safe-area.js", + "commit": "ccf77c4e" + }, + "sha256": "ce0368618ef6363b78271b8bcc7973abd0478e797cc464ddd912929e6dfa501a", + "bytes": 795 + }, + "/assets/sample/video.mp4": { + "source": { + "kind": "docs-media", + "file": "docs/assets/sample/video.mp4" + }, + "sha256": "30a2de667ba267b6bc605edcee1c4bd728c048ed76f500ea0e73d1f1a6f8f980", + "bytes": 5818706 + }, + "/test/performance.js": { + "source": { + "kind": "adapted-baseline-fixture", + "file": "refactor/fixtures/performance.js" + }, + "sha256": "2318f39bdb5f3a3348d755cb4335907ae4adc944be3a435839c1bba201e81500", + "bytes": 8994 + } + } + }, + "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d": { + "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 ", + "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" + } + }, + "sourceSHA256": "6387f66ef15194b78336ee6256b744862e7e27a41aaab96275dcaea2f8967aa8", + "audio": { + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "format": "AAC mono 48000 Hz, 16 seconds, 440 Hz tone in MP4" + }, + "wav": { + "sha256": "3150fc69aa2b94a4b556e2e6d9d67fb52c2926cd144fdd8694a7f8ddfd2f15ff", + "bytes": 512044, + "format": "PCM16LE mono 16000 Hz, 16 seconds, integer square wave 200 Hz" + }, + "scope": "Source browser baseline; no physical device or installed package acceptance" + } + }, + "browserRuns": [ + { + "file": "refactor/.cache/audio02-browser-first.json", + "sha256": "e8e4bd04a8a0fa68a8c9198391a8df1abc70370043559485baf3b428aee1750f", + "interpretation": "24 failures: wrong seek API, empty-src cleanup and Windows WebKit WAV", + "stats": { + "startTime": "2026-09-11T17:53:18.221Z", + "duration": 79655.926, + "expected": 0, + "skipped": 0, + "unexpected": 24, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.324114\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.925886\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.324114, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0.001279, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.324114, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0.000315, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.322912\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.927088\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.322912, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0.000211, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.322912, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0.000194, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.327913\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.9220869999999999\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.327913, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0.000297, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.327913, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0.002347, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.329371\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.920629\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.329371, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0.000326, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.329371, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0.002364, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.371519\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.878481\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.371519, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.371519, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.416882\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.833118\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.416882, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.416882, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.377871\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.872129\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.377871, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.377871, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0.374877\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 1.8751229999999999\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0.374877, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + }, + { + "event": "pause", + "time": 0.374877, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: \"\"\nReceived: \"http://127.0.0.1:8084/audio-fixture/recovered.wav\"\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.wav" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeGreaterThanOrEqual(expected)\n\nExpected: >= 2\nReceived: 0\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.wav" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.wav" + } + ], + "warnings": [] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio02-chromium.json", + "sha256": "6b59598124ac0bb115d679b8a52f08393ebdd6149696e0e47686b1efe03ebf5d", + "interpretation": "6 passed / 4 failed: AAC route without Range did not support seek", + "stats": { + "startTime": "2026-09-11T17:59:11.777Z", + "duration": 23031.971999999998, + "expected": 6, + "skipped": 0, + "unexpected": 4, + "flaky": 0 + }, + "cases": [ + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": {} + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "playing", + "time": 0.000205, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 2.25\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a", + "attribute": "/audio-fixture/first.m4a", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "playing", + "time": 0.000188, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "playing", + "time": 0.000283, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 2.25\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a", + "attribute": "/audio-fixture/first.m4a", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "playing", + "time": 0.000233, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "playing", + "time": 0.000285, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 2.25\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a", + "attribute": "/audio-fixture/first.m4a", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "playing", + "time": 0.001725, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "playing", + "time": 0.000277, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toBeCloseTo(expected, precision)\n\nExpected: 2.25\nReceived: 0\n\nExpected precision: 1\nExpected difference: < 0.05\nReceived difference: 2.25\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a", + "attribute": "/audio-fixture/first.m4a", + "time": 0, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 2, + "paused": true, + "readyState": 4, + "networkState": 1, + "rate": 1 + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "playing", + "time": 0.000241, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/first.m4a" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1 + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1 + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "playing", + "time": 0.000299, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/recovered.m4a" + } + ], + "warnings": [] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio02-chromium-range.json", + "sha256": "68952b63475761db9d4a56519f4b02947a22c185182f817ee6edad243c089a91", + "interpretation": "10 passed using the existing Range server", + "stats": { + "startTime": "2026-09-11T18:00:57.027Z", + "duration": 7574.789, + "expected": 10, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": {} + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000146, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.00019, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.258203, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.258203, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.258761, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.25878, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000154, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.002997, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.270305, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.270305, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.270382, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.270403, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.00022, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000234, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.268982, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.268982, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.270091, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.270107, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000231, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.002769, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.270209, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.270209, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.270415, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.270436, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.002267, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio02-browser-range.json", + "sha256": "143c3b6d1c255e3c24c645b3b09ac64f7643509f83c5d039ec8d37a780d32d2f", + "interpretation": "26 passed / 4 failed: documented Windows WebKit layout-sized height", + "stats": { + "startTime": "2026-09-11T18:01:33.855Z", + "duration": 26463.798, + "expected": 26, + "skipped": 0, + "unexpected": 4, + "flaky": 0 + }, + "cases": [ + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": {} + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.001914, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000254, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.270124, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.270124, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.270213, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.270228, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000277, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.00338, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.269683, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.269683, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.269787, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.269805, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000298, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000297, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.269473, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.269473, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.269572, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.269593, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000452, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.002871, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.269041, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.269041, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.269145, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.269157, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000354, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": {} + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.499999, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.499999, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": {} + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.02, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"duration\": 16,\n- \"height\": 180,\n+ \"height\": 360,\n }", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "/test/audio-tone.m4a?source=first", + "time": 0.6807906, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 16 + ] + ] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 0.7127177, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 8 + ] + ] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"duration\": 16,\n- \"height\": 180,\n+ \"height\": 360,\n }", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "/test/audio-tone.m4a?source=first", + "time": 0.7197489, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 16 + ] + ] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 0.7327382, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 8 + ] + ] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"duration\": 16,\n- \"height\": 180,\n+ \"height\": 360,\n }", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "/test/audio-tone.m4a?source=first", + "time": 0.6183532, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 16 + ] + ] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 0.6504937, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 8 + ] + ] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "failed", + "retry": 0, + "error": "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"duration\": 16,\n- \"height\": 180,\n+ \"height\": 360,\n }", + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "/test/audio-tone.m4a?source=first", + "time": 0.6066032, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 16 + ] + ] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": "/test/pattern.mp4", + "time": 0.6337551, + "paused": false, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 8 + ] + ] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio02-browser-confirm.json", + "sha256": "d9a27059fc1cbbc64de7c4b7c9a43803982428a099a75b2e7bb9076a4e6b4940", + "interpretation": "36 passed: final AAC matrix including published defects and native WAV diagnostic", + "stats": { + "startTime": "2026-09-11T18:03:36.467Z", + "duration": 31052.743, + "expected": 36, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "native-wav-capability": { + "canPlay": "maybe", + "readyState": 4, + "error": null, + "playerCreated": false + }, + "audio-state": {}, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.00024, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "published-native-pause-end": { + "videoEnded": true, + "videoPaused": true, + "audioPaused": false, + "audioTime": 8.124199 + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000341, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 255, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000248, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.268837, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.268837, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.268903, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.268916, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000396, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 503 (Service Unavailable)" + ], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 255, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000175, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.267919, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.267919, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.267999, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.268015, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000352, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 503 (Service Unavailable)" + ], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "published-native-pause-end": { + "videoEnded": true, + "videoPaused": true, + "audioPaused": false, + "audioTime": 8.121094 + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000279, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 7.800231, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 255, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.00031, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.268604, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.268604, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.268695, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.268709, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000282, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 503 (Service Unavailable)" + ], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 255, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.000281, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 2.268601, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 2.268601, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.269358, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.269371, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.000396, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "153.0.8010.12", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.8010.12 Safari/537.36", + "media": null + }, + "errors": [], + "consoleErrors": [ + "Failed to load resource: the server responded with a status of 503 (Service Unavailable)" + ], + "failedRequests": [ + { + "url": "http://127.0.0.1:8084/test/pattern.mp4", + "resourceType": "media", + "failure": { + "errorText": "net::ERR_ABORTED" + } + } + ] + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "native-wav-capability": { + "canPlay": "maybe", + "readyState": 4, + "error": null, + "playerCreated": false + }, + "audio-state": {}, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "published-native-pause-end": { + "videoEnded": true, + "videoPaused": true, + "audioPaused": false, + "audioTime": 8.043114 + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 241, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 241, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "published-native-pause-end": { + "videoEnded": true, + "videoPaused": true, + "audioPaused": false, + "audioTime": 8.087428 + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 241, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 255, + 241, + 2, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.541666, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "155.0", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "native-wav-capability": { + "canPlay": "probably", + "readyState": 0, + "error": 4, + "playerCreated": false + }, + "audio-state": {}, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "published-native-pause-end": { + "videoEnded": true, + "videoPaused": true, + "audioPaused": false, + "audioTime": 8.2911034 + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 7.81, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 235, + 236, + 12, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.03, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.6730056, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 2.6730056, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 235, + 236, + 12, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.6467672, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0.0009792, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=published", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "published-native-pause-end": { + "videoEnded": true, + "videoPaused": true, + "audioPaused": false, + "audioTime": 8.2229369 + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.02, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 7.8, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 235, + 236, + 12, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.26, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.6560003, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "decoded-frame-pixel": [ + 235, + 236, + 12, + 255 + ], + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "pause", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "playing", + "time": 2.25, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "loadedmetadata", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "seeked", + "time": 2.6667932, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=second" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "attachments": { + "audio-inputs": { + "sharedInput": "7888fc414bee1c270ad321ef3bc37f7cb64d0c75a185a4808850e3bcac7d150d" + }, + "audio-state": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "events": [ + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/audio-fixture/broken.m4a" + }, + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=recovered" + } + ], + "warnings": [] + }, + "browser-evidence": { + "browser": "26.6", + "platform": "win32", + "manifest": { + "sharedInput": "27258261e9ce712f0e40c6c6b61f26571d2e91ceb961928c08c664edef2ab881" + }, + "state": { + "url": "http://127.0.0.1:8084/test/player.html?core=candidate", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15", + "media": null + }, + "errors": [], + "consoleErrors": [], + "failedRequests": [] + } + } + } + ] + } + ], + "limitations": [ + "Source builds, not isolated installed artifacts", + "AAC and local video are not all codec coverage", + "Native WAV records Windows WebKit unsupported result, not playback certification", + "Published defect test passes mean reproduced, not fixed", + "No physical iOS/Android/Safari, acoustic output capture or autoplay policy certification" + ] +} diff --git a/refactor/changes/2026-09-12-PKG-AUDIO-02-tests.md b/refactor/changes/2026-09-12-PKG-AUDIO-02-tests.md new file mode 100644 index 000000000..2a547a324 --- /dev/null +++ b/refactor/changes/2026-09-12-PKG-AUDIO-02-tests.md @@ -0,0 +1,43 @@ +# PKG-AUDIO-02:外部音频行为基线 + +状态:本步测试基线验收完成;起点 8c0a2fee。遵循已冻结的 Audio Track 1.1.0 契约。 +范围是源码及真实发布三格式的可控行为、错误与生命周期测试,以及真实浏览器的 +外部音频/主视频播放、seek、切源和清理。受控 Audio 不被描述为真实解码证据。 +公开行为不在本步修改;复现的历史问题交由 03 修复、04 类型迁移。 + +## 交付与验证 + +新增 test/audio-track.test.js 和窄范围受控 Audio helper,源码及发布三格式共 38 项通过。 +公开 audio、工厂延迟安装、默认阈值、偏移正负、配置更新、事件、Promise 拒绝及清理均覆盖。 +Node 测试加入现有 test:unit 脚本,不新增依赖或 lock 改动。 + +新增 audio-track.spec.js 和自行生成的 AAC 媒体/来源 manifest,服务器复用 Range 处理。 +三引擎最终 36 项通过(其中 9 项历史缺陷复现、3 项原生能力诊断),没有重试/跳过。 +音频与视频时钟、真实解码像素、偏移 seek、音量倍率、换音源/错误恢复、清理状态均验证。 +577 项完整 CI、254 生产 TS 通过。最终浏览器补充又通过定向 lint 与三引擎执行。 +计划/风险生成校验和 Git diff 检查通过:216 项任务、126 项风险,未豁免未解决项。 + +原始失败及下一步见 [测试说明](../audio-validation.md),所有输入/关键状态/报告哈希冻结在 +[执行证据](../baselines/audio-validation.json)。首轮 fixture 调用错误、Range 不完整、 +WebKit 尺寸假设分别修正,没有增加超时或删掉真实播放/seek 断言。 +最初定向 lint 有换行/多语句格式错误,按现有规范修正;受控测试多宿主改为单次全局 Audio +安装,避免多组恢复钩子的顺序污染,最终 CI 通过。 + +## 兼容、缺陷与范围 + +生产源码/声明/构建产物没有变更,没有新增 API、DOM/CSS 或消费者依赖。 +AUDIO-LIFE-01:发布版保留 update 可在 destroy 后写 src,且空 src 清理导致浏览器 error=4。 +AUDIO-SYNC-01:真实旧核心及候选核心中,原生暂停/自然结束后外部音频仍继续播放。 +两项保持 open,由 03 修复;本步仅把证据等级更新为已复现。 + +负偏移起点、超时长、真实缓冲、快速切源、设备策略仍需 03/05 接续。 +WAV 在 Windows WebKit 的原生 Audio 也失败,AAC 通过不替代 WAV 或真实 Safari 认证。 +未测扬声器声音、物理设备和隔离安装包;不以本次基线关闭包发布门槛。 +实际生产模块地图随 03 源码变化交付,本步提供可重跑维护入口。 + +## 提交与回退 + +独立完成提交主题:`test(audio): [PKG-AUDIO-02] cover released behavior and real media`。 +回退本提交可移除新增测试/fixture/脚本接入和文档,生产播放器不受影响。 +下一步 03 开始同步与生命周期源码拆分/修复,04 接续严格 TS/公开类型。 +未 push/tag/publish/merge,全项目目标保持。 diff --git a/refactor/plan.md b/refactor/plan.md index 687287541..6e7ad17de 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 216 项,范围 22 个包及工作区/示例。 -状态:todo 149 / doing 1 / blocked 0 / done 66 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 148 / doing 1 / blocked 0 / done 67 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -156,7 +156,7 @@ | ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | | --- | --- | --- | --- | --- | --- | --- | | PKG-AUDIO-01 | artplayer-plugin-audio-track
核对包契约与历史用法 | BASE-05 | url/offset/sync、audio 实例暴露、update 与音量语义 | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done | -| PKG-AUDIO-02 | artplayer-plugin-audio-track
建立特有行为与错误测试 | PKG-AUDIO-01, ENG-03, ENG-05 | 偏移、倍率、seek、waiting/playing、加载错误和 autoplay 拒绝 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | todo | +| PKG-AUDIO-02 | artplayer-plugin-audio-track
建立特有行为与错误测试 | PKG-AUDIO-01, ENG-03, ENG-05 | 偏移、倍率、seek、waiting/playing、加载错误和 autoplay 拒绝 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done | | PKG-AUDIO-03 | artplayer-plugin-audio-track
整理内部职责与资源 | PKG-AUDIO-02, CORE-10 | 外部 audio 的同步策略、监听与源更新生命周期 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | todo | | PKG-AUDIO-04 | artplayer-plugin-audio-track
迁移自有源码和公开类型 | PKG-AUDIO-03, ENG-04, ENG-06, CORE-07 | Option/Result/audio、update 输入和事件类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo | | PKG-AUDIO-05 | artplayer-plugin-audio-track
验证新旧核心和组合 | PKG-AUDIO-04, CORE-22 | 主视频切源和缓冲恢复,多实例独立音频、旧核心 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | @@ -467,6 +467,7 @@ - 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-AUDIO-02: [记录](changes/2026-09-12-PKG-AUDIO-02-tests.md) [记录](audio-validation.md) [记录](baselines/audio-validation.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) diff --git a/refactor/progress.md b/refactor/progress.md index ae0a5a700..ea552bb04 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,18 @@ # 进度与证据 +## 最新完成:PKG-AUDIO-02 行为与真实媒体基线 + +38 项 Node 契约覆盖源码和发布三格式,完整 CI 577 项、254 个生产 TS 通过。 +三引擎最终 36 项通过、零失败/重试/跳过;其中 9 项为旧版缺陷复现、3 项为原生 WAV +能力诊断,不能把这些数量全部作为无缺陷候选验收。真实 AAC/视频播放、偏移 seek、 +音量倍率、音频切源/503 恢复已验证。原始夹具失败与归因/trace 均保留。 + +旧插件销毁后 update 可复活、src='' 新生媒体错误、原生视频暂停/结束未停外部音频 +已有证据;AUDIO-LIFE-01/SYNC-01 仍 open,03 接续源码拆分修复。 +当前 216 项、67 done、1 doing、148 todo;HLS 仍保持原发布门槛。 +Audio-01 已提交 8c0a2fee,Audio-02 独立本地提交后核实,再进入 03。 +详见 [测试说明](audio-validation.md) 和 [记录](changes/2026-09-12-PKG-AUDIO-02-tests.md)。 + ## 最新完成:PKG-AUDIO-01 外部音轨发布契约 冻结 npm audio-track 1.1.0 六文件及完整性,manifest/README/声明和起点一致, diff --git a/refactor/risk-table.md b/refactor/risk-table.md index d8709ea94..3bf771a48 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -126,7 +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-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 | diff --git a/refactor/risks.json b/refactor/risks.json index 920c3257b..70da2f8d3 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -2647,7 +2647,7 @@ { "id": "AUDIO-LIFE-01", "title": "Audio Track 销毁后 update 与媒体/订阅缺少终止守卫", - "confirmation": "source-observed", + "confirmation": "reproduced", "status": "open", "owners": [ "PKG-AUDIO-02", @@ -2656,15 +2656,18 @@ ], "evidence": [ "refactor/baselines/audio-track-contract.md", - "refactor/baselines/audio-track-release.json" + "refactor/baselines/audio-track-release.json", + "test/audio-track.test.js", + "test/browser/audio-track.spec.js", + "refactor/baselines/audio-validation.json" ], "compatibleResolution": "保留公开 audio 和同步 update,封闭销毁后的资源写入并管理插件订阅,验证待决播放拒绝。", "closureCriteria": "受控复现和新旧核心真实媒体切源/销毁验证通过,不以源码观察代替泄漏证据。" }, { "id": "AUDIO-SYNC-01", - "title": "Audio Track 偏移边界和切源/缓冲恢复尚缺真实时序证据", - "confirmation": "unverified", + "title": "Audio Track 未同步原生暂停/结束,偏移边界与切源/缓冲仍待完整验证", + "confirmation": "reproduced", "status": "open", "owners": [ "PKG-AUDIO-02", @@ -2673,7 +2676,10 @@ ], "evidence": [ "refactor/baselines/audio-track-contract.md", - "refactor/baselines/audio-track-release.json" + "refactor/baselines/audio-track-release.json", + "test/audio-track.test.js", + "test/browser/audio-track.spec.js", + "refactor/baselines/audio-validation.json" ], "compatibleResolution": "固定严格阈值、偏移正负、倍率和音量语义;实测负目标/超时长及连续切源,按证据修复。", "closureCriteria": "正常/边界/失败/缓冲恢复有媒体与受控断言,实际支持环境缺口明确处理。" diff --git a/refactor/tasks.json b/refactor/tasks.json index c39901f37..b55ce46f2 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -1490,11 +1490,15 @@ "ENG-03", "ENG-05" ], - "status": "todo", + "status": "done", "risk": "H", "deliverable": "偏移、倍率、seek、waiting/playing、加载错误和 autoplay 拒绝", "acceptance": "旧版本行为可重跑,成功/失败/切源/销毁有必要断言", - "evidence": [] + "evidence": [ + "changes/2026-09-12-PKG-AUDIO-02-tests.md", + "audio-validation.md", + "baselines/audio-validation.json" + ] }, { "id": "PKG-AUDIO-03", diff --git a/test/README.md b/test/README.md index e138c5aea..3cbebf059 100644 --- a/test/README.md +++ b/test/README.md @@ -40,3 +40,8 @@ Blob URL contents and cleanup when a controlled click fails. See [browser/README.md](browser/README.md) for `yarn test:browser`, browser installation, published/current combinations, media fixtures, candidate mapping and failure reports. These tests are separate from the fast Node suite and run in the Browser playback smoke CI job. + +`test/audio-track.test.js` compares source and published Audio Track 1.1.0 in all three +formats with a controlled Audio object: timing intent, offsets, source updates, rejection, +volume/rate, independent instances and cleanup. Published-only tests retain defect evidence. +See [audio validation](../refactor/audio-validation.md) for actual media tests and limitations. diff --git a/test/audio-track.test.js b/test/audio-track.test.js new file mode 100644 index 000000000..92bf5ea87 --- /dev/null +++ b/test/audio-track.test.js @@ -0,0 +1,167 @@ +import assert from 'node:assert/strict' +// eslint-disable-next-line test/no-import-node-test -- Controlled media contracts use Node's runner. +import { test } from 'node:test' +import { audioHost, audioImplementations, createAudioArt } from './helpers/audio-track.js' + +const implementations = await audioImplementations() +for (const { name, factory } of implementations) { + test(`${name}: synchronous lazy installation, exposed audio and initial media properties`, (t) => { + const { art, instances } = audioHost(t) + const option = { url: 'first.aac' } + const attach = factory(option) + assert.equal(instances.length, 0) + option.url = 'before-install.aac' + const plugin = attach(art) + assert.equal(plugin.name, 'artplayerPluginAudioTrack') + assert.deepEqual(Object.keys(plugin).sort(), ['audio', 'name', 'update']) + assert.equal(plugin.audio, instances[0]) + assert.deepEqual(plugin.audio.calls, [['preload', 'auto'], ['src', 'before-install.aac'], ['volume', 0.6], ['muted', false], ['playbackRate', 1.25]]) + assert.equal(plugin.update({}), undefined) + assert.equal(art.muted, false, 'Plugin must not mute the main video') + }) + + test(`${name}: default threshold is strict and offset applies in both directions`, (t) => { + const { art } = audioHost(t) + const { audio, update } = factory({ url: 'audio.aac' })(art) + audio.calls.length = 0 + art.currentTime = 0.3 + art.emit('seek') + assert.deepEqual(audio.calls, []) + art.currentTime = 0.31 + art.emit('seek') + assert.deepEqual(audio.calls, [['currentTime', 0.31]]) + update({ offset: 2, sync: 0 }) + art.currentTime = 4 + art.emit('seek') + assert.equal(audio.currentTime, 6) + update({ offset: -1 }) + art.emit('seek') + assert.equal(audio.currentTime, 3) + }) + + test(`${name}: play synchronizes before playback and timeupdate only follows playing video`, (t) => { + const { art } = audioHost(t) + const { audio } = factory({ url: 'audio.aac' })(art) + audio.calls.length = 0 + art.currentTime = 4 + art.emit('video:timeupdate') + assert.deepEqual(audio.calls, []) + art.emit('play') + assert.deepEqual(audio.calls, [['currentTime', 4], ['play']]) + art.playing = true + art.currentTime = 5 + art.emit('video:timeupdate') + assert.equal(audio.currentTime, 5) + art.video = null + audio.calls.length = 0 + art.emit('seek') + assert.deepEqual(audio.calls, []) + }) + + test(`${name}: waiting pauses, playing resumes conditionally, pause always stops audio`, (t) => { + const { art } = audioHost(t) + const { audio } = factory({ url: 'audio.aac' })(art) + audio.calls.length = 0 + art.emit('video:waiting').emit('video:playing') + assert.deepEqual(audio.calls, [['pause']]) + art.playing = true + art.emit('video:playing').emit('pause') + assert.deepEqual(audio.calls, [['pause'], ['play'], ['pause']]) + }) + + test(`${name}: independent volume mute and rate changes follow the host`, (t) => { + const { art } = audioHost(t) + const { audio } = factory({ url: 'audio.aac' })(art) + art.volume = 0 + art.muted = true + art.video.playbackRate = 2 + art.emit('video:volumechange').emit('video:ratechange') + assert.equal(audio.volume, 0) + assert.equal(audio.muted, true) + assert.equal(audio.playbackRate, 2) + art.video = undefined + assert.equal(factory({ url: '' })(art).audio.playbackRate, 1) + }) + + test(`${name}: same and empty URLs do not reload; changed source preserves audio identity`, (t) => { + const { art, instances } = audioHost(t) + const plugin = factory({ url: 'audio.aac' })(art) + plugin.audio.calls.length = 0 + plugin.update({ url: 'audio.aac' }) + plugin.update({ url: '' }) + assert.deepEqual(plugin.audio.calls, []) + assert.equal(plugin.update({ url: 'paused.aac' }), undefined) + assert.deepEqual(plugin.audio.calls, [['src', 'paused.aac']]) + art.playing = true + plugin.audio.calls.length = 0 + plugin.update({ url: 'playing.aac' }) + assert.deepEqual(plugin.audio.calls, [['src', 'playing.aac'], ['play']]) + assert.equal(plugin.audio, instances[0]) + assert.equal(instances.length, 1) + }) + + test(`${name}: an empty initial URL stays inert until configured`, (t) => { + const { art } = audioHost(t) + const { audio, update } = factory({ url: '' })(art) + art.currentTime = 3 + art.playing = true + audio.calls.length = 0 + art.emit('play').emit('seek').emit('video:timeupdate').emit('video:playing') + assert.deepEqual(audio.calls, []) + update({ url: 'configured.aac' }) + assert.deepEqual(audio.calls, [['src', 'configured.aac'], ['play']]) + }) + + test(`${name}: rejection at all three play sites is observed as the original warning`, async (t) => { + const { art, setPlay, warnings } = audioHost(t) + const plugin = factory({ url: 'audio.aac' })(art) + const rejection = new Error('Controlled NotAllowedError') + setPlay(() => Promise.reject(rejection)) + art.playing = true + art.emit('play') + await Promise.resolve() + art.emit('video:playing') + await Promise.resolve() + assert.equal(plugin.update({ url: 'next.aac' }), undefined) + await Promise.resolve() + assert.deepEqual(warnings, [rejection, rejection, rejection]) + }) + + test(`${name}: destroy releases the exposed media and multiple hosts stay independent`, (t) => { + const first = audioHost(t) + const second = createAudioArt() + const left = factory({ url: 'left.aac' })(first.art) + const right = factory({ url: 'right.aac' })(second.art) + assert.notEqual(left.audio, right.audio) + left.audio.calls.length = 0 + right.audio.calls.length = 0 + first.art.emit('destroy') + assert.deepEqual(left.audio.calls, [['pause'], ['src', ''], ['load']]) + assert.deepEqual(right.audio.calls, []) + second.art.currentTime = 2 + second.art.emit('seek') + assert.equal(right.audio.currentTime, 2) + }) +} + +const historical = implementations.find(item => item.name === 'published-main').factory +test('published defect AUDIO-LIFE-01: retained update reloads audio after destroy', (t) => { + const { art, listeners } = audioHost(t) + const plugin = historical({ url: 'audio.aac' })(art) + art.emit('destroy') + plugin.audio.calls.length = 0 + plugin.update({ url: 'revived.aac' }) + assert.deepEqual(plugin.audio.calls, [['src', 'revived.aac']]) + assert.equal([...listeners.values()].reduce((count, set) => count + set.size, 0), 9) +}) + +test('published observation: offset update is deferred, negative target is written without clamping', (t) => { + const { art } = audioHost(t) + const plugin = historical({ url: 'audio.aac' })(art) + plugin.audio.calls.length = 0 + plugin.update({ offset: -2 }) + assert.deepEqual(plugin.audio.calls, []) + art.currentTime = 0 + art.emit('seek') + assert.deepEqual(plugin.audio.calls, [['currentTime', -2]]) +}) diff --git a/test/browser/README.md b/test/browser/README.md index 9ca7c0a6a..770224280 100644 --- a/test/browser/README.md +++ b/test/browser/README.md @@ -1,5 +1,10 @@ # Browser regression entry +Audio Track tests use the source and frozen 1.1.0 plugin on both cores. The local AAC fixture +has a pinned hash and generation command in media/audio-tone.json and uses the existing Range +server. The suite retains published cleanup/native-pause defects as explicit observations. +See [audio validation](../../refactor/audio-validation.md) for passed scope and device limitations. + Use the pinned Node and Yarn versions, then run: ```sh diff --git a/test/browser/audio-track.spec.js b/test/browser/audio-track.spec.js new file mode 100644 index 000000000..384989862 --- /dev/null +++ b/test/browser/audio-track.spec.js @@ -0,0 +1,206 @@ +import assert from 'node:assert/strict' +import { Buffer } from 'node:buffer' +import fs from 'node:fs' +import process from 'node:process' +import { ensureArchive, hash, readMember } from '../../refactor/scripts/releases.mjs' +import { compilePackage } from '../helpers/load.js' +import { expect, test } from './fixtures.js' + +let publishedCode +let sourceCode +let evidence +const samples = 16000 * 16 +const tone = fs.readFileSync(new URL('./media/audio-tone.m4a', import.meta.url)) +const toneManifest = JSON.parse(fs.readFileSync(new URL('./media/audio-tone.json', import.meta.url))) +const wav = Buffer.alloc(44 + samples * 2) +wav.write('RIFF', 0) +wav.writeUInt32LE(wav.length - 8, 4) +wav.write('WAVEfmt ', 8) +wav.writeUInt32LE(16, 16) +wav.writeUInt16LE(1, 20) +wav.writeUInt16LE(1, 22) +wav.writeUInt32LE(16000, 24) +wav.writeUInt32LE(32000, 28) +wav.writeUInt16LE(2, 32) +wav.writeUInt16LE(16, 34) +wav.write('data', 36) +wav.writeUInt32LE(samples * 2, 40) +for (let index = 0; index < samples; index++) + wav.writeInt16LE(index % 80 < 40 ? 2000 : -2000, 44 + index * 2) + +test.beforeAll(async () => { + assert.equal(hash(tone), toneManifest.sha256) + assert.equal(tone.length, toneManifest.bytes) + assert(!process.env.ARTPLAYER_BROWSER_ARTIFACTS, 'Audio source tests cannot represent installed artifacts') + const { release } = JSON.parse(fs.readFileSync(new URL('../../refactor/baselines/audio-track-release.json', import.meta.url))) + const member = 'package/dist/artplayer-plugin-audio-track.js' + const bytes = readMember(await ensureArchive(release), member) + assert.equal(hash(bytes), release.files[member]) + publishedCode = bytes.toString() + sourceCode = await compilePackage(release.name, 'umd') + evidence = { release, sourceSHA256: hash(sourceCode), audio: { sha256: hash(tone), bytes: tone.length, format: 'AAC mono 48000 Hz, 16 seconds, 440 Hz tone in MP4' }, wav: { sha256: hash(wav), bytes: wav.length, format: 'PCM16LE mono 16000 Hz, 16 seconds, integer square wave 200 Hz' }, scope: 'Source browser baseline; no physical device or installed package acceptance' } +}) + +test.afterEach(async ({ page }, testInfo) => { + const state = await page.evaluate(() => { + const audio = window.audioPlugin?.audio + const video = window.art?.video + const media = element => element && ({ src: element.currentSrc, attribute: element.getAttribute('src'), time: element.currentTime, paused: element.paused, readyState: element.readyState, networkState: element.networkState, error: element.error?.code, rate: element.playbackRate, seekable: Array.from({ length: element.seekable.length }, (_, index) => [element.seekable.start(index), element.seekable.end(index)]) }) + return { audio: media(audio), video: media(video), events: window.audioEvents, warnings: window.audioWarnings } + }).catch(error => ({ error: error.message })) + await testInfo.attach('audio-state', { contentType: 'application/json', body: JSON.stringify(state) }) +}) + +async function openAudio(page, core, plugin, testInfo, url = '/test/audio-tone.m4a?source=first') { + await testInfo.attach('audio-inputs', { contentType: 'application/json', body: JSON.stringify(evidence) }) + await page.goto(`/test/player.html?core=${core}`) + await page.addScriptTag({ content: plugin === 'published' ? publishedCode : sourceCode }) + await page.evaluate((url) => { + window.audioEvents = [] + window.audioWarnings = [] + const warn = console.warn.bind(console) + console.warn = (...args) => { + window.audioWarnings.push(args.map(String)) + warn(...args) + } + window.art = new window.Artplayer({ + container: '.player', + url: '/test/pattern.mp4', + muted: true, + plugins: [window.artplayerPluginAudioTrack({ url, sync: 0.1 })], + }) + window.audioPlugin = window.art.plugins.artplayerPluginAudioTrack + for (const event of ['loadedmetadata', 'playing', 'pause', 'seeked', 'error', 'emptied']) + window.audioPlugin.audio.addEventListener(event, () => window.audioEvents.push({ event, time: window.audioPlugin.audio.currentTime, src: window.audioPlugin.audio.currentSrc })) + document.querySelector('#play').onclick = () => window.art.play() + }, url) + await expect.poll(() => page.evaluate(() => window.art.isReady)).toBe(true) + if (url) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.readyState)).toBeGreaterThanOrEqual(2) +} + +test('native WAV diagnostic isolates sample decoding from ArtPlayer and plugin', async ({ page }, testInfo) => { + await page.route('**/native-wave.wav', route => route.fulfill({ contentType: 'audio/wav', body: wav })) + await page.goto('/test/player.html') + await page.evaluate(() => { + window.nativeAudio = new Audio() + window.nativeAudio.muted = true + window.nativeAudio.src = '/native-wave.wav' + }) + await expect.poll(() => page.evaluate(() => window.nativeAudio.readyState >= 2 || Boolean(window.nativeAudio.error))).toBe(true) + const state = await page.evaluate(() => ({ canPlay: window.nativeAudio.canPlayType('audio/wav'), readyState: window.nativeAudio.readyState, error: window.nativeAudio.error?.code || null, playerCreated: Boolean(window.art) })) + expect(state.playerCreated).toBe(false) + await testInfo.attach('native-wav-capability', { contentType: 'application/json', body: JSON.stringify(state) }) + if (!state.error) { + await page.evaluate(() => window.nativeAudio.play()) + await expect.poll(() => page.evaluate(() => window.nativeAudio.currentTime)).toBeGreaterThan(0.2) + } + else { + expect(state.error).toBe(4) + } + await page.evaluate(() => { + window.nativeAudio.pause() + window.nativeAudio.removeAttribute('src') + window.nativeAudio.load() + }) +}) + +test('published AUDIO-LIFE-01: empty src cleanup produces a native media error', async ({ page }, testInfo) => { + await openAudio(page, 'published', 'published', testInfo) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(0.2) + await page.evaluate(() => window.art.destroy()) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.error?.code)).toBe(4) + expect(await page.evaluate(() => window.audioPlugin.audio.getAttribute('src'))).toBe('') + expect(await page.evaluate(() => window.audioPlugin.audio.readyState)).toBe(0) +}) + +for (const core of ['published', 'candidate']) { + test(`${core} core + published audio: native pause and end leave external audio playing`, async ({ page }, testInfo) => { + await openAudio(page, core, 'published', testInfo) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(0.2) + await page.evaluate(() => window.art.video.pause()) + expect(await page.evaluate(() => window.art.video.paused)).toBe(true) + expect(await page.evaluate(() => window.audioPlugin.audio.paused)).toBe(false) + await page.evaluate(() => { + window.art.seek = 7.8 + window.art.play() + }) + await expect.poll(() => page.evaluate(() => window.art.video.ended)).toBe(true) + expect(await page.evaluate(() => window.audioPlugin.audio.paused)).toBe(false) + await testInfo.attach('published-native-pause-end', { contentType: 'application/json', body: JSON.stringify(await page.evaluate(() => ({ videoEnded: window.art.video.ended, videoPaused: window.art.video.paused, audioPaused: window.audioPlugin.audio.paused, audioTime: window.audioPlugin.audio.currentTime }))) }) + await page.evaluate(() => window.art.destroy()) + }) + + for (const plugin of ['published', 'source']) { + test(`${core} core + ${plugin} audio: decoded play, offset seek, rate, source and cleanup`, async ({ page }, testInfo) => { + await openAudio(page, core, plugin, testInfo) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(0.3) + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(0.3) + expect(await page.evaluate(() => window.audioPlugin.audio.duration)).toBe(16) + // Windows WebKit may expose layout size; decoded pixels are the playback evidence. + const pixel = await page.evaluate(() => { + const canvas = document.createElement('canvas') + canvas.width = 80 + canvas.height = 45 + const context = canvas.getContext('2d') + context.drawImage(window.art.video, 0, 0, 80, 45) + return [...context.getImageData(30, 2, 1, 1).data] + }) + expect(pixel[0]).toBeGreaterThan(180) + expect(pixel[1]).toBeGreaterThan(180) + expect(pixel[2]).toBeLessThan(80) + await testInfo.attach('decoded-frame-pixel', { contentType: 'application/json', body: JSON.stringify(pixel) }) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.seekable.length && window.audioPlugin.audio.seekable.end(0))).toBeGreaterThan(2.25) + await page.evaluate(() => { + window.art.pause() + window.audioPlugin.update({ offset: 0.25 }) + window.art.seek = 2 + }) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.paused)).toBe(true) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeCloseTo(2.25, 1) + await page.evaluate(() => { + window.art.playbackRate = 1.5 + window.art.volume = 0.4 + }) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.playbackRate)).toBe(1.5) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.volume)).toBeCloseTo(0.4) + await page.locator('#play').click() + await page.evaluate(() => { + window.originalAudio = window.audioPlugin.audio + window.audioPlugin.update({ url: '/test/audio-tone.m4a?source=second' }) + }) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentSrc)).toContain('source=second') + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.paused)).toBe(false) + await expect.poll(() => page.evaluate(() => Math.abs(window.audioPlugin.audio.currentTime - window.art.currentTime - 0.25))).toBeLessThan(0.5) + expect(await page.evaluate(() => window.originalAudio === window.audioPlugin.audio)).toBe(true) + await page.evaluate(() => { + window.art.pause() + window.art.destroy() + }) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.readyState)).toBe(0) + expect(await page.evaluate(() => window.audioPlugin.audio.getAttribute('src'))).toBe('') + expect(await page.evaluate(() => window.audioPlugin.audio.paused)).toBe(true) + expect(await page.locator('.art-video-player').count()).toBe(0) + }) + + test(`${core} core + ${plugin} audio: real load error can recover with a new source`, async ({ page }, testInfo) => { + await openAudio(page, core, plugin, testInfo, '') + await page.route('**/audio-fixture/broken.m4a', route => route.fulfill({ status: 503, body: 'Intentional media failure' })) + await page.evaluate(() => window.audioPlugin.update({ url: '/audio-fixture/broken.m4a' })) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.error?.code)).toBe(4) + expect(await page.evaluate(() => window.art.video.error)).toBeNull() + await page.evaluate(() => window.audioPlugin.update({ url: '/test/audio-tone.m4a?source=recovered' })) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.readyState)).toBeGreaterThanOrEqual(2) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(0.3) + expect(await page.evaluate(() => window.audioPlugin.audio.error)).toBeNull() + await page.evaluate(() => window.art.destroy()) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.readyState)).toBe(0) + expect(await page.evaluate(() => window.audioPlugin.audio.paused)).toBe(true) + expect(await page.evaluate(() => window.audioPlugin.audio.getAttribute('src'))).toBe('') + }) + } +} diff --git a/test/browser/media/audio-tone.json b/test/browser/media/audio-tone.json new file mode 100644 index 000000000..39ab50d0d --- /dev/null +++ b/test/browser/media/audio-tone.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "command": "ffmpeg -hide_banner -loglevel error -f lavfi -i sine=frequency=440:sample_rate=48000:duration=16 -ac 1 -c:a aac -b:a 64k -map_metadata -1 -movflags +faststart test/browser/media/audio-tone.m4a", + "ffmpeg": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "probe": { + "programs": [], + "stream_groups": [], + "streams": [ + { + "codec_name": "aac", + "codec_type": "audio", + "sample_rate": "48000", + "channels": 1 + } + ], + "format": { + "duration": "16.000000" + } + } +} diff --git a/test/browser/media/audio-tone.m4a b/test/browser/media/audio-tone.m4a new file mode 100644 index 0000000000000000000000000000000000000000..edad923b8d6415eebccb8e207de0b72849a434e5 GIT binary patch literal 132436 zcmafa1zZ-*zb_b|lt?3?q=0m%C=$}$B}jK8EhQb&UD7E?cO%^(E!`m9Ja@Auz+ip%t53S~|eN!I_ym z80kUje_Z!B;NV_=hJ%L#|Ni^>A2(3(|GIzk-<1Ei+&wrr)G0d~9aE@M!_M@t&insC z_^&ib?|)zLe+&PYp8tRy=Z{cqpv zKEol`!zs4^<)kyxGqd?u2Ar*>y~SM~r1H?c-g_MjJu`hkgK}+dY+(Rp&~45Chfs38 zf658h^>+uG@xL3tBfJKMX)05odmR;<8KaDn@OE_gU}kbz7E z7rVZ#9&i}${^!r1DIl^3P>TBo8x+A^t^+)TN*+G-S6YQbfO7CqQ^4Wb+Wid^Ac7>{ z+y5ILC~S}gA3-5>0geCGffRWNs&oEZ^Y=f%1J?{;8$t?%Gzi}ybV3+|&;g+uLJWjb z2-y(AAcR1G?1F28kOUzbLIs3g2!RlSAS6R*gU||L1VSZ*8VH#X3LyZVI0&f_q97DQ z$c69&Ldm}X^?eY4o-7De5CDH8gaQaf5P)8P2;mT#A>=^-w7`c%2te<52!IFJ4)g%~ zfSgeXKnAcC=mI>zS3nQSCLjR%bO^wApdX|_Ca@9c0d@czKzwo_fO_D!4}?evz`r>N zpbqe7KmhWAj9>`BM!;VS0niRX0P*O80BiyJ^C6T$xQiQTlLQF;5P%Kw5P&^*Hi9+; z_aFs+1N(tqpdaKx9f%WX51^wH0`M1<0e@m4q(SJ00NS@40^k8Ufj%G;_>cmj83K?E z%7Guihr9Ly<#)CK|AEhdrv(Dg1!Mz%BOm};Km%+_gHR6vv-9iRbr0y&`F04>M^d3Q2^J$EueTmbH5 z0e=C2eZU{U2WWvUcX0;vz%Jl>8U(-#cmNHE9iRjJfDh0CeV`u50(OE}fIJwxU`*ZV z2KECUa1ZLhI7ov4d;sM@4v-D#fUdj#1^Nl_5zKwS=R2LiPQU|n0sVJ!03DzQb^v*x z9P|m$K7jr|`v;%{{RXrzkPT#lG5}x)kPCbOHh{JVbaycavhHF9WPq5YL1_Fp4|oAR zD8I`Czd#!UMKS4d<1N1;Hkas8hjvkbO zcmq3t&43@+4dM%UfGlti=1E{5xWBXKPCw8E9#p0|EF2 zcmNIH0dznQ=p&%bKsnG4YzK891!X`#pucN>kO%TXyWP!acXc2IG665J^=?c6`M?$+ z3#7mfKnMJ~({XnXVgl+x3hV*Az+a#X*a~a|Wq=oy0iD1mzz^zxe830pfoxz4hz;ly zpzN;C0$V^ipar%9c|Z@S2XcWNAP>|5K424wGniB2Ab@rQ_kae-0W_ct*mGwCkOQ6( zU~B;%U^lP__y+Xf0muQmfebLt!Se*j0k(lSgA|kj8-cE92zN08Ddooc z&;dE%9`s=_=D-*P{(*boBk2Et2j~Lv0V%K(*aOBjkO5)_J$OUox&#?f?0WXLdNbmH4nB4U}5J%9yAQphP4+5wIw16Mz1#&_D z&NgrlZ1@QQ&;i+?4EO zHU4LZMxJM93CtkW)A`E`1j0$^I2f=q)3ehvF|t6nj|^<|_2J-8z04t^`Fo)HBUH`A z1=Tac-80Hp-TWhojI0*#QMFLCbv<8YGg6>P?x-*pLH>wx^UGR?@wQ=EaX5FKmnx;f zBK)8ho49C3^`J9@){=ek=x{Yr-JlC@=3zld!VkWH8dVD=^{8D_g23vjVs?|h<6V

Qb?W6p#jj+= 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%0D&QiGdA`s`K;9yIX)Kx^n8F@HDH0i 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 Promise.resolve() + class Audio { + constructor() { + instances.push(this) + this.calls = [] + this.paused = true + for (const [name, initial] of Object.entries({ src: '', preload: '', currentTime: 0, playbackRate: 1, volume: 1, muted: false })) { + let value = initial + Object.defineProperty(this, name, { + get: () => value, + set: (next) => { + this.calls.push([name, next]) + value = next + }, + }) + } + } + + play() { + this.calls.push(['play']) + return play(this) + } + + pause() { this.calls.push(['pause']) } + load() { this.calls.push(['load']) } + } + const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'Audio') + Object.defineProperty(globalThis, 'Audio', { configurable: true, value: Audio }) + t.after(() => descriptor ? Object.defineProperty(globalThis, 'Audio', descriptor) : Reflect.deleteProperty(globalThis, 'Audio')) + t.mock.method(console, 'warn', error => warnings.push(error)) + return { ...createAudioArt(), instances, warnings, setPlay: callback => play = callback } +} + +export function createAudioArt() { + const listeners = new Map() + const art = { + video: { playbackRate: 1.25 }, + currentTime: 0, + playing: false, + volume: 0.6, + muted: false, + on(event, callback) { + if (!listeners.has(event)) + listeners.set(event, new Set()) + listeners.get(event).add(callback) + return art + }, + off(event, callback) { + listeners.get(event)?.delete(callback) + return art + }, + emit(event, ...args) { + for (const callback of [...(listeners.get(event) || [])]) + callback(...args) + return art + }, + } + return { art, listeners } +}