From d18c5456752872d6d635f5a8607f86279e81e071 Mon Sep 17 00:00:00 2001 From: Harvey Zhao Date: Sat, 12 Sep 2026 03:58:39 +0800 Subject: [PATCH] fix(audio): [PKG-AUDIO-05] checkpoint zero-time resume and native buffering evidence --- docs/compiled/artplayer-plugin-audio-track.js | 2 +- .../artplayer-plugin-audio-track.legacy.js | 2 +- .../compiled/artplayer-plugin-audio-track.mjs | 18 +- package.json | 2 +- .../ARCHITECTURE.md | 7 + .../dist/artplayer-plugin-audio-track.js | 2 +- .../artplayer-plugin-audio-track.legacy.js | 2 +- .../dist/artplayer-plugin-audio-track.mjs | 18 +- .../artplayer-plugin-audio-track/src/index.ts | 21 +- refactor/audio-validation.md | 42 + .../audio-combinations-checkpoint.json | 13767 ++++++++++++++++ .../2026-09-12-PKG-AUDIO-05-combinations.md | 44 + refactor/plan.md | 6 +- refactor/progress.md | 16 + refactor/risk-table.md | 3 +- refactor/risks.json | 39 +- refactor/tasks.json | 6 +- test/audio-track.test.js | 38 + test/browser/README.md | 22 + test/browser/audio-buffering.spec.js | 62 + test/browser/audio-combinations.spec.js | 45 +- test/browser/audio-fixture.js | 4 +- test/browser/media-gate-native.spec.js | 63 + test/helpers/media-gate.js | 90 + test/media-gate.test.js | 84 + 25 files changed, 14373 insertions(+), 32 deletions(-) create mode 100644 refactor/baselines/audio-combinations-checkpoint.json create mode 100644 test/browser/audio-buffering.spec.js create mode 100644 test/browser/media-gate-native.spec.js create mode 100644 test/helpers/media-gate.js create mode 100644 test/media-gate.test.js diff --git a/docs/compiled/artplayer-plugin-audio-track.js b/docs/compiled/artplayer-plugin-audio-track.js index a11e2781b..69c7f2693 100644 --- a/docs/compiled/artplayer-plugin-audio-track.js +++ b/docs/compiled/artplayer-plugin-audio-track.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{const o=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch{}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:n}=o,a=[];let i=!0;function u(){t.video&&o.sync(t.currentTime)}function c(e,o){const n=()=>{i&&o()};a.push([e,n]),t.on(e,n)}function r(){if(!i)return;i=!1;const e=[];for(const[o,i]of a.splice(0))try{t.off(o,i)}catch(n){e.push(n)}try{o.destroy()}catch(n){e.push(n)}if(e.length)throw e[0]}try{c("play",()=>{u(),o.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])c(e,o.pause);c("seek",u),c("video:seeked",()=>{u(),t.playing&&o.play()}),c("video:timeupdate",()=>{t.playing&&u()}),c("video:ratechange",()=>{n.playbackRate=t.video.playbackRate}),c("video:volumechange",()=>{n.volume=t.volume,n.muted=t.muted}),c("video:playing",()=>{t.playing&&(u(),o.play())}),c("destroy",r),n.volume=t.volume,n.muted=t.muted,n.playbackRate=t.video?.playbackRate||1}catch(d){try{r()}catch{}throw d}return{name:"artplayerPluginAudioTrack",audio:n,update(e){i&&o.update(e,t.playing)}}}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{const o=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch{}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:n}=o,a=[];let i=!0;function u(){t.video&&o.sync(t.currentTime)}function c(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function r(e,o){const n=()=>{i&&o()};a.push([e,n]),t.on(e,n)}function d(){if(!i)return;i=!1;const e=[];for(const[o,i]of a.splice(0))try{t.off(o,i)}catch(n){e.push(n)}try{o.destroy()}catch(n){e.push(n)}if(e.length)throw e[0]}try{r("play",()=>{u(),o.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])r(e,o.pause);r("seek",u),r("video:seeked",()=>{u(),c()&&o.play()}),r("video:timeupdate",()=>{t.playing&&u()}),r("video:ratechange",()=>{n.playbackRate=t.video.playbackRate}),r("video:volumechange",()=>{n.volume=t.volume,n.muted=t.muted}),r("video:playing",()=>{c()&&(u(),o.play())}),r("video:canplay",()=>{n.paused&&c()&&(u(),o.play())}),r("destroy",d),n.volume=t.volume,n.muted=t.muted,n.playbackRate=t.video?.playbackRate||1}catch(s){try{d()}catch{}throw s}return{name:"artplayerPluginAudioTrack",audio:n,update(e){i&&o.update(e,t.playing)}}}}}); diff --git a/docs/compiled/artplayer-plugin-audio-track.legacy.js b/docs/compiled/artplayer-plugin-audio-track.legacy.js index 9872bf07a..12cd4abb8 100644 --- a/docs/compiled/artplayer-plugin-audio-track.legacy.js +++ b/docs/compiled/artplayer-plugin-audio-track.legacy.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{var o;const n=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch(d){}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:a}=n,i=[];let u=!0;function c(){t.video&&n.sync(t.currentTime)}function r(e,o){const n=()=>{u&&o()};i.push([e,n]),t.on(e,n)}function d(){if(!u)return;u=!1;const e=[];for(const[n,a]of i.splice(0))try{t.off(n,a)}catch(o){e.push(o)}try{n.destroy()}catch(o){e.push(o)}if(e.length)throw e[0]}try{r("play",()=>{c(),n.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])r(e,n.pause);r("seek",c),r("video:seeked",()=>{c(),t.playing&&n.play()}),r("video:timeupdate",()=>{t.playing&&c()}),r("video:ratechange",()=>{a.playbackRate=t.video.playbackRate}),r("video:volumechange",()=>{a.volume=t.volume,a.muted=t.muted}),r("video:playing",()=>{t.playing&&(c(),n.play())}),r("destroy",d),a.volume=t.volume,a.muted=t.muted,a.playbackRate=(null==(o=t.video)?void 0:o.playbackRate)||1}catch(s){try{d()}catch(l){}throw s}return{name:"artplayerPluginAudioTrack",audio:a,update(e){u&&n.update(e,t.playing)}}}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{var o;const n=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch(d){}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:a}=n,i=[];let u=!0;function c(){t.video&&n.sync(t.currentTime)}function r(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function d(e,o){const n=()=>{u&&o()};i.push([e,n]),t.on(e,n)}function l(){if(!u)return;u=!1;const e=[];for(const[n,a]of i.splice(0))try{t.off(n,a)}catch(o){e.push(o)}try{n.destroy()}catch(o){e.push(o)}if(e.length)throw e[0]}try{d("play",()=>{c(),n.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])d(e,n.pause);d("seek",c),d("video:seeked",()=>{c(),r()&&n.play()}),d("video:timeupdate",()=>{t.playing&&c()}),d("video:ratechange",()=>{a.playbackRate=t.video.playbackRate}),d("video:volumechange",()=>{a.volume=t.volume,a.muted=t.muted}),d("video:playing",()=>{r()&&(c(),n.play())}),d("video:canplay",()=>{a.paused&&r()&&(c(),n.play())}),d("destroy",l),a.volume=t.volume,a.muted=t.muted,a.playbackRate=(null==(o=t.video)?void 0:o.playbackRate)||1}catch(s){try{l()}catch(p){}throw s}return{name:"artplayerPluginAudioTrack",audio:a,update(e){u&&n.update(e,t.playing)}}}}}); diff --git a/docs/compiled/artplayer-plugin-audio-track.mjs b/docs/compiled/artplayer-plugin-audio-track.mjs index 55583c8bd..450af29e3 100644 --- a/docs/compiled/artplayer-plugin-audio-track.mjs +++ b/docs/compiled/artplayer-plugin-audio-track.mjs @@ -84,6 +84,14 @@ function artplayerPluginAudioTrack(option) { if (art.video) track.sync(art.currentTime); } + function canResumeAudio() { + const video = art.video; + if (!video) + return false; + if ("playing" in video && typeof video.playing === "boolean") + return video.playing; + return art.playing || video.paused === false && !video.ended && video.readyState > 2; + } function listen(event, callback) { const listener = () => { if (active) @@ -122,7 +130,7 @@ function artplayerPluginAudioTrack(option) { listen("seek", syncAudio); listen("video:seeked", () => { syncAudio(); - if (art.playing) + if (canResumeAudio()) track.play(); }); listen("video:timeupdate", () => { @@ -137,7 +145,13 @@ function artplayerPluginAudioTrack(option) { audio.muted = art.muted; }); listen("video:playing", () => { - if (art.playing) { + if (canResumeAudio()) { + syncAudio(); + track.play(); + } + }); + listen("video:canplay", () => { + if (audio.paused && canResumeAudio()) { syncAudio(); track.play(); } diff --git a/package.json b/package.json index 92b5b7398..b343c6dfc 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "check:toolchain": "node scripts/check-toolchain.mjs", "lint:fix": "eslint \"packages/*/{src,public,types,package.json}\" \"scripts/*.{js,mjs}\" \"test/*\" \"docs/assets/ts/*\" \"types/*.d.ts\" \"playwright*.config.js\" --fix", "check:plan": "node refactor/scripts/plan.mjs --check", - "test:node": "yarn test:unit && node --test test/toolchain.test.js test/build-docs.test.js test/package-check.test.js test/declarations.test.js test/editor-types.test.js test/coverage.test.js test/performance-report.test.js", + "test:node": "yarn test:unit && node --test test/toolchain.test.js test/build-docs.test.js test/package-check.test.js test/declarations.test.js test/editor-types.test.js test/coverage.test.js test/performance-report.test.js test/media-gate.test.js", "test:baseline": "node --test refactor/scripts/*.test.mjs", "ci:check": "yarn check:toolchain --strict && yarn check:plan && yarn lint && yarn check:types && yarn typecheck && yarn test", "ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports", diff --git a/packages/artplayer-plugin-audio-track/ARCHITECTURE.md b/packages/artplayer-plugin-audio-track/ARCHITECTURE.md index efd72c0f4..197feec14 100644 --- a/packages/artplayer-plugin-audio-track/ARCHITECTURE.md +++ b/packages/artplayer-plugin-audio-track/ARCHITECTURE.md @@ -26,6 +26,13 @@ pause audio; seeked synchronizes and resumes only if the video is playing. Nativ synchronizes again before resume. Ordinary playing timeupdate retains the strict drift threshold and offset rule. Rate and volume/mute follow the existing core properties. +The entry owns 15 subscriptions. Resume checks respect an explicit proxy video.playing +boolean first. For native media they also accept an unpaused, non-ended video with +readyState > 2 at currentTime zero: the historical art.playing getter requires time > 0, +which can otherwise leave audio paused after the seek associated with a source switch. +If seeked arrives before readiness, canplay synchronizes and resumes only paused audio +whose host is playing. A paused host or proxy playing=false must never trigger recovery. + Destroy marks the entry inactive before removing listeners. The track then closes before pausing, removing the src attribute and loading the empty element. Cleanup attempts all steps even when a consumer-overridden method throws, then propagates the first cleanup error. diff --git a/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js b/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js index a11e2781b..69c7f2693 100644 --- a/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js +++ b/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{const o=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch{}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:n}=o,a=[];let i=!0;function u(){t.video&&o.sync(t.currentTime)}function c(e,o){const n=()=>{i&&o()};a.push([e,n]),t.on(e,n)}function r(){if(!i)return;i=!1;const e=[];for(const[o,i]of a.splice(0))try{t.off(o,i)}catch(n){e.push(n)}try{o.destroy()}catch(n){e.push(n)}if(e.length)throw e[0]}try{c("play",()=>{u(),o.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])c(e,o.pause);c("seek",u),c("video:seeked",()=>{u(),t.playing&&o.play()}),c("video:timeupdate",()=>{t.playing&&u()}),c("video:ratechange",()=>{n.playbackRate=t.video.playbackRate}),c("video:volumechange",()=>{n.volume=t.volume,n.muted=t.muted}),c("video:playing",()=>{t.playing&&(u(),o.play())}),c("destroy",r),n.volume=t.volume,n.muted=t.muted,n.playbackRate=t.video?.playbackRate||1}catch(d){try{r()}catch{}throw d}return{name:"artplayerPluginAudioTrack",audio:n,update(e){i&&o.update(e,t.playing)}}}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{const o=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch{}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:n}=o,a=[];let i=!0;function u(){t.video&&o.sync(t.currentTime)}function c(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function r(e,o){const n=()=>{i&&o()};a.push([e,n]),t.on(e,n)}function d(){if(!i)return;i=!1;const e=[];for(const[o,i]of a.splice(0))try{t.off(o,i)}catch(n){e.push(n)}try{o.destroy()}catch(n){e.push(n)}if(e.length)throw e[0]}try{r("play",()=>{u(),o.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])r(e,o.pause);r("seek",u),r("video:seeked",()=>{u(),c()&&o.play()}),r("video:timeupdate",()=>{t.playing&&u()}),r("video:ratechange",()=>{n.playbackRate=t.video.playbackRate}),r("video:volumechange",()=>{n.volume=t.volume,n.muted=t.muted}),r("video:playing",()=>{c()&&(u(),o.play())}),r("video:canplay",()=>{n.paused&&c()&&(u(),o.play())}),r("destroy",d),n.volume=t.volume,n.muted=t.muted,n.playbackRate=t.video?.playbackRate||1}catch(s){try{d()}catch{}throw s}return{name:"artplayerPluginAudioTrack",audio:n,update(e){i&&o.update(e,t.playing)}}}}}); diff --git a/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js b/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js index 9872bf07a..12cd4abb8 100644 --- a/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js +++ b/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js @@ -4,4 +4,4 @@ * (c) 2017-2026 Harvey Zhao * Released under the MIT License. */ -!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{var o;const n=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch(d){}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:a}=n,i=[];let u=!0;function c(){t.video&&n.sync(t.currentTime)}function r(e,o){const n=()=>{u&&o()};i.push([e,n]),t.on(e,n)}function d(){if(!u)return;u=!1;const e=[];for(const[n,a]of i.splice(0))try{t.off(n,a)}catch(o){e.push(o)}try{n.destroy()}catch(o){e.push(o)}if(e.length)throw e[0]}try{r("play",()=>{c(),n.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])r(e,n.pause);r("seek",c),r("video:seeked",()=>{c(),t.playing&&n.play()}),r("video:timeupdate",()=>{t.playing&&c()}),r("video:ratechange",()=>{a.playbackRate=t.video.playbackRate}),r("video:volumechange",()=>{a.volume=t.volume,a.muted=t.muted}),r("video:playing",()=>{t.playing&&(c(),n.play())}),r("destroy",d),a.volume=t.volume,a.muted=t.muted,a.playbackRate=(null==(o=t.video)?void 0:o.playbackRate)||1}catch(s){try{d()}catch(l){}throw s}return{name:"artplayerPluginAudioTrack",audio:a,update(e){u&&n.update(e,t.playing)}}}}}); +!function(e,t){"object"===typeof exports&&"undefined"!==typeof module?module.exports=t():"function"==typeof define&&define.amd?(e.artplayerPluginAudioTrack=t(),define(function(){return e.artplayerPluginAudioTrack})):(e="undefined"!==typeof globalThis?globalThis:e||self).artplayerPluginAudioTrack=t()}(this,function(){"use strict";return function(e){return t=>{var o;const n=function(e){let{url:t,offset:o=0,sync:n=.3}=e;const a=new Audio;let i=!1;function u(){!i&&t&&a.play().catch(e=>{i||console.warn(e)})}function c(){if(i)return;i=!0;const e=[];for(const o of[()=>a.pause(),()=>a.removeAttribute("src"),()=>a.load()])try{o()}catch(t){e.push(t)}if(e.length)throw e[0]}try{a.preload="auto",t&&(a.src=t)}catch(r){try{c()}catch(d){}throw r}return{audio:a,play:u,pause:function(){i||a.pause()},destroy:c,sync(e){if(i||!t)return;const u=e+o;Math.abs(a.currentTime-u)>n&&(a.currentTime=u)},update(e,c){i||(e.url&&e.url!==t&&(t=e.url,a.src=t,c&&u()),void 0!==e.offset&&(o=e.offset),void 0!==e.sync&&(n=e.sync))}}}(e),{audio:a}=n,i=[];let u=!0;function c(){t.video&&n.sync(t.currentTime)}function r(){const e=t.video;return!!e&&("playing"in e&&"boolean"===typeof e.playing?e.playing:t.playing||!1===e.paused&&!e.ended&&e.readyState>2)}function d(e,o){const n=()=>{u&&o()};i.push([e,n]),t.on(e,n)}function l(){if(!u)return;u=!1;const e=[];for(const[n,a]of i.splice(0))try{t.off(n,a)}catch(o){e.push(o)}try{n.destroy()}catch(o){e.push(o)}if(e.length)throw e[0]}try{d("play",()=>{c(),n.play()});for(const e of["pause","video:pause","video:ended","video:waiting","video:emptied","video:seeking"])d(e,n.pause);d("seek",c),d("video:seeked",()=>{c(),r()&&n.play()}),d("video:timeupdate",()=>{t.playing&&c()}),d("video:ratechange",()=>{a.playbackRate=t.video.playbackRate}),d("video:volumechange",()=>{a.volume=t.volume,a.muted=t.muted}),d("video:playing",()=>{r()&&(c(),n.play())}),d("video:canplay",()=>{a.paused&&r()&&(c(),n.play())}),d("destroy",l),a.volume=t.volume,a.muted=t.muted,a.playbackRate=(null==(o=t.video)?void 0:o.playbackRate)||1}catch(s){try{l()}catch(p){}throw s}return{name:"artplayerPluginAudioTrack",audio:a,update(e){u&&n.update(e,t.playing)}}}}}); diff --git a/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.mjs b/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.mjs index 55583c8bd..450af29e3 100644 --- a/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.mjs +++ b/packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.mjs @@ -84,6 +84,14 @@ function artplayerPluginAudioTrack(option) { if (art.video) track.sync(art.currentTime); } + function canResumeAudio() { + const video = art.video; + if (!video) + return false; + if ("playing" in video && typeof video.playing === "boolean") + return video.playing; + return art.playing || video.paused === false && !video.ended && video.readyState > 2; + } function listen(event, callback) { const listener = () => { if (active) @@ -122,7 +130,7 @@ function artplayerPluginAudioTrack(option) { listen("seek", syncAudio); listen("video:seeked", () => { syncAudio(); - if (art.playing) + if (canResumeAudio()) track.play(); }); listen("video:timeupdate", () => { @@ -137,7 +145,13 @@ function artplayerPluginAudioTrack(option) { audio.muted = art.muted; }); listen("video:playing", () => { - if (art.playing) { + if (canResumeAudio()) { + syncAudio(); + track.play(); + } + }); + listen("video:canplay", () => { + if (audio.paused && canResumeAudio()) { syncAudio(); track.play(); } diff --git a/packages/artplayer-plugin-audio-track/src/index.ts b/packages/artplayer-plugin-audio-track/src/index.ts index 839cc2065..821ddbd0b 100644 --- a/packages/artplayer-plugin-audio-track/src/index.ts +++ b/packages/artplayer-plugin-audio-track/src/index.ts @@ -2,7 +2,7 @@ import type Artplayer from 'artplayer' import type { Option, RuntimeResult, UpdateOption } from '../types/artplayer-plugin-audio-track' import { createAudioTrack } from './track' -type AudioEvent = 'play' | 'pause' | 'seek' | 'destroy' | 'video:pause' | 'video:ended' | 'video:waiting' | 'video:emptied' | 'video:seeking' | 'video:seeked' | 'video:timeupdate' | 'video:ratechange' | 'video:volumechange' | 'video:playing' +type AudioEvent = 'play' | 'pause' | 'seek' | 'destroy' | 'video:pause' | 'video:ended' | 'video:waiting' | 'video:emptied' | 'video:seeking' | 'video:seeked' | 'video:timeupdate' | 'video:ratechange' | 'video:volumechange' | 'video:playing' | 'video:canplay' export default function artplayerPluginAudioTrack(option: Option) { return (art: Artplayer): RuntimeResult => { @@ -16,6 +16,15 @@ export default function artplayerPluginAudioTrack(option: Option) { track.sync(art.currentTime) } + function canResumeAudio() { + const video = art.video + if (!video) + return false + if ('playing' in video && typeof video.playing === 'boolean') + return video.playing + return art.playing || (video.paused === false && !video.ended && video.readyState > 2) + } + function listen(event: AudioEvent, callback: () => void) { const listener = () => { if (active) @@ -54,7 +63,7 @@ export default function artplayerPluginAudioTrack(option: Option) { listen('seek', syncAudio) listen('video:seeked', () => { syncAudio() - if (art.playing) + if (canResumeAudio()) track.play() }) listen('video:timeupdate', () => { @@ -69,7 +78,13 @@ export default function artplayerPluginAudioTrack(option: Option) { audio.muted = art.muted }) listen('video:playing', () => { - if (art.playing) { + if (canResumeAudio()) { + syncAudio() + track.play() + } + }) + listen('video:canplay', () => { + if (audio.paused && canResumeAudio()) { syncAudio() track.play() } diff --git a/refactor/audio-validation.md b/refactor/audio-validation.md index 7fb3fd887..f40e61d78 100644 --- a/refactor/audio-validation.md +++ b/refactor/audio-validation.md @@ -82,3 +82,45 @@ legacy 首次 WebKit 的“候选核心 + 已发布 audio”结束观察失败 两种结束用例现统一先确认视频/音频 seek 完成且就绪,再确认音频实际恢复推进后才 观测 video.ended,并记录宿主事件;避免原测试因音频早已暂停而误判。相关 WebKit 12 次及最终 main/legacy 各 42 项通过。未证明首次暂停的确切来源,未改生产代码。 + +## PKG-AUDIO-05 恢复播放修复与缓冲检查点 + +CORE-24 后,旧核心与候选 audio 的 WebKit 快速切源仍可复现音频暂停。补充宿主日志 +后确认 video:seeked 时 video.currentTime=0、paused=false、readyState=4,而 art.playing=false。 +原核心 playing 要求时间大于 0,候选的 seeking 暂停后错过恢复。先前猜测 readyState=2 +并非这次日志的根因。index.ts 现在优先尊重 proxy 的显式 playing 布尔值,原生媒体额外 +接受未暂停、未结束且 readyState>2 的时间零状态;canplay 为 seeked 早于就绪提供守卫恢复。 +公开类型、默认值、偏移算法、update 的同步/真值语义和 audio 元素身份均未改变。 + +受控用例先红后绿,三种实际 JS 产物共 97 项通过;完整 CI 599 项(550+14+35)通过。 +快速切源 WebKit 修复前四次 3 通过/1 失败,修复后四次全部通过;完整媒体和组合测试 +还覆盖两种核心与两种插件。最终报告在本阶段冻结证据中登记,不能把四次专项当成全矩阵。 + +偏移边界使用相同 AAC 的独立原生 Audio 对照。首轮 legacy 的唯一失败来自原生对照 +负 seek 后返回 0.01,而断言严格为 0;已保存报告。起点和时长边界现在都要求原生值 +接近边界、插件接近同场原生值(差值小于 0.05 秒)、非负起点、无媒体错误,并验证 +回到区间内 2.5 秒及实际恢复播放。不是只将候选结果与宽泛常量比较。 + +### 真实缓冲与原生能力限制 + +media-gate.js 用 loopback HTTP 提供固定媒体,先发前缀并扣住尾部,release 后发送原字节。 +三项真实 HTTP 测试覆盖流式正文、完成的部分 Range、HEAD/416/suffix 与强 ETag。 +该文件已加入 test:node,无新增依赖。集成测试要求实际推进后原生 isTrusted waiting, +同时检查视频缓冲暂停外部音频、音频缓冲不暂停视频,以及恢复后的时钟和同步。 + +初轮默认流式 24 项为 Chromium/Firefox 16 通过、Windows WebKit 8 失败;改为完整 +部分 Range 的 WebKit 8 项仍失败。保留两次失败,未提高超时、重试或跳过。失败时 +清理后的空 src/error=4 不能用来判断缓冲失败根因;请求附件现在在页面清理前写入。 +最终同一流式夹具与实际 main/legacy 在 Chromium/Firefox 各 16 项通过;这是限定引擎 +的补充证据,保留先前 Windows WebKit 失败,不代表三引擎完整缓冲验收。 + +独立 media-gate-native.spec.js 确认没有 ArtPlayer 实例,测试两种响应模式。最初使用 +原生默认 preload,Firefox 也无法在放行前推进;与实际插件对齐为 preload=auto 后, +Chromium/Firefox 的八种组合都观测到推进与可信 waiting,Windows WebKit 四种组合 +仍停在约 0、readyState=3/4、paused=false、无错误且没有可信 waiting。全部在放行后 +推进。12 个诊断通过只证明观察和放行后恢复,不等于 12 个真实缓冲验收通过。 + +此证据限定当前 Windows WebKit、固定 MP4/AAC 和两种 HTTP 响应,不能推断真实 Safari +不支持缓冲;更不能为候选忽略 failing 用例。AUDIO-BUFFER-01 保持 open,Audio-05 +仍 doing;需要其他可实际执行的原生环境/输入路径补齐。当前没有已安装 WSL 发行版或 +可用 Docker 命令。物理设备、声音输出、自动播放策略和 Audio-06 的安装/demo 仍未验收。 diff --git a/refactor/baselines/audio-combinations-checkpoint.json b/refactor/baselines/audio-combinations-checkpoint.json new file mode 100644 index 000000000..f668ff3eb --- /dev/null +++ b/refactor/baselines/audio-combinations-checkpoint.json @@ -0,0 +1,13767 @@ +{ + "schemaVersion": 1, + "task": "PKG-AUDIO-05", + "date": "2026-09-12", + "baseCommit": "0218196d", + "status": "incomplete", + "scope": "Audio resume fix and native offset comparisons; buffering remains unaccepted on Windows WebKit. No installed package, physical device, audible output or npm release acceptance.", + "sourceFiles": [ + { + "file": "packages/artplayer-plugin-audio-track/src/index.ts", + "bytes": 3217, + "sha256": "769b3d04261456bfb2c10849486244c9c15529229b658e39e48f8f71403abe49" + }, + { + "file": "packages/artplayer-plugin-audio-track/src/track.ts", + "bytes": 1620, + "sha256": "9c6d587dc881e30a4d55746088d0122da5e0051258303d50d14a8fe5f69be2df" + }, + { + "file": "test/audio-track.test.js", + "bytes": 12397, + "sha256": "283a05933e5e2d3630de80161de962e076b248a3456908102ae435c825d40640" + }, + { + "file": "test/browser/audio-fixture.js", + "bytes": 5322, + "sha256": "41215d454fa48b45b248c4af6992aa3980a059d20ca41f95cff910186849aee3" + }, + { + "file": "test/browser/audio-combinations.spec.js", + "bytes": 9431, + "sha256": "1db548954678c6fbe7b4757f9a1b105926e4c04e2a65af206402902b60210e68" + }, + { + "file": "test/browser/audio-buffering.spec.js", + "bytes": 3906, + "sha256": "cd651c1f16610cde1329770d8e65fbb3c08879e2487e27bdceb1f362d9d259aa" + }, + { + "file": "test/browser/media-gate-native.spec.js", + "bytes": 3654, + "sha256": "961cb3f9a82ae41dbdbf25d4b04c07bc03c475671b0365b92f58f5814f1349a2" + }, + { + "file": "test/helpers/media-gate.js", + "bytes": 3309, + "sha256": "b9bc0e8550739902ed4d94674b53d6c5b35795cd25ddf3e567ed22eed591f385" + }, + { + "file": "test/media-gate.test.js", + "bytes": 3484, + "sha256": "2f27f469011eb13fe451c0ecae27ffa2ede0510ebf011b0f9dc2bf6c8c3dc60b" + } + ], + "artifacts": [ + { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "bytes": 2292, + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "bytes": 2324, + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.mjs", + "bytes": 4407, + "sha256": "9caa5a6e11a2e777760dd2835426842a87d04fb081ea2e7d48c7229035fd89a9" + } + ], + "reports": [ + { + "file": "refactor/.cache/audio05-resume-browser-before.json", + "sha256": "03d2727699416e9ae27f5a78bfd806bae1e1a652c57d67df63118140a793d11e", + "resultDir": "refactor/.cache/audio05-resume-browser-before-results", + "stats": { + "startTime": "2026-09-11T19:28:04.221Z", + "duration": 12777.964, + "expected": 3, + "skipped": 0, + "unexpected": 1, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 22 | await expect.poll(() => page.evaluate(() => window.art.video.currentSrc)).toContain('pair=last')\n 23 | await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentSrc)).toContain('pair=last')\n> 24 | await expect.poll(() => page.evaluate(() => !window.art.video.paused && !window.audioPlugin.audio.paused && window.art.currentTime > 0.3)).toBe(true)\n | ^\n 25 | await expect.poll(() => page.evaluate(() => Math.abs(window.art.currentTime - window.audioPlugin.audio.currentTime))).toBeLessThan(0.5)\n 26 | expect(await page.evaluate(() => window.originalAudio === window.audioPlugin.audio)).toBe(true)\n 27 | await page.evaluate(async () => {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-combinations.spec.js:24:146" + ], + "candidate": { + "file": "workspace source build", + "sha256": "5ede3ac9970c9102fb251b342ca2f40626438d37d975b21b38d2033ba2025472" + }, + "evidence": { + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last", + "attribute": "/test/audio-tone.m4a?pair=last", + "time": 6.2677277, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 16 + ] + ] + }, + "video": { + "src": "http://127.0.0.1:8084/test/pattern.mp4?pair=last", + "attribute": "/test/pattern.mp4?pair=last", + "time": 6.2850211, + "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.0599999, + "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?pair=last" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 0.2329331, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 0.4905903, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 0.75005, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 1.0059406, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 1.2666878, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 1.5236955, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 1.7842786, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 2.0439702, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 2.3051412, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 2.5685032, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 2.832704, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 3.0948822, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 3.3598468, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 3.6233408, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 3.8953308, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 4.1467604, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 4.4086288, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 4.6696784, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 4.9291, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 5.188978, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 5.4462444, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 5.7060956, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + }, + { + "event": "seeked", + "time": 5.9578872, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?pair=last" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.015546, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.0599999, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0207264, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.0599999, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.5227898, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.5081659, + "audioPaused": true + }, + { + "event": "pause", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 0, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "pause", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 0, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "play", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "5ede3ac9970c9102fb251b342ca2f40626438d37d975b21b38d2033ba2025472" + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "5ede3ac9970c9102fb251b342ca2f40626438d37d975b21b38d2033ba2025472" + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "5ede3ac9970c9102fb251b342ca2f40626438d37d975b21b38d2033ba2025472" + } + } + ] + }, + { + "file": "refactor/.cache/audio05-resume-browser-after.json", + "sha256": "d68167eb3e010d2e6826f8b736feb68fa96f7c5995e219fd44f6cb992fa85563", + "resultDir": "refactor/.cache/audio05-resume-browser-after-results", + "stats": { + "startTime": "2026-09-11T19:31:41.214Z", + "duration": 12642.521, + "expected": 4, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + } + } + ] + }, + { + "file": "refactor/.cache/audio05-buffering-first.json", + "sha256": "3eb808cd24e44d5ea36a1ac7659c33cc9f3420c17ad2f87d95f54ef28678a2d9", + "resultDir": "refactor/.cache/audio05-buffering-first-results", + "stats": { + "startTime": "2026-09-11T19:33:47.538Z", + "duration": 75490.135, + "expected": 16, + "skipped": 0, + "unexpected": 8, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.051073, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.051073 + } + ] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520204, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.572766 + }, + { + "trusted": true, + "time": 3.70644, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.706691 + }, + { + "trusted": true, + "time": 4.768425, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.768614 + } + ] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.044163, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.044163 + } + ] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520138, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.570272 + }, + { + "trusted": true, + "time": 3.708122, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.708408 + }, + { + "trusted": true, + "time": 4.770338, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.770514 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.051502, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.051502 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520117, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.572616 + }, + { + "trusted": true, + "time": 3.710823, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.711015 + }, + { + "trusted": true, + "time": 4.773836, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.774018 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.056678, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.056678 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520204, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.572764 + }, + { + "trusted": true, + "time": 3.708802, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.709007 + }, + { + "trusted": true, + "time": 4.769417, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.76961 + } + ] + } + } + }, + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.08365, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.08365 + } + ] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.479461, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.480339 + }, + { + "trusted": true, + "time": 4.816293, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.816293 + } + ] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 3, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.106487, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.106487 + } + ] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.468864, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.466854 + }, + { + "trusted": true, + "time": 4.840025, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.840025 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.117204, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.117204 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.465794, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.466638 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.085232, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.085232 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.475024, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.47601 + } + ] + } + } + }, + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "timedOut", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Test timeout of 20000ms exceeded.", + "Error: page.evaluate: Target page, context or browser has been closed\n\n 47 | finally {\n 48 | try {\n> 49 | const events = page.isClosed() ? { closed: true } : await page.evaluate(() => window.starvation)\n | ^\n 50 | await testInfo.attach('media-gate', { contentType: 'application/json', body: JSON.stringify({ file, sha256: hash(bytes), bytes: bytes.length, limit, requests: gate.requests, events }) })\n 51 | if (!page.isClosed())\n 52 | await page.evaluate(() => window.art?.destroy())\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:49:76" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": "/test/audio-tone.m4a", + "time": 0.4685201, + "paused": true, + "readyState": 4, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 16 + ] + ] + }, + "video": { + "src": "http://127.0.0.1:10923/media.mp4", + "attribute": "http://127.0.0.1:10923/media.mp4", + "time": 0, + "paused": true, + "readyState": 2, + "networkState": 2, + "rate": 1, + "seekable": [ + [ + 0, + 8 + ] + ] + }, + "events": [ + { + "event": "loadedmetadata", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0.04, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.4685201, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0085744, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.04, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0089635, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.04, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.5062957, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.4685201, + "audioPaused": true + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 2, + "playing": false, + "audioTime": 0.4685201, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 2, + "playing": false, + "audioTime": 0.4685201, + "audioPaused": true + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 32768, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:11425/media.m4a", + "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:11425/media.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:11425/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:11425/media.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:11425/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0014499, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0135666, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:1040/media.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" + }, + { + "event": "playing", + "time": 0.0304791, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.4145827, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0113469, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.03, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0115762, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.03, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.4164894, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.4145827, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.4145827, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 32768, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:10931/media.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "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:10931/media.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:10931/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:10931/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0085826, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0088334, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:9915/media.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" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.3921661, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0169927, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0175908, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.4350741, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3921661, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.3921661, + "audioPaused": true + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.3921661, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.3921661, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.3921661, + "audioPaused": true + }, + { + "event": "play", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 32768, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:11419/media.m4a", + "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:11419/media.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:11419/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:11419/media.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:11419/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0043108, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0046633, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:9905/media.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" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.3729786, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0209483, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0212516, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.4062749, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3729786, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.3729786, + "audioPaused": true + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.3729786, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 32768, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:11410/media.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "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:11410/media.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:11410/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:11410/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0087447, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0093061, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio05-buffering-range.json", + "sha256": "6324bf0fd37a55a8aaf9b4f6184106b74de09a0339a78eb7fe4bfe6504c3a5a9", + "resultDir": "refactor/.cache/audio05-buffering-range-results", + "stats": { + "startTime": "2026-09-11T19:38:23.771Z", + "duration": 32413.353, + "expected": 0, + "skipped": 0, + "unexpected": 8, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:5142/media.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" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.4431452, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0.0122689, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0067564, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0072316, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.5097273, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.4431452, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0.4431452, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.4431452, + "audioPaused": true + }, + { + "event": "play", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:6523/media.m4a", + "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:6523/media.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:6523/media.m4a" + }, + { + "event": "seeked", + "time": 0.2757954, + "src": "http://127.0.0.1:6523/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:6523/media.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:6523/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0043847, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.004759, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:12415/media.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" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.4191452, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0.0051514, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.010577, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0108101, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.4565386, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.4191452, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.4191452, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0, + "videoPaused": false, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "video:seeking", + "videoTime": 0.0051514, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0.0051514, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:5140/media.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "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:5140/media.m4a" + }, + { + "event": "playing", + "time": 0, + "src": "http://127.0.0.1:5140/media.m4a" + }, + { + "event": "seeked", + "time": 0.270323, + "src": "http://127.0.0.1:5140/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:5140/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0023163, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0094821, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": "", + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 3, + "error": 4, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:6531/media.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" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.3853327, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0.0019365, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0.0019365, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0.0019365, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0056252, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0099037, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.4423159, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3853327, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3853327, + "audioPaused": true + }, + { + "event": "video:seeking", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3853327, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3853327, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0019365, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.4499993, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0019365, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.0019365, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:12412/media.m4a", + "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:12412/media.m4a" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:12412/media.m4a" + }, + { + "event": "seeked", + "time": 0.2705959, + "src": "http://127.0.0.1:12412/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:12412/media.m4a" + }, + { + "event": "error", + "time": 0, + "src": "http://127.0.0.1:12412/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0099985, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0104975, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "rate": 1, + "seekable": [] + }, + "video": { + "src": "http://127.0.0.1:5145/media.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" + }, + { + "event": "playing", + "time": 0.04, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "pause", + "time": 0.5099159, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "playing", + "time": 0.0155212, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0.0155212, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "seeked", + "time": 0.0072245, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0054347, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.04, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.005711, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.04, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.4991899, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.5099159, + "audioPaused": true + }, + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.5099159, + "audioPaused": true + }, + { + "event": "video:seeking", + "videoTime": 0.0055213, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.5099159, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0.0055213, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.0055213, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0072245, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.0055213, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0072245, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.0055213, + "audioPaused": false + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n\nCall Log:\n- Timeout 7000ms exceeded while waiting on the predicate\n\n 28 | if (owner === 'video')\n 29 | await page.evaluate(url => window.art.switchUrl(url), gate.url)\n> 30 | await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true)\n | ^\n 31 | expect(gate.blocked).toBeGreaterThan(0)\n 32 | const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime }))\n 33 | if (owner === 'video') {\n at D:\\github\\ArtPlayer\\test\\browser\\audio-buffering.spec.js:30:148" + ], + "candidate": { + "file": "workspace source build", + "sha256": "c4b37388ecf38c4c33dc172895d2d76d1ffca2587628c01b11b38cfe1852c713" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 0, + "wasHeld": true, + "closed": false + } + ], + "events": [] + }, + "audioState": { + "audio": { + "src": "http://127.0.0.1:6526/media.m4a", + "attribute": null, + "time": 0, + "paused": true, + "readyState": 0, + "networkState": 0, + "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:6526/media.m4a" + }, + { + "event": "playing", + "time": 0.01, + "src": "http://127.0.0.1:6526/media.m4a" + }, + { + "event": "seeked", + "time": 0.2704205, + "src": "http://127.0.0.1:6526/media.m4a" + }, + { + "event": "emptied", + "time": 0, + "src": "http://127.0.0.1:6526/media.m4a" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0101653, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0105265, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + } + ], + "warnings": [] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio05-native-gate.json", + "sha256": "66e004da32035a0e7f3da443bf3cd1cc67b12a1ffbbe89d5852df7825b935e05", + "resultDir": "refactor/.cache/audio05-native-gate-results", + "stats": { + "startTime": "2026-09-11T19:41:53.906Z", + "duration": 13741.815, + "expected": 6, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "native video progressive gate capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "progressed": true, + "waiting": true, + "before": { + "time": 3.058466, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 4 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 4 + }, + { + "event": "playing", + "trusted": true, + "time": 0.008574, + "readyState": 4 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.058466, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.467406, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio progressive gate capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "progressed": true, + "waiting": true, + "before": { + "time": 3.520088, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.520088, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.941515, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video progressive gate capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 0, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 0, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.370381, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio progressive gate capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "progressed": false, + "waiting": false, + "before": { + "time": 0.007338, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 0.007338, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 0, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.33334, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video progressive gate capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "progressed": false, + "waiting": false, + "before": { + "time": 0.0015322, + "readyState": 4, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.0015322, + "readyState": 4 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5418984, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio progressive gate capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 4, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 4 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5886241, + "readyState": 4, + "paused": false + } + } + } + } + ] + }, + { + "file": "refactor/.cache/audio05-native-gate-modes.json", + "sha256": "de64305734cdd5650248c05dfc4a3441d0f813c497fe7f0f4ed56e7439b25143", + "resultDir": "refactor/.cache/audio05-native-gate-modes-results", + "stats": { + "startTime": "2026-09-11T19:44:53.627Z", + "duration": 23539.946, + "expected": 12, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "native video streamed response capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": false, + "progressed": true, + "waiting": true, + "before": { + "time": 3.056878, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 4 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 4 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 4 + }, + { + "event": "playing", + "trusted": true, + "time": 0.007564, + "readyState": 4 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.056878, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.467469, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video complete ranges capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": true, + "progressed": true, + "waiting": true, + "before": { + "time": 3.05782, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.008634, + "readyState": 4 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.05782, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.465331, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio streamed response capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": false, + "progressed": true, + "waiting": true, + "before": { + "time": 3.520093, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.520093, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.933101, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio complete ranges capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": true, + "progressed": true, + "waiting": true, + "before": { + "time": 3.520322, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.520322, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.94277, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video streamed response capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": false, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 0, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.411953, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video complete ranges capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": true, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 0, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 0, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.332938, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio streamed response capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": false, + "progressed": false, + "waiting": false, + "before": { + "time": 0.001457, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 0.001457, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 32768, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.405297, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio complete ranges capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": true, + "progressed": false, + "waiting": false, + "before": { + "time": 0.001535, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 0.001535, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 0, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.364553, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video streamed response capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": false, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 3, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5203526, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video complete ranges capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": true, + "progressed": false, + "waiting": false, + "before": { + "time": 0.001194, + "readyState": 4, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.0010823, + "readyState": 4 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5994215, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio streamed response capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": false, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 3, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5642908, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio complete ranges capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": true, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 4, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 4 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5164575, + "readyState": 4, + "paused": false + } + } + } + } + ] + }, + { + "file": "refactor/.cache/audio05-native-preload.json", + "sha256": "5afa60842860262a5874928fff788141d27579aa40f8c742290cf70abbc930cf", + "resultDir": "refactor/.cache/audio05-native-preload-results", + "stats": { + "startTime": "2026-09-11T19:52:11.881Z", + "duration": 23649.817000000003, + "expected": 12, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "native video streamed response capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": false, + "progressed": true, + "waiting": true, + "before": { + "time": 3.057163, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.007045, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.057163, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.509993, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video complete ranges capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": true, + "progressed": true, + "waiting": true, + "before": { + "time": 3.057933, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.007816, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.057933, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.510883, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio streamed response capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": false, + "progressed": true, + "waiting": true, + "before": { + "time": 3.5201, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.013691, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.5201, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.946327, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio complete ranges capability without ArtPlayer instances", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": true, + "progressed": true, + "waiting": true, + "before": { + "time": 3.520125, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.013439, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.520125, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.9301, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video streamed response capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": false, + "progressed": true, + "waiting": true, + "before": { + "time": 3.124083, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "stalled", + "trusted": true, + "time": 3.041666, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.124083, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.534162, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video complete ranges capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": true, + "progressed": true, + "waiting": true, + "before": { + "time": 3.123058, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "stalled", + "trusted": true, + "time": 3.000305, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.123058, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.528452, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio streamed response capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": false, + "progressed": true, + "waiting": true, + "before": { + "time": 3.480786, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "stalled", + "trusted": true, + "time": 2.915738, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.480786, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.88914, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio complete ranges capability without ArtPlayer instances", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": true, + "progressed": true, + "waiting": true, + "before": { + "time": 3.475381, + "readyState": 2, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 1 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "stalled", + "trusted": true, + "time": 2.990622, + "readyState": 3 + }, + { + "event": "waiting", + "trusted": true, + "time": 3.475381, + "readyState": 2 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 3.879204, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video streamed response capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": false, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 3, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5358984, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native video complete ranges capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "limit": 98304, + "completeRanges": true, + "progressed": false, + "waiting": false, + "before": { + "time": 0.0010975, + "readyState": 4, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0.0009908, + "readyState": 4 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 98303, + "sent": 98304, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-251537", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.3351694, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio streamed response capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": false, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 3, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 3 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5994157, + "readyState": 4, + "paused": false + } + } + } + }, + { + "title": "native audio complete ranges capability without ArtPlayer instances", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "evidence": { + "native-gate-capability": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "limit": 32768, + "completeRanges": true, + "progressed": false, + "waiting": false, + "before": { + "time": 0, + "readyState": 4, + "paused": false, + "error": null, + "instances": 0, + "events": [ + { + "event": "loadedmetadata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "loadeddata", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "canplay", + "trusted": true, + "time": 0, + "readyState": 3 + }, + { + "event": "playing", + "trusted": true, + "time": 0, + "readyState": 4 + } + ] + }, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 32767, + "sent": 32768, + "wasHeld": false, + "closed": true + }, + { + "method": "GET", + "range": "bytes=32768-132435", + "start": 32768, + "end": 132435, + "sent": 99668, + "wasHeld": true, + "closed": true + } + ], + "after": { + "time": 0.5714783, + "readyState": 4, + "paused": false + } + } + } + } + ] + }, + { + "file": "refactor/.cache/audio05-main-final.json", + "sha256": "957d06e2d4d76123f57f88f7bb024eb6c0bbcfcf5f4113bfc6e4286fe2f34af6", + "resultDir": "refactor/.cache/audio05-main-final-results", + "stats": { + "startTime": "2026-09-11T19:48:44.346Z", + "duration": 70371.302, + "expected": 78, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16.01, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + } + ] + }, + { + "file": "refactor/.cache/audio05-legacy-first.json", + "sha256": "d33400253d74833815745c39a7041478b9de5aab5936aba59f00ee81a5ffde1c", + "resultDir": "refactor/.cache/audio05-legacy-first-results", + "stats": { + "startTime": "2026-09-11T19:50:31.712Z", + "duration": 83518.777, + "expected": 77, + "skipped": 0, + "unexpected": 1, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "failed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [ + "Error: expect(received).toEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"error\": null,\n- \"time\": 0,\n+ \"time\": 0.01,\n }\n\n 101 | return { audio: state(window.audioPlugin.audio), native: state(window.boundaryAudio) }\n 102 | })\n> 103 | expect(negative.native).toEqual({ time: 0, error: null })\n | ^\n 104 | expect(negative.audio).toEqual(negative.native)\n 105 | await page.evaluate(() => {\n 106 | window.audioPlugin.update({ offset: 20 })\n at D:\\github\\ArtPlayer\\test\\browser\\audio-combinations.spec.js:103:31" + ], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "audioState": { + "audio": { + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first", + "attribute": "/test/audio-tone.m4a?source=first", + "time": 0, + "paused": true, + "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.5009295, + "paused": true, + "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" + }, + { + "event": "pause", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 0.01, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + }, + { + "event": "seeked", + "time": 0, + "src": "http://127.0.0.1:8084/test/audio-tone.m4a?source=first" + } + ], + "hostEvents": [ + { + "event": "video:canplay", + "videoTime": 0, + "videoPaused": true, + "videoReadyState": 3, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:playing", + "videoTime": 0.0187376, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "play", + "videoTime": 0.0191983, + "videoPaused": false, + "videoReadyState": 4, + "playing": true, + "audioTime": 0.01, + "audioPaused": false + }, + { + "event": "pause", + "videoTime": 0.2779891, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0.3512495, + "audioPaused": true + }, + { + "event": "seek", + "videoTime": 0.5, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:pause", + "videoTime": 0.5, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:seeking", + "videoTime": 0.5, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + }, + { + "event": "video:seeked", + "videoTime": 0.5009295, + "videoPaused": true, + "videoReadyState": 4, + "playing": false, + "audioTime": 0, + "audioPaused": true + } + ], + "warnings": [] + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + } + ] + }, + { + "file": "refactor/.cache/audio05-main-verified.json", + "sha256": "595616e0a145335e4e9b170c3a1a40dd57adb6e059d29582b9c173ab50b9d92f", + "resultDir": "refactor/.cache/audio05-main-verified-results", + "stats": { + "startTime": "2026-09-11T19:53:07.593Z", + "duration": 67652.504, + "expected": 78, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + } + } + ] + }, + { + "file": "refactor/.cache/audio05-legacy-verified.json", + "sha256": "7eb66b1911f23b858e588103979e63def637579951e054f9b1e28cf225479c28", + "resultDir": "refactor/.cache/audio05-legacy-verified-results", + "stats": { + "startTime": "2026-09-11T19:54:16.148Z", + "duration": 67259.5, + "expected": 78, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "published core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + published audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "candidate core + source audio: rapid main/audio switches settle on the last pair", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: two active players keep clocks and ownership independent", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native offset bounds recover to an in-range seek", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "negative-offset-native": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow-offset-native": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "offset-boundary": { + "negative": { + "audio": { + "time": 0, + "error": null + }, + "native": { + "time": 0, + "error": null + } + }, + "overflow": { + "audio": { + "time": 16, + "duration": 16, + "error": null + }, + "native": { + "time": 16, + "duration": 16, + "error": null + } + }, + "recovered": true + } + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "native WAV diagnostic isolates sample decoding from ArtPlayer and plugin", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [] + }, + { + "title": "published AUDIO-LIFE-01: empty src cleanup produces a native media error", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "published core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: native pause/end stop audio and closed references stay inert", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: native pause and end leave external audio playing", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + published audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: decoded play, offset seek, rate, source and cleanup", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + }, + { + "title": "candidate core + source audio: real load error can recover with a new source", + "engine": "webkit", + "status": "passed", + "retry": 0, + "browser": "26.6", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + } + } + ] + }, + { + "file": "refactor/.cache/audio05-buffering-main-verified.json", + "sha256": "938f4aa737edba20d16877fbf5c848a1899467d1b2c71e4067ce1cf78f6c1b1d", + "resultDir": "refactor/.cache/audio05-buffering-main-verified-results", + "stats": { + "startTime": "2026-09-11T19:56:07.265Z", + "duration": 39460.18, + "expected": 16, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.046952, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.046952 + } + ] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520099, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.571896 + }, + { + "trusted": true, + "time": 3.713268, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.713423 + }, + { + "trusted": true, + "time": 4.77619, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.777043 + } + ] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.044984, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.044984 + } + ] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.52009, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.570001 + }, + { + "trusted": true, + "time": 3.709846, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.710125 + }, + { + "trusted": true, + "time": 4.772766, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.772964 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.053599, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.053599 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520191, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.572656 + }, + { + "trusted": true, + "time": 3.717265, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.717479 + }, + { + "trusted": true, + "time": 4.779745, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.780182 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.046969, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.046969 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520086, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.572527 + }, + { + "trusted": true, + "time": 3.710438, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.710666 + }, + { + "trusted": true, + "time": 4.772738, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.772961 + } + ] + } + } + }, + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.091355, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.091355 + } + ] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.472442, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.473147 + }, + { + "trusted": true, + "time": 4.851071, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.851071 + } + ] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.124274, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.124274 + } + ] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.46977, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.470308 + }, + { + "trusted": true, + "time": 4.863898, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.863898 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.085056, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.085056 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.47336, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.473967 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.119118, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.119118 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.js", + "sha256": "23b10856628c5568f1aa7ad88e926c7da8d96edfadf6df872777062a78a4b4be" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.470919, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.472051 + }, + { + "trusted": true, + "time": 4.809731, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.809731 + } + ] + } + } + } + ] + }, + { + "file": "refactor/.cache/audio05-buffering-legacy-verified.json", + "sha256": "4be33788eed7e05fe69fce3d81c4af610437fafab4a7eeec8c02a1e362431c93", + "resultDir": "refactor/.cache/audio05-buffering-legacy-verified-results", + "stats": { + "startTime": "2026-09-11T19:56:47.438Z", + "duration": 39232.465, + "expected": 16, + "skipped": 0, + "unexpected": 0, + "flaky": 0 + }, + "cases": [ + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.057768, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.057768 + } + ] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520129, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.571263 + }, + { + "trusted": true, + "time": 3.718571, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.718916 + }, + { + "trusted": true, + "time": 4.781188, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.781398 + } + ] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.046582, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.046582 + } + ] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520105, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.572026 + }, + { + "trusted": true, + "time": 3.725024, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.725195 + }, + { + "trusted": true, + "time": 4.781138, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.781305 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.057216, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.057216 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520118, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.571326 + }, + { + "trusted": true, + "time": 3.709577, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.710835 + }, + { + "trusted": true, + "time": 4.772257, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.772514 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 98304, + "wasHeld": true, + "closed": true + }, + { + "method": "GET", + "range": "bytes=98304-", + "start": 98304, + "end": 251537, + "sent": 153234, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.056473, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.056473 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "chromium", + "status": "passed", + "retry": 0, + "browser": "153.0.8010.12", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.520133, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.570552 + }, + { + "trusted": true, + "time": 3.717869, + "readyState": 1, + "audioPaused": false, + "videoTime": 3.718226 + }, + { + "trusted": true, + "time": 4.780486, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.780705 + } + ] + } + } + }, + { + "title": "published core + published audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.089564, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.089564 + } + ] + } + } + }, + { + "title": "published core + published audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.456143, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.456461 + }, + { + "trusted": true, + "time": 4.806926, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.806926 + } + ] + } + } + }, + { + "title": "published core + source audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 0, + "readyState": 1, + "audioPaused": true, + "videoTime": 0 + }, + { + "trusted": true, + "time": 3.120104, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.120104 + } + ] + } + } + }, + { + "title": "published core + source audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.466804, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.467978 + }, + { + "trusted": true, + "time": 4.846831, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.846831 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.08836, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.08836 + } + ] + } + } + }, + { + "title": "candidate core + published audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.469772, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.472316 + }, + { + "trusted": true, + "time": 4.808428, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.808428 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real video starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "pattern.mp4", + "sha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "bytes": 251538, + "limit": 98304, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 251537, + "sent": 251538, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.113086, + "readyState": 2, + "audioPaused": true, + "videoTime": 3.113086 + } + ] + } + } + }, + { + "title": "candidate core + source audio: real audio starvation resumes after network release", + "engine": "firefox", + "status": "passed", + "retry": 0, + "browser": "155.0", + "platform": "win32", + "errors": [], + "candidate": { + "file": "packages/artplayer-plugin-audio-track/dist/artplayer-plugin-audio-track.legacy.js", + "sha256": "41b94e84e3d3729b9373cb13de2f64d5ea30b4c36627f38583bf4c3c9bc2160c" + }, + "evidence": { + "mediaGate": { + "file": "audio-tone.m4a", + "sha256": "83e6672b880b5d1c97093b1e26bdc40221c0b279615f40e99dbf9d2ade7b4d56", + "bytes": 132436, + "limit": 32768, + "requests": [ + { + "method": "GET", + "range": "bytes=0-", + "start": 0, + "end": 132435, + "sent": 132436, + "wasHeld": true, + "closed": true + } + ], + "events": [ + { + "trusted": true, + "time": 3.45942, + "readyState": 2, + "audioPaused": false, + "videoTime": 3.460135 + }, + { + "trusted": true, + "time": 4.835629, + "readyState": 1, + "audioPaused": false, + "videoTime": 4.835629 + } + ] + } + } + } + ] + } + ], + "logs": [ + { + "file": "refactor/.cache/audio05-resume-unit-before.log", + "sha256": "4e4ff92741ef962595e8b8ee460cac66c7f81864dc2c0832e2dfae0f06a3c9bb", + "summaries": [ + "ℹ tests 45", + "ℹ pass 44", + "ℹ fail 1", + "ℹ skipped 0" + ] + }, + { + "file": "refactor/.cache/audio05-native-zero-before.log", + "sha256": "ce7385f6763fda2462791c5f32709a6f86a04e00eda2dd5978fe5894ab144377", + "summaries": [ + "ℹ tests 46", + "ℹ pass 44", + "ℹ fail 2", + "ℹ skipped 0" + ] + }, + { + "file": "refactor/.cache/audio05-resume-unit.log", + "sha256": "4eae74a39cc19e02f69d808b7dcf6b81f8133cefdda80e18717bc7c396e67b54", + "summaries": [ + "ℹ tests 46", + "ℹ pass 46", + "ℹ fail 0", + "ℹ skipped 0" + ] + }, + { + "file": "refactor/.cache/audio05-artifacts.log", + "sha256": "74af1d95d806bb405e92e7352b950cd7149cb2178ab54c24110ff6bc8ccc4daa", + "summaries": [ + "ℹ tests 97", + "ℹ pass 97", + "ℹ fail 0", + "ℹ skipped 0" + ] + }, + { + "file": "refactor/.cache/audio05-build.log", + "sha256": "f44c27b9e589b145117edfcd618d91b883e09050dab18b55ba80df087913cbb7", + "summaries": [ + "Done in 1.83s." + ] + }, + { + "file": "refactor/.cache/audio05-ci.log", + "sha256": "f1bdb385889cf6a626f16d3f4d0847ef71298732e8b7af892d1dffb00cd099b1", + "summaries": [ + "ℹ tests 550", + "ℹ pass 550", + "ℹ fail 0", + "ℹ skipped 0", + "ℹ tests 14", + "ℹ pass 14", + "ℹ fail 0", + "ℹ skipped 0", + "ℹ tests 35", + "ℹ pass 35", + "ℹ fail 0", + "ℹ skipped 0", + "Done in 109.95s." + ] + }, + { + "file": "refactor/.cache/audio05-gate-final-unit.log", + "sha256": "24d75e55de687f999f0f368357b3d74c20a243571b6cde0d13f37f61bb13a99b", + "summaries": [ + "ℹ tests 3", + "ℹ pass 3", + "ℹ fail 0", + "ℹ skipped 0" + ] + } + ], + "resultPathNote": "Raw reports retain their original shared output paths. Copied resultDir contains the preserved relative test directories and traces. Cache is local; hashes and these summaries survive in Git. Rerun if cache is missing.", + "remaining": [ + "AUDIO-BUFFER-01: Windows WebKit never reached real starvation for these inputs even without ArtPlayer", + "AUDIO-SYNC-01: full supported environment and playback-policy coverage", + "PKG-AUDIO-06: installed artifacts and 8082 docs demo", + "Physical Safari/iOS/Android and actual sound output" + ] +} diff --git a/refactor/changes/2026-09-12-PKG-AUDIO-05-combinations.md b/refactor/changes/2026-09-12-PKG-AUDIO-05-combinations.md index a9faf5bf5..bf74d0635 100644 --- a/refactor/changes/2026-09-12-PKG-AUDIO-05-combinations.md +++ b/refactor/changes/2026-09-12-PKG-AUDIO-05-combinations.md @@ -22,3 +22,47 @@ Audio-04 的模块边界及旧类型入口不变;发现问题先比较已发 共用输入/事件/清理辅助移入 audio-fixture.js,通过显式 useAudioFixture() 为每个测试 文件注册各自 hooks,避免 import 缓存让后一个 suite 缺输入。原有媒体用例也会重跑。 本阶段只提交明确标注 checkpoint 的测试与发现,未提交生产修复,也未完成 Audio-05。 + +## CORE-24 后恢复实施 + +0218196d 已核实,工作区干净。六项候选核心切源回归已由 CORE-24 修复并重跑原断言。 +Audio-05 恢复 doing;继续旧核心 WebKit 的音频恢复、边界原生对照和真实网络缓冲。 + +## 第二个检查点:已修复时间零恢复,保留缓冲缺口 + +本次有生产修复,仍不是 Audio-05 完成提交。index.ts 的 resume 判断优先采用 proxy +显式 playing 布尔值;原生媒体在时间零、未暂停/未结束且 readyState>2 时也可恢复。 +canplay 只对暂停音频且宿主可播放的状态补恢复,监听仍由当前实例统一解绑。模块职责、 +public 类型、update 同步返回、默认 offset/sync、音频身份和 URL 真值语义不变。 + +修复前日志精确显示 video:playing/seeking/seeked 的时间为 0、readyState=4、paused=false, +而 art.playing=false。不是先前猜测的 readyState=2。先加受控失败用例,修复后源/历史 +共 46 项、三格式产物共 97 项通过。主/legacy 实际构建分别 78 项浏览器测试通过,无重试 +或跳过;每组含 36 新旧组合、原 42 媒体项,其中 9 项历史缺陷观察和 3 项 WAV 原生诊断。 +完整 CI 599 项通过(550 单元、14 工程、35 基线);声明校验和严格类型通过。 +保留生成声明的一条既有 ESLint warning,没有新 lint error。 + +负偏移和超过时长现在与同文件独立原生 Audio 比较。main 首轮 78 通过;legacy 首轮 +77 通过/1 失败,失败是原生负 seek 的实际 0.01 与严格 0 不等。记录此证据后,对两端 +统一使用小于 0.05 秒的原生边界/候选差值断言,同时检查起点非负、无错误及区间内恢复。 +最终 main/legacy 重新执行各 78 项通过。负/超时长的状态在断言之前保存,方便后续诊断。 + +新增 loopback media-gate 及三项真实 HTTP 测试,已纳入 test:node,没有新依赖。 +真实缓冲测试保留完整四种新旧组合和三个引擎的要求,初轮 Chromium/Firefox 16 通过、 +Windows WebKit 8 失败。换为有强 ETag 的完整部分 Range 响应后 WebKit 8 项仍失败; +没有删掉失败用例。原生 preload=auto 对照两种响应形状,证明 Chromium/Firefox 可以推进 +后 waiting,Windows WebKit 此输入则没有推进到缓冲;12 项诊断通过仅证明观测与放行后恢复。 +最初原生默认 preload 导致 Firefox 也不推进,已对齐插件属性,保留前后两个报告。 +此独立原生观察不证明真实 Safari 不支持,也不替代插件实际缓冲验收。 +最终流式夹具对实际 main/legacy 在 Chromium/Firefox 分别执行 16 项,均通过;这是明确 +限定引擎的补充验证,不能覆盖之前保留的 Windows WebKit 失败。 + +证据和报告指纹见 [本次冻结记录](../baselines/audio-combinations-checkpoint.json)。所有首轮失败 +报告/trace 按独立路径保留。原始报告中的附件仍写共用路径,读取时使用记录的复制结果目录; +cache 不入 Git,丢失后应按命令重跑,不能声称旧 trace 永久可用。 + +AUDIO-RESUME-01 按具体切源恢复范围关闭;AUDIO-SYNC-01 与新增 AUDIO-BUFFER-01 +保持 open,任务仍为 doing。下一步需要有效原生环境补齐缓冲,并继续策略/设备要求; +Audio-06 的 tarball/8082 demo 仍待验收。其他独立包可继续,不能将该缺口升级成全局阻塞。 +本检查点未更改包版本、推送、打 tag 或发布。回退整个本次提交可恢复 CORE-24 后的 +候选音频行为;已确认的时间零恢复问题会随生产修复回退而重新出现。 diff --git a/refactor/plan.md b/refactor/plan.md index e3c970cd7..c823704ab 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 217 项,范围 22 个包及工作区/示例。 -状态:todo 146 / doing 1 / blocked 0 / done 70 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 145 / doing 2 / blocked 0 / done 70 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -160,7 +160,7 @@ | 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 | done | | PKG-AUDIO-04 | artplayer-plugin-audio-track
迁移自有源码和公开类型 | PKG-AUDIO-03, ENG-04, ENG-06, CORE-07 | Option/Result/audio、update 输入和事件类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done | -| PKG-AUDIO-05 | artplayer-plugin-audio-track
验证新旧核心和组合 | PKG-AUDIO-04, CORE-22, CORE-24 | 主视频切源和缓冲恢复,多实例独立音频、旧核心 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo | +| PKG-AUDIO-05 | artplayer-plugin-audio-track
验证新旧核心和组合 | PKG-AUDIO-04, CORE-22, CORE-24 | 主视频切源和缓冲恢复,多实例独立音频、旧核心 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | doing | | PKG-AUDIO-06 | artplayer-plugin-audio-track
验证分发并同步文档 | PKG-AUDIO-05, ENG-07 | audio.track.js 示例与运行返回值一致的声明 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo | ## 5 包迁移:artplayer-plugin-auto-thumbnail @@ -472,7 +472,7 @@ - PKG-AUDIO-02: [记录](changes/2026-09-12-PKG-AUDIO-02-tests.md) [记录](audio-validation.md) [记录](baselines/audio-validation.json) - PKG-AUDIO-03: [记录](changes/2026-09-12-PKG-AUDIO-03-lifecycle.md) [记录](baselines/audio-lifecycle-validation.json) - PKG-AUDIO-04: [记录](changes/2026-09-12-PKG-AUDIO-04-types.md) [记录](baselines/audio-types-validation.json) -- PKG-AUDIO-05: [记录](changes/2026-09-12-PKG-AUDIO-05-combinations.md) [记录](baselines/audio-combinations-first.json) +- PKG-AUDIO-05: [记录](changes/2026-09-12-PKG-AUDIO-05-combinations.md) [记录](baselines/audio-combinations-first.json) [记录](baselines/audio-combinations-checkpoint.json) [记录](audio-validation.md) - 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 15c9c7487..f85f785fc 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,21 @@ # 进度与证据 +## 当前实施:Audio-05 恢复修复与真实缓冲检查点 + +已修复旧核心时间零 seek 后候选音频漏恢复,严格 TS 与公开接口不变;三格式 Node 97 项、 +完整 CI 599 项、main/legacy 三引擎媒体和新旧组合各 78 项通过。首次 legacy 原生负 seek +返回 0.01 导致的严格零断言失败已保留,补充边界对照后完整重跑。不是发布或全包验收。 + +独立原生媒体 preload=auto 对照已确认 Chromium/Firefox 可推进后真实 waiting,Windows +WebKit 在两种受限响应下未推进到缓冲,放行后可播放。AUDIO-RESUME-01 关闭, +AUDIO-BUFFER-01 与 AUDIO-SYNC-01 保持 open;没有跳过集成失败或将原生诊断当作通过。 + +当前 217 项:70 done、2 doing、145 todo。Audio-05 和 HLS-SDK-01 尚未完成。 +本批为本地 checkpoint,源码、测试、包内架构与证据一同提交。其余包继续按依赖推进; +分发、设备、完整 CI/CD、各包大版本升级和三轮发布复盘仍待完成,未推送或发布。 +见 [本次变更](changes/2026-09-12-PKG-AUDIO-05-combinations.md) 和 +[冻结证据](baselines/audio-combinations-checkpoint.json)。以下是各阶段当时的历史状态。 + ## 最新完成:CORE-24 连续切源播放意图修复 Audio-05 检查点已提交 b5e96664,原六项候选核心回归保持原断言重跑全部通过。 diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 0e0787b90..4806ba7c0 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -131,4 +131,5 @@ | AUDIO-TYPE-01 | accepted-with-scope / 源码/产物事实 | Audio Track update 部分配置与公开/编辑器声明不一致 | PKG-AUDIO-04 | | AUDIO-DEMO-01 | open / 源码/产物事实 | Audio Track README 示例链接名称不匹配且缺维护说明 | PKG-AUDIO-06 | | CORE-SOURCE-01 | resolved / 已复现 | 候选核心连续切源丢失原播放意图 | CORE-24 | -| AUDIO-RESUME-01 | open / 已复现 | WebKit 旧核心切源后候选音频保持暂停 | PKG-AUDIO-05 | +| AUDIO-RESUME-01 | resolved / 已复现 | WebKit 旧核心切源后候选音频保持暂停 | PKG-AUDIO-05 | +| AUDIO-BUFFER-01 | open / 已复现 | Windows WebKit 原生媒体无法在受限响应下推进至真实缓冲 | PKG-AUDIO-05 | diff --git a/refactor/risks.json b/refactor/risks.json index 708c895a4..bd1125d0b 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -2686,9 +2686,10 @@ "test/audio-track.test.js", "test/browser/audio-track.spec.js", "refactor/baselines/audio-validation.json", - "refactor/baselines/audio-lifecycle-validation.json" + "refactor/baselines/audio-lifecycle-validation.json", + "refactor/baselines/audio-combinations-checkpoint.json" ], - "compatibleResolution": "PKG-AUDIO-03 已修复原生暂停/结束与直接 seek 同步;严格阈值、偏移正负、倍率/音量不变。PKG-AUDIO-05 继续负目标/超时长、真实缓冲和连续切源的完整验证,条目仍 open。", + "compatibleResolution": "03 已修复原生暂停/结束;05 的连续切源和偏移原生对照已验证,真实缓冲 Chromium/Firefox 初轮通过但 Windows WebKit 保留 AUDIO-BUFFER-01;策略/设备缺口继续 open。", "closureCriteria": "正常/边界/失败/缓冲恢复有媒体与受控断言,实际支持环境缺口明确处理。" }, { @@ -2753,15 +2754,43 @@ "id": "AUDIO-RESUME-01", "title": "WebKit 旧核心切源后候选音频保持暂停", "confirmation": "reproduced", + "status": "resolved", + "owners": [ + "PKG-AUDIO-05" + ], + "evidence": [ + "refactor/baselines/audio-combinations-first.json", + "test/audio-track.test.js", + "test/browser/audio-combinations.spec.js", + "refactor/baselines/audio-combinations-checkpoint.json" + ], + "compatibleResolution": "原生时间零且未暂停、未结束、readyState>2 时允许恢复;显式 proxy playing 布尔值优先。canplay 仅恢复暂停且宿主可播放的 audio,保持公开接口与同步算法。", + "closureCriteria": "保留原始失败,精确事件复现并有旧核心/新核心三引擎回归;不可仅重复到绿灯。", + "resolutionEvidence": [ + "refactor/baselines/audio-combinations-checkpoint.json", + "refactor/changes/2026-09-12-PKG-AUDIO-05-combinations.md", + "packages/artplayer-plugin-audio-track/ARCHITECTURE.md" + ], + "resolutionRationale": "失败日志确认 seeked 时间零、readyState=4、paused=false 而 art.playing=false。受控用例先红后绿,实际三格式 97 项通过;main/legacy 每组 78 项含三引擎旧/新核心组合通过。仅关闭此具体恢复缺陷,真实缓冲、策略与设备范围保持开放。" + }, + { + "id": "AUDIO-BUFFER-01", + "title": "Windows WebKit 原生媒体无法在受限响应下推进至真实缓冲", + "confirmation": "reproduced", "status": "open", "owners": [ "PKG-AUDIO-05" ], "evidence": [ - "refactor/baselines/audio-combinations-first.json" + "test/browser/audio-buffering.spec.js", + "test/browser/media-gate-native.spec.js", + "test/helpers/media-gate.js", + "test/media-gate.test.js", + "refactor/baselines/audio-combinations-checkpoint.json", + "refactor/audio-validation.md" ], - "compatibleResolution": "先核实 seeked/canplay 和宿主 playing 的事件顺序;修复真实可播放后音频缺少恢复入口,保持旧核心支持。", - "closureCriteria": "保留原始失败,精确事件复现并有旧核心/新核心三引擎回归;不可仅重复到绿灯。" + "compatibleResolution": "保留真实 waiting 断言;使用独立原生对照和其他实际支持环境/输入继续验证,不将没有播放推进的诊断当成缓冲通过,也不凭此改变插件 API 或否定真实 Safari 支持。", + "closureCriteria": "受影响的缓冲/恢复得到真实媒体证据;与原生能力和测试夹具差异分开,发布环境的剩余范围经显式处理。" } ] } diff --git a/refactor/tasks.json b/refactor/tasks.json index a8f407b19..80dbea19e 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -1575,13 +1575,15 @@ "CORE-22", "CORE-24" ], - "status": "todo", + "status": "doing", "risk": "H", "deliverable": "主视频切源和缓冲恢复,多实例独立音频、旧核心", "acceptance": "最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成", "evidence": [ "changes/2026-09-12-PKG-AUDIO-05-combinations.md", - "baselines/audio-combinations-first.json" + "baselines/audio-combinations-first.json", + "baselines/audio-combinations-checkpoint.json", + "audio-validation.md" ] }, { diff --git a/test/audio-track.test.js b/test/audio-track.test.js index 52b6cb620..6fe745931 100644 --- a/test/audio-track.test.js +++ b/test/audio-track.test.js @@ -146,6 +146,44 @@ for (const { name, factory } of implementations) { const historical = implementations.find(item => item.name === 'published-main').factory for (const { name, factory: candidate } of implementations.filter(item => !item.name.startsWith('published'))) { + test(`${name}: native playback at zero resumes after seek without overriding proxy playing`, (t) => { + const { art } = audioHost(t) + Object.assign(art.video, { currentTime: 0, paused: false, ended: false, readyState: 4 }) + const { audio } = candidate({ url: 'audio.aac' })(art) + audio.calls.length = 0 + art.emit('video:seeking').emit('video:seeked') + assert.deepEqual(audio.calls, [['pause'], ['play']]) + art.video.playing = false + audio.calls.length = 0 + art.emit('video:seeked').emit('video:playing').emit('video:canplay') + assert.deepEqual(audio.calls, [], 'A proxy explicit false is authoritative') + art.video.playing = true + art.emit('video:seeked') + assert.deepEqual(audio.calls, [['play']]) + }) + + test(`${name}: canplay recovers a paused audio after seeked preceded host readiness`, (t) => { + const { art } = audioHost(t) + const { audio } = candidate({ url: 'audio.aac' })(art) + art.currentTime = 3 + art.emit('video:seeking').emit('video:seeked') + assert.equal(audio.currentTime, 3) + audio.calls.length = 0 + art.emit('video:canplay') + assert.deepEqual(audio.calls, [], 'A paused host must not resume audio') + art.playing = true + art.emit('video:canplay') + assert.deepEqual(audio.calls, [['play']]) + audio.paused = false + audio.calls.length = 0 + art.emit('video:canplay') + assert.deepEqual(audio.calls, [], 'Already playing audio needs no additional play request') + art.emit('destroy') + audio.calls.length = 0 + art.emit('video:canplay') + assert.deepEqual(audio.calls, []) + }) + test(`${name}: closed callbacks and retained update cannot revive resources`, (t) => { const { art, listeners } = audioHost(t) const plugin = candidate({ url: 'audio.aac' })(art) diff --git a/test/browser/README.md b/test/browser/README.md index 770224280..6aae34ac1 100644 --- a/test/browser/README.md +++ b/test/browser/README.md @@ -97,3 +97,25 @@ The docs `assets/sample/video.mp4` remains an existing sample with its original tracked by BASE-MEDIA-01. The new synthetic fixtures do not resolve rights for existing media. Browser binaries/codec support vary by OS; these projects do not replace Safari/iOS/Android device checks. See the [official browser guidance](https://playwright.dev/docs/browsers). + +## Withheld media diagnostics + +`test/helpers/media-gate.js` binds a temporary HTTP server to loopback and withholds +the tail of the pinned media until the test calls release(). Its default response +keeps the full Content-Length and streams the prefix; the diagnostic completeRanges +mode sends a bounded 206 response and holds the later range. Both preserve exact +bytes and a strong ETag. Partial range semantics follow +[RFC 9110 section 15.3.7](https://www.rfc-editor.org/rfc/rfc9110.html#name-partial-content). +`node --test test/media-gate.test.js` verifies actual HTTP bytes, headers and release. + +`audio-buffering.spec.js` requires trusted waiting after actual clock progression, +then release, resumed clocks and synchronization across old/new core/plugin pairs. +It currently has unresolved Windows WebKit failures; do not skip them or count +the native diagnostic below as equivalent acceptance. See refactor/audio-validation.md. + +`media-gate-native.spec.js` removes all ArtPlayer instances and uses a native element +with preload=auto. It records whether playback and starvation were observed for +both response modes. A passing diagnostic only proves observation plus successful +playback after release; inspect its progressed/waiting flags before claiming buffering. +These capability observation timeouts do not relax the integration assertions. +Archive the report and results (including traces) before starting another browser suite. diff --git a/test/browser/audio-buffering.spec.js b/test/browser/audio-buffering.spec.js new file mode 100644 index 000000000..d473f5886 --- /dev/null +++ b/test/browser/audio-buffering.spec.js @@ -0,0 +1,62 @@ +import fs from 'node:fs' +import { hash } from '../../refactor/scripts/releases.mjs' +import { createMediaGate } from '../helpers/media-gate.js' +import { useAudioFixture } from './audio-fixture.js' +import { expect, test } from './fixtures.js' + +const { openAudio } = useAudioFixture() + +for (const core of ['published', 'candidate']) { + for (const plugin of ['published', 'source']) { + for (const owner of ['video', 'audio']) { + test(`${core} core + ${plugin} audio: real ${owner} starvation resumes after network release`, async ({ page }, testInfo) => { + const file = owner === 'video' ? 'pattern.mp4' : 'audio-tone.m4a' + const bytes = fs.readFileSync(new URL(`./media/${file}`, import.meta.url)) + const limit = owner === 'video' ? 96 * 1024 : 32 * 1024 + const gate = await createMediaGate(bytes, owner === 'video' ? 'video/mp4' : 'audio/mp4', limit) + try { + await openAudio(page, core, plugin, testInfo, owner === 'audio' ? gate.url : '/test/audio-tone.m4a') + await page.evaluate((owner) => { + window.starvation = [] + const media = owner === 'video' ? window.art.video : window.audioPlugin.audio + media.addEventListener('waiting', (event) => { + window.starvation.push({ trusted: event.isTrusted, time: media.currentTime, readyState: media.readyState, audioPaused: window.audioPlugin.audio.paused, videoTime: window.art.currentTime }) + }) + }, owner) + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime > 0.3 && window.art.currentTime > 0.3)).toBe(true) + if (owner === 'video') + await page.evaluate(url => window.art.switchUrl(url), gate.url) + await expect.poll(() => page.evaluate(() => window.starvation.some(event => event.trusted && event.time > 0.3 && event.readyState < 3))).toBe(true) + expect(gate.blocked).toBeGreaterThan(0) + const stalled = await page.evaluate(() => ({ audio: window.audioPlugin.audio.currentTime, video: window.art.currentTime })) + if (owner === 'video') { + expect(await page.evaluate(() => window.audioPlugin.audio.paused)).toBe(true) + } + else { + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(stalled.video + 0.3) + expect(await page.evaluate(() => window.art.video.paused)).toBe(false) + } + gate.release() + await expect.poll(() => page.evaluate(() => !window.audioPlugin.audio.paused && !window.art.video.paused)).toBe(true) + await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(stalled.audio + 0.3) + await expect.poll(() => page.evaluate(() => window.art.currentTime)).toBeGreaterThan(stalled.video + 0.3) + await expect.poll(() => page.evaluate(() => Math.abs(window.audioPlugin.audio.currentTime - window.art.currentTime))).toBeLessThan(0.5) + expect(await page.evaluate(() => [window.art.video.error, window.audioPlugin.audio.error])).toEqual([null, null]) + } + finally { + try { + await testInfo.attach('media-gate-requests', { contentType: 'application/json', body: JSON.stringify({ file, sha256: hash(bytes), bytes: bytes.length, limit, requests: gate.requests }) }) + const events = page.isClosed() ? { closed: true } : await page.evaluate(() => window.starvation) + await testInfo.attach('media-gate', { contentType: 'application/json', body: JSON.stringify({ file, sha256: hash(bytes), bytes: bytes.length, limit, requests: gate.requests, events }) }) + if (!page.isClosed()) + await page.evaluate(() => window.art?.destroy()) + } + finally { + await gate.close() + } + } + }) + } + } +} diff --git a/test/browser/audio-combinations.spec.js b/test/browser/audio-combinations.spec.js index c1b04cd2c..ee6736e30 100644 --- a/test/browser/audio-combinations.spec.js +++ b/test/browser/audio-combinations.spec.js @@ -80,33 +80,64 @@ for (const core of ['published', 'candidate']) { test(`${core} core + ${plugin} audio: native offset bounds recover to an in-range seek`, async ({ page }, testInfo) => { await openAudio(page, core, plugin, testInfo) + await page.evaluate(() => { + window.boundaryAudio = new Audio('/test/audio-tone.m4a?boundary=native') + window.boundaryAudio.muted = true + document.querySelector('#play').onclick = () => Promise.all([window.art.play(), window.boundaryAudio.play()]) + }) + await expect.poll(() => page.evaluate(() => window.boundaryAudio.readyState)).toBeGreaterThanOrEqual(2) await page.locator('#play').click() await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(0.2) await page.evaluate(() => { window.art.pause() + window.boundaryAudio.pause() window.audioPlugin.update({ offset: -2 }) window.art.seek = 0.5 + window.boundaryAudio.currentTime = -1.5 }) - await expect.poll(() => page.evaluate(() => !window.art.video.seeking && !window.audioPlugin.audio.seeking)).toBe(true) - const negative = await page.evaluate(() => ({ time: window.audioPlugin.audio.currentTime, error: window.audioPlugin.audio.error?.code || null })) - expect(negative).toEqual({ time: 0, error: null }) + await expect.poll(() => page.evaluate(() => !window.art.video.seeking && !window.audioPlugin.audio.seeking && !window.boundaryAudio.seeking)).toBe(true) + const negative = await page.evaluate(() => { + const state = audio => ({ time: audio.currentTime, error: audio.error?.code || null }) + return { audio: state(window.audioPlugin.audio), native: state(window.boundaryAudio) } + }) + await testInfo.attach('negative-offset-native', { contentType: 'application/json', body: JSON.stringify(negative) }) + expect(negative.native.time).toBeGreaterThanOrEqual(0) + expect(negative.native.time).toBeCloseTo(0, 1) + expect(negative.audio.time).toBeGreaterThanOrEqual(0) + expect(negative.audio.time).toBeCloseTo(negative.native.time, 1) + expect([negative.audio.error, negative.native.error]).toEqual([null, null]) await page.evaluate(() => { window.audioPlugin.update({ offset: 20 }) window.art.seek = 1 + window.boundaryAudio.currentTime = 21 }) - await expect.poll(() => page.evaluate(() => !window.art.video.seeking && !window.audioPlugin.audio.seeking)).toBe(true) - await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBe(16) + await expect.poll(() => page.evaluate(() => !window.art.video.seeking && !window.audioPlugin.audio.seeking && !window.boundaryAudio.seeking)).toBe(true) + const overflow = await page.evaluate(() => { + const state = audio => ({ time: audio.currentTime, duration: audio.duration, error: audio.error?.code || null }) + return { audio: state(window.audioPlugin.audio), native: state(window.boundaryAudio) } + }) + await testInfo.attach('overflow-offset-native', { contentType: 'application/json', body: JSON.stringify(overflow) }) + expect(overflow.native.duration).toBe(16) + expect(overflow.native.time).toBeCloseTo(overflow.native.duration, 1) + expect(overflow.audio.time).toBeCloseTo(overflow.native.time, 1) + expect([overflow.audio.error, overflow.native.error]).toEqual([null, null]) expect(await page.evaluate(() => window.audioPlugin.audio.paused)).toBe(true) await page.evaluate(() => { window.audioPlugin.update({ offset: -0.5 }) window.art.seek = 3 + window.boundaryAudio.currentTime = 2.5 }) await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeCloseTo(2.5, 1) await page.locator('#play').click() await expect.poll(() => page.evaluate(() => window.audioPlugin.audio.currentTime)).toBeGreaterThan(2.8) await expect.poll(() => page.evaluate(() => Math.abs(window.audioPlugin.audio.currentTime - window.art.currentTime + 0.5))).toBeLessThan(0.5) - await testInfo.attach('offset-boundary', { contentType: 'application/json', body: JSON.stringify({ negative, overflow: 16, recovered: true }) }) - await page.evaluate(() => window.art.destroy()) + await testInfo.attach('offset-boundary', { contentType: 'application/json', body: JSON.stringify({ negative, overflow, recovered: true }) }) + await page.evaluate(() => { + window.art.destroy() + window.boundaryAudio.pause() + window.boundaryAudio.removeAttribute('src') + window.boundaryAudio.load() + }) }) } } diff --git a/test/browser/audio-fixture.js b/test/browser/audio-fixture.js index 197a4b20a..608e8c267 100644 --- a/test/browser/audio-fixture.js +++ b/test/browser/audio-fixture.js @@ -72,8 +72,8 @@ export function useAudioFixture() { plugins: [window.artplayerPluginAudioTrack({ url, sync: 0.1 })], }) window.audioPlugin = window.art.plugins.artplayerPluginAudioTrack - for (const event of ['play', 'pause', 'seek', 'video:waiting', 'video:playing', 'video:seeking', 'video:seeked', 'video:pause', 'video:ended']) - window.art.on(event, () => window.audioHostEvents.push({ event, videoTime: window.art.currentTime, audioTime: window.audioPlugin.audio.currentTime, audioPaused: window.audioPlugin.audio.paused })) + for (const event of ['play', 'pause', 'seek', 'video:waiting', 'video:playing', 'video:canplay', 'video:seeking', 'video:seeked', 'video:pause', 'video:ended']) + window.art.on(event, () => window.audioHostEvents.push({ event, videoTime: window.art.currentTime, videoPaused: window.art.video.paused, videoReadyState: window.art.video.readyState, playing: window.art.playing, audioTime: window.audioPlugin.audio.currentTime, audioPaused: window.audioPlugin.audio.paused })) 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() diff --git a/test/browser/media-gate-native.spec.js b/test/browser/media-gate-native.spec.js new file mode 100644 index 000000000..19581164e --- /dev/null +++ b/test/browser/media-gate-native.spec.js @@ -0,0 +1,63 @@ +import fs from 'node:fs' +import { hash } from '../../refactor/scripts/releases.mjs' +import { createMediaGate } from '../helpers/media-gate.js' +import { expect, test } from './fixtures.js' + +for (const owner of ['video', 'audio']) { + for (const completeRanges of [false, true]) { + test(`native ${owner} ${completeRanges ? 'complete ranges' : 'streamed response'} capability without ArtPlayer instances`, async ({ page }, testInfo) => { + const file = owner === 'video' ? 'pattern.mp4' : 'audio-tone.m4a' + const bytes = fs.readFileSync(new URL(`./media/${file}`, import.meta.url)) + const limit = owner === 'video' ? 96 * 1024 : 32 * 1024 + const gate = await createMediaGate(bytes, owner === 'video' ? 'video/mp4' : 'audio/mp4', limit, completeRanges) + try { + await page.goto('/test/player.html') + await page.evaluate(({ owner, url }) => { + window.nativeMedia = document.createElement(owner) + window.nativeMedia.preload = 'auto' + window.nativeMedia.muted = true + window.nativeEvents = [] + for (const event of ['loadedmetadata', 'loadeddata', 'canplay', 'playing', 'waiting', 'stalled', 'pause', 'error']) + window.nativeMedia.addEventListener(event, e => window.nativeEvents.push({ event, trusted: e.isTrusted, time: window.nativeMedia.currentTime, readyState: window.nativeMedia.readyState })) + window.nativeMedia.src = url + document.body.append(window.nativeMedia) + document.querySelector('#play').onclick = () => window.nativeMedia.play() + }, { owner, url: gate.url }) + await expect.poll(() => page.evaluate(() => window.nativeMedia.readyState >= 2 || Boolean(window.nativeMedia.error))).toBe(true) + await page.locator('#play').click() + let progressed = false + let waiting = false + try { + await page.waitForFunction(() => window.nativeMedia.currentTime > 0.3, null, { timeout: 3000 }) + progressed = true + await page.waitForFunction(() => window.nativeEvents.some(event => event.event === 'waiting' && event.trusted && event.time > 0.3 && event.readyState < 3), null, { timeout: 7000 }) + waiting = true + } + catch (error) { + if (error.name !== 'TimeoutError') + throw error + } + const before = await page.evaluate(() => ({ time: window.nativeMedia.currentTime, readyState: window.nativeMedia.readyState, paused: window.nativeMedia.paused, error: window.nativeMedia.error?.code || null, instances: window.Artplayer.instances.length, events: window.nativeEvents })) + expect(before.instances).toBe(0) + expect(gate.blocked).toBeGreaterThan(0) + gate.release() + await page.locator('#play').click() + await expect.poll(() => page.evaluate(() => window.nativeMedia.currentTime)).toBeGreaterThan(before.time + 0.3) + expect(await page.evaluate(() => window.nativeMedia.error)).toBeNull() + await testInfo.attach('native-gate-capability', { contentType: 'application/json', body: JSON.stringify({ file, sha256: hash(bytes), limit, completeRanges, progressed, waiting, before, requests: gate.requests, after: await page.evaluate(() => ({ time: window.nativeMedia.currentTime, readyState: window.nativeMedia.readyState, paused: window.nativeMedia.paused })) }) }) + } + finally { + try { + await page.evaluate(() => { + window.nativeMedia?.pause() + window.nativeMedia?.removeAttribute('src') + window.nativeMedia?.load() + }) + } + finally { + await gate.close() + } + } + }) + } +} diff --git a/test/helpers/media-gate.js b/test/helpers/media-gate.js new file mode 100644 index 000000000..172a23bb5 --- /dev/null +++ b/test/helpers/media-gate.js @@ -0,0 +1,90 @@ +import assert from 'node:assert/strict' +import { createHash } from 'node:crypto' +import http from 'node:http' + +// Serves real media bytes, withholding the tail until a test observes native starvation. +export async function createMediaGate(bytes, contentType, limit, completeRanges = false) { + assert(Number.isSafeInteger(limit) && limit > 0 && limit < bytes.length) + const requests = [] + const pending = new Map() + let released = false + const etag = `"${createHash('sha256').update(bytes).digest('hex')}"` + const server = http.createServer((req, res) => { + if (!['GET', 'HEAD'].includes(req.method) || !req.url.startsWith('/media.')) { + res.writeHead(404).end() + return + } + let start = 0 + let end = bytes.length - 1 + if (req.headers.range) { + const match = /^bytes=(\d*)-(\d*)$/.exec(req.headers.range) + start = match?.[1] ? Number(match[1]) : Math.max(0, bytes.length - Number(match?.[2])) + end = match?.[1] && match[2] ? Math.min(bytes.length - 1, Number(match[2])) : bytes.length - 1 + if (!match || (!match[1] && !match[2]) || !Number.isSafeInteger(start) || start > end || start >= bytes.length) { + res.writeHead(416, { 'Content-Range': `bytes */${bytes.length}` }).end() + return + } + res.statusCode = 206 + if (completeRanges && !released && start < limit) + end = Math.min(end, limit - 1) + res.setHeader('Content-Range', `bytes ${start}-${end}/${bytes.length}`) + } + res.setHeader('Content-Type', contentType) + res.setHeader('Content-Length', end - start + 1) + res.setHeader('Accept-Ranges', 'bytes') + res.setHeader('Cache-Control', 'no-store') + res.setHeader('ETag', etag) + res.setHeader('Access-Control-Allow-Origin', '*') + const record = { method: req.method, range: req.headers.range || null, start, end, sent: 0, wasHeld: false, closed: false } + requests.push(record) + res.on('close', () => { + record.closed = true + pending.delete(res) + }) + res.on('error', (error) => { + record.error = error.message + }) + if (req.method === 'HEAD') { + res.end() + return + } + const availableEnd = released ? end + 1 : Math.min(end + 1, limit) + const sentEnd = Math.max(start, availableEnd) + if (sentEnd > start) { + res.write(bytes.subarray(start, sentEnd)) + record.sent += sentEnd - start + } + if (sentEnd > end) { + res.end() + } + else { + record.wasHeld = true + pending.set(res, { offset: sentEnd, end, record }) + res.flushHeaders() + } + }) + await new Promise((resolve, reject) => { + server.once('error', reject) + server.listen(0, '127.0.0.1', resolve) + }) + const address = server.address() + return { + url: `http://127.0.0.1:${address.port}/media.${contentType === 'video/mp4' ? 'mp4' : 'm4a'}`, + requests, + get blocked() { return pending.size }, + release() { + released = true + for (const [res, { offset, end, record }] of pending) { + if (!res.destroyed) { + record.sent += end + 1 - offset + res.end(bytes.subarray(offset, end + 1)) + } + } + pending.clear() + }, + async close() { + server.closeAllConnections() + await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve())) + }, + } +} diff --git a/test/media-gate.test.js b/test/media-gate.test.js new file mode 100644 index 000000000..399072f8f --- /dev/null +++ b/test/media-gate.test.js @@ -0,0 +1,84 @@ +import assert from 'node:assert/strict' +import { Buffer } from 'node:buffer' +// eslint-disable-next-line test/no-import-node-test -- Test the real local HTTP fixture with Node's runner. +import test from 'node:test' +import { setImmediate } from 'node:timers/promises' +import { createMediaGate } from './helpers/media-gate.js' + +test('media gate completes a bounded range and withholds the rest without altering bytes', async () => { + const bytes = Buffer.from('0123456789abcdef') + const gate = await createMediaGate(bytes, 'audio/mp4', 5, true) + try { + const first = await fetch(gate.url, { headers: { Range: 'bytes=0-' }, signal: AbortSignal.timeout(2000) }) + assert.equal(first.status, 206) + assert.equal(first.headers.get('Content-Range'), 'bytes 0-4/16') + assert.equal(first.headers.get('Content-Length'), '5') + assert.deepEqual(Buffer.from(await first.arrayBuffer()), bytes.subarray(0, 5)) + const tail = await fetch(gate.url, { headers: { Range: 'bytes=5-' }, signal: AbortSignal.timeout(2000) }) + assert.equal(tail.status, 206) + assert.equal(tail.headers.get('ETag'), first.headers.get('ETag')) + assert.equal(gate.blocked, 1) + let finished = false + const remaining = tail.arrayBuffer().then((body) => { + finished = true + return Buffer.from(body) + }) + await setImmediate() + assert.equal(finished, false) + gate.release() + assert.deepEqual(await remaining, bytes.subarray(5)) + assert.equal(gate.blocked, 0) + assert(gate.requests.some(request => request.wasHeld)) + } + finally { + await gate.close() + } +}) + +test('media gate streams a prefix within a full declared response and releases the remaining bytes', async () => { + const bytes = Buffer.from('0123456789abcdef') + const gate = await createMediaGate(bytes, 'audio/mp4', 5) + try { + const response = await fetch(gate.url, { headers: { Range: 'bytes=0-' }, signal: AbortSignal.timeout(2000) }) + assert.equal(response.headers.get('Content-Range'), 'bytes 0-15/16') + assert.equal(response.headers.get('Content-Length'), '16') + const reader = response.body.getReader() + const first = await reader.read() + assert.deepEqual(Buffer.from(first.value), bytes.subarray(0, 5)) + let finished = false + const tail = reader.read().then((value) => { + finished = true + return value + }) + await setImmediate() + assert.equal(finished, false) + assert.equal(gate.blocked, 1) + gate.release() + assert.deepEqual(Buffer.from((await tail).value), bytes.subarray(5)) + assert.equal((await reader.read()).done, true) + } + finally { + await gate.close() + } +}) + +test('media gate preserves HEAD and rejects invalid ranges before serving the released suffix', async () => { + const gate = await createMediaGate(Buffer.from('0123456789'), 'video/mp4', 4) + try { + const head = await fetch(gate.url, { method: 'HEAD' }) + assert.equal(head.status, 200) + assert.equal(head.headers.get('Content-Length'), '10') + assert.equal(await head.text(), '') + assert.equal(gate.blocked, 0) + const invalid = await fetch(gate.url, { headers: { Range: 'bytes=20-' } }) + assert.equal(invalid.status, 416) + assert.equal(invalid.headers.get('Content-Range'), 'bytes */10') + gate.release() + const suffix = await fetch(gate.url, { headers: { Range: 'bytes=-3' } }) + assert.equal(suffix.headers.get('Content-Range'), 'bytes 7-9/10') + assert.equal(await suffix.text(), '789') + } + finally { + await gate.close() + } +})