diff --git a/package.json b/package.json index a104b118e..8eecf9a86 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:docs && yarn test:imports", "test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js", "typecheck": "node scripts/typecheck.mjs", - "test:unit": "node --test test/dpip.test.js test/dpip-lifecycle.test.js test/canvas.test.js test/canvas-lifecycle.test.js test/ambilight.test.js test/ambilight-lifecycle.test.js test/ambilight-proxy.test.js test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js", + "test:unit": "node --test test/mediabunny.test.js test/dpip.test.js test/dpip-lifecycle.test.js test/canvas.test.js test/canvas-lifecycle.test.js test/ambilight.test.js test/ambilight-lifecycle.test.js test/ambilight-proxy.test.js test/vast.test.js test/vast-lifecycle.test.js test/ads.test.js test/ads-lifecycle.test.js test/playback.test.js test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js test/hls-control.test.js test/audio-track.test.js test/public-behavior.test.js test/helpers.test.js test/chapter.test.js test/utils.test.js test/resource-scope.test.js test/instance-lifecycle.test.js test/options.test.js test/media-hosts.test.js test/plugins.test.js test/source.test.js test/playback-properties.test.js test/media-events.test.js test/template-resources.test.js test/core-vendor.test.js test/component-resources.test.js test/setting-model.test.js test/setting-layout.test.js test/setting-resources.test.js test/subtitle.test.js test/display-native.test.js test/display-video-fullscreen.test.js test/display-pip.test.js test/display-mini.test.js test/display-sizing.test.js test/display-orientation.test.js test/hotkey.test.js test/listener-registry.test.js test/global-events.test.js test/pointer-events.test.js test/gesture.test.js test/event-scheduling.test.js test/notice.test.js test/fast-forward.test.js test/auto-playback.test.js test/builtin-layers.test.js test/prompt-components.test.js test/screenshot.test.js test/thumbnails.test.js test/progress.test.js test/environment.test.js test/storage.test.js test/facade-properties.test.js test/dom-boundaries.test.js test/initialization.test.js test/entry.test.js test/accessibility-button.test.js test/accessibility-focus.test.js test/accessibility-slider.test.js", "test:coverage": "node --test test/coverage.test.js && node scripts/coverage.mjs", "test": "yarn test:node && yarn test:baseline", "test:browser": "playwright test", @@ -75,7 +75,8 @@ "test:canvas": "node --test test/canvas.test.js test/canvas-lifecycle.test.js", "test:canvas-types-package": "node refactor/scripts/canvas-package-types.mjs", "test:dpip": "node --test test/dpip.test.js test/dpip-lifecycle.test.js", - "test:dpip-types-package": "node refactor/scripts/dpip-package-types.mjs" + "test:dpip-types-package": "node refactor/scripts/dpip-package-types.mjs", + "test:mediabunny": "node --test test/mediabunny.test.js" }, "browserslist": "last 1 Chrome version", "devDependencies": { diff --git a/refactor/baselines/mb-behavior-validation.json b/refactor/baselines/mb-behavior-validation.json new file mode 100644 index 000000000..54e712dea --- /dev/null +++ b/refactor/baselines/mb-behavior-validation.json @@ -0,0 +1,7058 @@ +{ + "task": "PKG-MB-02", + "status": "done", + "parentCommit": "63c8938dd768539cba701a6ef171c17ddd877955", + "node": { + "tests": 24, + "reproducedHistoricalDefectCases": 18, + "normalAndVersionControls": 6 + }, + "browser": { + "report": "refactor/.cache/mb02-final-results/report.json", + "results": "refactor/.cache/mb02-final-results/results", + "total": 42, + "outcomes": { + "native-input-playback-and-seek": 16, + "historical-trackless-readiness-control": 4, + "historical-stream-lock-control": 3, + "historical-unsupported-hls-control": 3, + "unsupported-capability-control": 10, + "native-mp4-playback-observed": 4, + "verified-unsupported-capability-control": 2 + }, + "records": [ + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "webm", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.010666666666666668, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2586666666666667, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.38933333333333336, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.38933333333333336, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.38933333333333336, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5693333333333332, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.8200000000000001, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8999999999999999, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8999999999999999, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.583, + "audioClock": 0.5986666666666667, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666667, + "paused": false + }, + { + "frame": 0.667, + "audioClock": 0.6706666666666667, + "paused": false + }, + { + "frame": 0.708, + "audioClock": 0.7186666666666668, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666666, + "paused": false + }, + { + "frame": 0.792, + "audioClock": 0.7986666666666666, + "paused": false + }, + { + "frame": 0.833, + "audioClock": 0.8493333333333333, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8786666666666667, + "paused": false + } + ], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.01633333333333331, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "blob", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.008, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2586666666666667, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5693333333333334, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.8200000000000001, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.9, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.9, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.5986666666666667, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.628, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.668, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7186666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7693333333333333, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.7986666666666667, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8493333333333334, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8786666666666667, + "paused": false + } + ], + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.019333333333333313, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "stream", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.008, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2586666666666667, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5693333333333334, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.8200000000000001, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.9, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.9, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.5986666666666667, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.628, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.668, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7186666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7693333333333333, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.7986666666666667, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8493333333333334, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8786666666666667, + "paused": false + } + ], + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": true + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.019333333333333313, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "audio", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2613333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0.5, + "duration": 16, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "hls", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2613333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.4, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.4, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.4, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.548, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.7986666666666666, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:durationchange", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:durationchange", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.8786666666666667, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.8786666666666667, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0.8786666666666667, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.5986666666666667, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.628, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.668, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7186666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7693333333333333, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.7986666666666666, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8493333333333333, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8786666666666667, + "paused": false + } + ], + "tracks": { + "initial": 180, + "quality": 90, + "videoMode": "manual", + "language": "fr", + "audioMode": "manual", + "afterSourceSwitch": null + }, + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": { + "kind": "generated-hls-media", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "duration": 12, + "commands": [ + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=160x90:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "low-%02d.mpegts", + "low.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=320x180:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "high-%02d.mpegts", + "high.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=440:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "english-%02d.mpegts", + "english.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=880:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "french-%02d.mpegts", + "french.m3u8" + ] + ], + "files": { + "english-00.mpegts": { + "sha256": "cc599f7c270385e85c28f710a34c5bd90b09d4d27adb3b1e6af3de65584b8207", + "bytes": 13912 + }, + "english-01.mpegts": { + "sha256": "01b17c28defc8a8ebf4978c5236eb759d80521a1cb840898095c35dac420cec5", + "bytes": 14100 + }, + "english-02.mpegts": { + "sha256": "90751b8b5abedd6b2f2e4eb83ccd609098ec7f2901163aaebf977cb9a11c46eb", + "bytes": 14100 + }, + "english-03.mpegts": { + "sha256": "9b1d86b7b261df66dbdace4ef1e846796cd710ffb72b22fc69532c1fe7d1c55e", + "bytes": 13912 + }, + "english-04.mpegts": { + "sha256": "dbfddd4f997942dd0b912f4c8bdbc5c11ee2a3fc51ac67df48d3aed2756715b9", + "bytes": 14100 + }, + "english-05.mpegts": { + "sha256": "9b53790d4f50f172852b7d4ff51bdd4bedd39e4c7a1efbfe734edf7b9a68a533", + "bytes": 14100 + }, + "english-06.mpegts": { + "sha256": "50baaa5e9fe7ca49b22c4d0817c44103b3edc763aee7f1b17d22f796d4189d4a", + "bytes": 752 + }, + "english.m3u8": { + "sha256": "5aae9d117d458f65f7febae68555ea4e48b2055b4cfb123fb919e385a1edda21", + "bytes": 365 + }, + "french-00.mpegts": { + "sha256": "7278acd094bc7caeeeea424a2c11ac4285fc45a8becb6c8ec55068f295ae35cd", + "bytes": 13912 + }, + "french-01.mpegts": { + "sha256": "e9464d109e36a53d7f151442b544d47ce79324bbaa805e0a98f171621c9c7a13", + "bytes": 14100 + }, + "french-02.mpegts": { + "sha256": "3ac48cab6aac942950b59f79ac6bd950dcae425f14821b83b1b5bb72d6815eb0", + "bytes": 14100 + }, + "french-03.mpegts": { + "sha256": "906f2d8b1f29bb7d57240b145563bab975d8f7dfff78cebd1505b6d2a3feb43b", + "bytes": 13912 + }, + "french-04.mpegts": { + "sha256": "cbf82876118d41af254bdef51f6cd08d842e8c6edf53250667fad2b8088e3601", + "bytes": 14100 + }, + "french-05.mpegts": { + "sha256": "a91e564ec54d845837217c45b8e25b08fe208f2b5f97562f513baabd515427d9", + "bytes": 14100 + }, + "french-06.mpegts": { + "sha256": "2c8edc11b06bacf1e62c4db67594ce187aa93e0241012011ebcf587b64ccff46", + "bytes": 752 + }, + "french.m3u8": { + "sha256": "6f7fb3eacb944597fa3105cb6d708eac3a8dc413e1706a11b6fb0e631214634e", + "bytes": 358 + }, + "high-00.mpegts": { + "sha256": "c5a8faac85b0594818255117696dce43fda6b363df40e2f3ffc453bd236cc833", + "bytes": 45308 + }, + "high-01.mpegts": { + "sha256": "5714640c3f17d86c56036453dc17d45f871af63b461318c43527af3482f8661c", + "bytes": 52264 + }, + "high-02.mpegts": { + "sha256": "fea1cbfb199bc867a322c7a646d43594a1d0d1d23fa0bcb6e770f2669b489440", + "bytes": 48128 + }, + "high-03.mpegts": { + "sha256": "4a74a28e7ad6bc626358e32365a0b07df1da82c92753e28032983e22404958b5", + "bytes": 54144 + }, + "high-04.mpegts": { + "sha256": "d04889b3b996d3e79c12bc297f9577690d3ae4f4172cdc0484b584954dab789c", + "bytes": 47376 + }, + "high-05.mpegts": { + "sha256": "36ee0c64b8c3637d0e2282c611e9250650ac493440095fc2efbe9de1c54add15", + "bytes": 48128 + }, + "high.m3u8": { + "sha256": "672c0e8b99242be05b16fc747a00715b2c25579b1ecc1623c0579fa34f0cb11d", + "bytes": 311 + }, + "low-00.mpegts": { + "sha256": "cbd62f5f4641cbe188a15640139bea393b5927fce600ff7513ef9ade9b33fb62", + "bytes": 28952 + }, + "low-01.mpegts": { + "sha256": "f7821fba38c63f5d80daef21cdd3430880bdc9fd5f5adfa939ed6481106c2507", + "bytes": 32900 + }, + "low-02.mpegts": { + "sha256": "3dc93f9f0fd065678b01fc6c568c12350e9ab0b324d1e0fa0e9f77787da7e7d2", + "bytes": 30268 + }, + "low-03.mpegts": { + "sha256": "d94c8913f7fde98161550041287529b90a58d537d6083d4382540c5fce0b430b", + "bytes": 32336 + }, + "low-04.mpegts": { + "sha256": "11596c59b547c2ff23bbba1f70e15f061a3e87bbdc1f4f59daa9b5279a6003af", + "bytes": 29704 + }, + "low-05.mpegts": { + "sha256": "5c6ec25a69fdad73a23cfbc34f0f3c6d8abe44592650c92fa9110a38d6bd9e45", + "bytes": 29516 + }, + "low.m3u8": { + "sha256": "404a8d868ed2af3598269aee89caba0563c2805dac223fe4c00c9a9eda73554f", + "bytes": 305 + }, + "master.m3u8": { + "sha256": "f226bd38f3c76714ada2b5a6866ad1cb39b041023e4a18d971d175f26f917e38", + "bytes": 470 + }, + "video-only.m3u8": { + "sha256": "3d7bb9069f6218191dc65745389bf1ab0ba6d5ed66cbd14e2cf30211913da3fc", + "bytes": 108 + } + } + }, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.019333333333333313, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "trackless", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-trackless-readiness-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": null, + "error": null, + "readyState": 4, + "audioState": "running", + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": { + "parentSha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "sha256": "8b03d7a9ce2998e592c081bb83e88ed6c15c7a4c9add6a1cc0fda88d88f678c0" + }, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "webm", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2613333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.6013333333333334, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.852, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8706666666666667, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8706666666666667, + "duration": 7.999666666, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.583, + "audioClock": 0.6013333333333334, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666667, + "paused": false + }, + { + "frame": 0.667, + "audioClock": 0.6813333333333333, + "paused": false + }, + { + "frame": 0.708, + "audioClock": 0.7106666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666667, + "paused": false + }, + { + "frame": 0.792, + "audioClock": 0.8013333333333333, + "paused": false + }, + { + "frame": 0.833, + "audioClock": 0.852, + "paused": false + } + ], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 7, + "maxAbsoluteDeltaSeconds": 0.019000000000000017, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "blob", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2613333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5800000000000001, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.8306666666666667, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8813333333333333, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8813333333333333, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.6013333333333334, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666667, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.6813333333333333, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7106666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666667, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.8013333333333333, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.852, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8813333333333333, + "paused": false + } + ], + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.01866666666666661, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "stream", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-stream-lock-control", + "state": { + "events": [ + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 300, + 150, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "Failed to execute 'getReader' on 'ReadableStream': ReadableStreamDefaultReader constructor can only accept readable streams that are not yet locked to a reader" + }, + "readyState": 0, + "audioState": "running", + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "audio", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.25866666666666666, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.38666666666666666, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.38666666666666666, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.38666666666666666, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0.5, + "duration": 16, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "hls", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-unsupported-hls-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 300, + 150, + 0, + 0 + ], + "currentTime": 0, + "duration": null, + "error": { + "code": 4, + "message": "Input has an unsupported or unrecognizable format." + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": { + "kind": "generated-hls-media", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "duration": 12, + "commands": [ + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=160x90:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "low-%02d.mpegts", + "low.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=320x180:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "high-%02d.mpegts", + "high.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=440:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "english-%02d.mpegts", + "english.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=880:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "french-%02d.mpegts", + "french.m3u8" + ] + ], + "files": { + "english-00.mpegts": { + "sha256": "cc599f7c270385e85c28f710a34c5bd90b09d4d27adb3b1e6af3de65584b8207", + "bytes": 13912 + }, + "english-01.mpegts": { + "sha256": "01b17c28defc8a8ebf4978c5236eb759d80521a1cb840898095c35dac420cec5", + "bytes": 14100 + }, + "english-02.mpegts": { + "sha256": "90751b8b5abedd6b2f2e4eb83ccd609098ec7f2901163aaebf977cb9a11c46eb", + "bytes": 14100 + }, + "english-03.mpegts": { + "sha256": "9b1d86b7b261df66dbdace4ef1e846796cd710ffb72b22fc69532c1fe7d1c55e", + "bytes": 13912 + }, + "english-04.mpegts": { + "sha256": "dbfddd4f997942dd0b912f4c8bdbc5c11ee2a3fc51ac67df48d3aed2756715b9", + "bytes": 14100 + }, + "english-05.mpegts": { + "sha256": "9b53790d4f50f172852b7d4ff51bdd4bedd39e4c7a1efbfe734edf7b9a68a533", + "bytes": 14100 + }, + "english-06.mpegts": { + "sha256": "50baaa5e9fe7ca49b22c4d0817c44103b3edc763aee7f1b17d22f796d4189d4a", + "bytes": 752 + }, + "english.m3u8": { + "sha256": "5aae9d117d458f65f7febae68555ea4e48b2055b4cfb123fb919e385a1edda21", + "bytes": 365 + }, + "french-00.mpegts": { + "sha256": "7278acd094bc7caeeeea424a2c11ac4285fc45a8becb6c8ec55068f295ae35cd", + "bytes": 13912 + }, + "french-01.mpegts": { + "sha256": "e9464d109e36a53d7f151442b544d47ce79324bbaa805e0a98f171621c9c7a13", + "bytes": 14100 + }, + "french-02.mpegts": { + "sha256": "3ac48cab6aac942950b59f79ac6bd950dcae425f14821b83b1b5bb72d6815eb0", + "bytes": 14100 + }, + "french-03.mpegts": { + "sha256": "906f2d8b1f29bb7d57240b145563bab975d8f7dfff78cebd1505b6d2a3feb43b", + "bytes": 13912 + }, + "french-04.mpegts": { + "sha256": "cbf82876118d41af254bdef51f6cd08d842e8c6edf53250667fad2b8088e3601", + "bytes": 14100 + }, + "french-05.mpegts": { + "sha256": "a91e564ec54d845837217c45b8e25b08fe208f2b5f97562f513baabd515427d9", + "bytes": 14100 + }, + "french-06.mpegts": { + "sha256": "2c8edc11b06bacf1e62c4db67594ce187aa93e0241012011ebcf587b64ccff46", + "bytes": 752 + }, + "french.m3u8": { + "sha256": "6f7fb3eacb944597fa3105cb6d708eac3a8dc413e1706a11b6fb0e631214634e", + "bytes": 358 + }, + "high-00.mpegts": { + "sha256": "c5a8faac85b0594818255117696dce43fda6b363df40e2f3ffc453bd236cc833", + "bytes": 45308 + }, + "high-01.mpegts": { + "sha256": "5714640c3f17d86c56036453dc17d45f871af63b461318c43527af3482f8661c", + "bytes": 52264 + }, + "high-02.mpegts": { + "sha256": "fea1cbfb199bc867a322c7a646d43594a1d0d1d23fa0bcb6e770f2669b489440", + "bytes": 48128 + }, + "high-03.mpegts": { + "sha256": "4a74a28e7ad6bc626358e32365a0b07df1da82c92753e28032983e22404958b5", + "bytes": 54144 + }, + "high-04.mpegts": { + "sha256": "d04889b3b996d3e79c12bc297f9577690d3ae4f4172cdc0484b584954dab789c", + "bytes": 47376 + }, + "high-05.mpegts": { + "sha256": "36ee0c64b8c3637d0e2282c611e9250650ac493440095fc2efbe9de1c54add15", + "bytes": 48128 + }, + "high.m3u8": { + "sha256": "672c0e8b99242be05b16fc747a00715b2c25579b1ecc1623c0579fa34f0cb11d", + "bytes": 311 + }, + "low-00.mpegts": { + "sha256": "cbd62f5f4641cbe188a15640139bea393b5927fce600ff7513ef9ade9b33fb62", + "bytes": 28952 + }, + "low-01.mpegts": { + "sha256": "f7821fba38c63f5d80daef21cdd3430880bdc9fd5f5adfa939ed6481106c2507", + "bytes": 32900 + }, + "low-02.mpegts": { + "sha256": "3dc93f9f0fd065678b01fc6c568c12350e9ab0b324d1e0fa0e9f77787da7e7d2", + "bytes": 30268 + }, + "low-03.mpegts": { + "sha256": "d94c8913f7fde98161550041287529b90a58d537d6083d4382540c5fce0b430b", + "bytes": 32336 + }, + "low-04.mpegts": { + "sha256": "11596c59b547c2ff23bbba1f70e15f061a3e87bbdc1f4f59daa9b5279a6003af", + "bytes": 29704 + }, + "low-05.mpegts": { + "sha256": "5c6ec25a69fdad73a23cfbc34f0f3c6d8abe44592650c92fa9110a38d6bd9e45", + "bytes": 29516 + }, + "low.m3u8": { + "sha256": "404a8d868ed2af3598269aee89caba0563c2805dac223fe4c00c9a9eda73554f", + "bytes": 305 + }, + "master.m3u8": { + "sha256": "f226bd38f3c76714ada2b5a6866ad1cb39b041023e4a18d971d175f26f917e38", + "bytes": 470 + }, + "video-only.m3u8": { + "sha256": "3d7bb9069f6218191dc65745389bf1ab0ba6d5ed66cbd14e2cf30211913da3fc", + "bytes": 108 + } + } + }, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "trackless", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-trackless-readiness-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 0, + "error": null, + "readyState": 4, + "audioState": "running", + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": { + "parentSha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "sha256": "8b03d7a9ce2998e592c081bb83e88ed6c15c7a4c9add6a1cc0fda88d88f678c0" + }, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "webm", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2506666666666667, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.38933333333333336, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.38933333333333336, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.38933333333333336, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.532, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.78, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.9, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.9, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.583, + "audioClock": 0.6013333333333334, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666667, + "paused": false + }, + { + "frame": 0.667, + "audioClock": 0.6706666666666667, + "paused": false + }, + { + "frame": 0.708, + "audioClock": 0.7213333333333334, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666667, + "paused": false + }, + { + "frame": 0.792, + "audioClock": 0.8013333333333333, + "paused": false + }, + { + "frame": 0.833, + "audioClock": 0.852, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8813333333333333, + "paused": false + } + ], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.019000000000000017, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "blob", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2693333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.4, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.4, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.4, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5213333333333334, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.7693333333333334, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8893333333333334, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8893333333333334, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.5906666666666667, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6413333333333334, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.6706666666666667, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7213333333333334, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666667, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.8013333333333333, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8493333333333334, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8893333333333334, + "paused": false + } + ], + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.016333333333333422, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "stream", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.272, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3813333333333333, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5293333333333333, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.78, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8706666666666666, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8706666666666666, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.5906666666666667, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666666, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.6813333333333333, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7106666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7613333333333333, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.8093333333333333, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8413333333333333, + "paused": false + } + ], + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": true + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 7, + "maxAbsoluteDeltaSeconds": 0.01766666666666672, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "audio", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.28, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.42133333333333334, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.42133333333333334, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.42133333333333334, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0.5, + "duration": 16, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "hls", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.2693333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.42133333333333334, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.42133333333333334, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.42133333333333334, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5213333333333333, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.7693333333333333, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:durationchange", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:durationchange", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.8999999999999999, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.8999999999999999, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0.8999999999999999, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.6013333333333333, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666666, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.6706666666666666, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7213333333333333, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666666, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.8013333333333333, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8493333333333333, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8813333333333333, + "paused": false + } + ], + "tracks": { + "initial": 180, + "quality": 90, + "videoMode": "manual", + "language": "fr", + "audioMode": "manual", + "afterSourceSwitch": null + }, + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": { + "kind": "generated-hls-media", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "duration": 12, + "commands": [ + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=160x90:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "low-%02d.mpegts", + "low.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=320x180:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "high-%02d.mpegts", + "high.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=440:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "english-%02d.mpegts", + "english.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=880:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "french-%02d.mpegts", + "french.m3u8" + ] + ], + "files": { + "english-00.mpegts": { + "sha256": "cc599f7c270385e85c28f710a34c5bd90b09d4d27adb3b1e6af3de65584b8207", + "bytes": 13912 + }, + "english-01.mpegts": { + "sha256": "01b17c28defc8a8ebf4978c5236eb759d80521a1cb840898095c35dac420cec5", + "bytes": 14100 + }, + "english-02.mpegts": { + "sha256": "90751b8b5abedd6b2f2e4eb83ccd609098ec7f2901163aaebf977cb9a11c46eb", + "bytes": 14100 + }, + "english-03.mpegts": { + "sha256": "9b1d86b7b261df66dbdace4ef1e846796cd710ffb72b22fc69532c1fe7d1c55e", + "bytes": 13912 + }, + "english-04.mpegts": { + "sha256": "dbfddd4f997942dd0b912f4c8bdbc5c11ee2a3fc51ac67df48d3aed2756715b9", + "bytes": 14100 + }, + "english-05.mpegts": { + "sha256": "9b53790d4f50f172852b7d4ff51bdd4bedd39e4c7a1efbfe734edf7b9a68a533", + "bytes": 14100 + }, + "english-06.mpegts": { + "sha256": "50baaa5e9fe7ca49b22c4d0817c44103b3edc763aee7f1b17d22f796d4189d4a", + "bytes": 752 + }, + "english.m3u8": { + "sha256": "5aae9d117d458f65f7febae68555ea4e48b2055b4cfb123fb919e385a1edda21", + "bytes": 365 + }, + "french-00.mpegts": { + "sha256": "7278acd094bc7caeeeea424a2c11ac4285fc45a8becb6c8ec55068f295ae35cd", + "bytes": 13912 + }, + "french-01.mpegts": { + "sha256": "e9464d109e36a53d7f151442b544d47ce79324bbaa805e0a98f171621c9c7a13", + "bytes": 14100 + }, + "french-02.mpegts": { + "sha256": "3ac48cab6aac942950b59f79ac6bd950dcae425f14821b83b1b5bb72d6815eb0", + "bytes": 14100 + }, + "french-03.mpegts": { + "sha256": "906f2d8b1f29bb7d57240b145563bab975d8f7dfff78cebd1505b6d2a3feb43b", + "bytes": 13912 + }, + "french-04.mpegts": { + "sha256": "cbf82876118d41af254bdef51f6cd08d842e8c6edf53250667fad2b8088e3601", + "bytes": 14100 + }, + "french-05.mpegts": { + "sha256": "a91e564ec54d845837217c45b8e25b08fe208f2b5f97562f513baabd515427d9", + "bytes": 14100 + }, + "french-06.mpegts": { + "sha256": "2c8edc11b06bacf1e62c4db67594ce187aa93e0241012011ebcf587b64ccff46", + "bytes": 752 + }, + "french.m3u8": { + "sha256": "6f7fb3eacb944597fa3105cb6d708eac3a8dc413e1706a11b6fb0e631214634e", + "bytes": 358 + }, + "high-00.mpegts": { + "sha256": "c5a8faac85b0594818255117696dce43fda6b363df40e2f3ffc453bd236cc833", + "bytes": 45308 + }, + "high-01.mpegts": { + "sha256": "5714640c3f17d86c56036453dc17d45f871af63b461318c43527af3482f8661c", + "bytes": 52264 + }, + "high-02.mpegts": { + "sha256": "fea1cbfb199bc867a322c7a646d43594a1d0d1d23fa0bcb6e770f2669b489440", + "bytes": 48128 + }, + "high-03.mpegts": { + "sha256": "4a74a28e7ad6bc626358e32365a0b07df1da82c92753e28032983e22404958b5", + "bytes": 54144 + }, + "high-04.mpegts": { + "sha256": "d04889b3b996d3e79c12bc297f9577690d3ae4f4172cdc0484b584954dab789c", + "bytes": 47376 + }, + "high-05.mpegts": { + "sha256": "36ee0c64b8c3637d0e2282c611e9250650ac493440095fc2efbe9de1c54add15", + "bytes": 48128 + }, + "high.m3u8": { + "sha256": "672c0e8b99242be05b16fc747a00715b2c25579b1ecc1623c0579fa34f0cb11d", + "bytes": 311 + }, + "low-00.mpegts": { + "sha256": "cbd62f5f4641cbe188a15640139bea393b5927fce600ff7513ef9ade9b33fb62", + "bytes": 28952 + }, + "low-01.mpegts": { + "sha256": "f7821fba38c63f5d80daef21cdd3430880bdc9fd5f5adfa939ed6481106c2507", + "bytes": 32900 + }, + "low-02.mpegts": { + "sha256": "3dc93f9f0fd065678b01fc6c568c12350e9ab0b324d1e0fa0e9f77787da7e7d2", + "bytes": 30268 + }, + "low-03.mpegts": { + "sha256": "d94c8913f7fde98161550041287529b90a58d537d6083d4382540c5fce0b430b", + "bytes": 32336 + }, + "low-04.mpegts": { + "sha256": "11596c59b547c2ff23bbba1f70e15f061a3e87bbdc1f4f59daa9b5279a6003af", + "bytes": 29704 + }, + "low-05.mpegts": { + "sha256": "5c6ec25a69fdad73a23cfbc34f0f3c6d8abe44592650c92fa9110a38d6bd9e45", + "bytes": 29516 + }, + "low.m3u8": { + "sha256": "404a8d868ed2af3598269aee89caba0563c2805dac223fe4c00c9a9eda73554f", + "bytes": 305 + }, + "master.m3u8": { + "sha256": "f226bd38f3c76714ada2b5a6866ad1cb39b041023e4a18d971d175f26f917e38", + "bytes": 470 + }, + "video-only.m3u8": { + "sha256": "3d7bb9069f6218191dc65745389bf1ab0ba6d5ed66cbd14e2cf30211913da3fc", + "bytes": 108 + } + } + }, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.017999999999999905, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "trackless", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-trackless-readiness-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": null, + "error": null, + "readyState": 4, + "audioState": "suspended", + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": { + "parentSha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "sha256": "8b03d7a9ce2998e592c081bb83e88ed6c15c7a4c9add6a1cc0fda88d88f678c0" + }, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "webm", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.008000000000000007, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.25866666666666666, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.39999999999999997, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.39999999999999997, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.39999999999999997, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5479999999999999, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.8093333333333332, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8893333333333333, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8893333333333333, + "duration": 7.999666666, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.583, + "audioClock": 0.5986666666666666, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.628, + "paused": false + }, + { + "frame": 0.667, + "audioClock": 0.6786666666666666, + "paused": false + }, + { + "frame": 0.708, + "audioClock": 0.708, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7586666666666666, + "paused": false + }, + { + "frame": 0.792, + "audioClock": 0.7986666666666666, + "paused": false + }, + { + "frame": 0.833, + "audioClock": 0.8493333333333333, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8786666666666666, + "paused": false + } + ], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.01633333333333331, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "blob", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.26133333333333336, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.38133333333333336, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.38133333333333336, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.38133333333333336, + "readyState": 4 + }, + { + "name": "video:loadeddata", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0.5, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.5293333333333333, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.78, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.8893333333333334, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "currentTime": 0.8893333333333334, + "duration": 8, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [ + { + "frame": 0.5, + "audioClock": 0.5, + "paused": true + }, + { + "frame": 0.5833333333333334, + "audioClock": 0.6013333333333334, + "paused": false + }, + { + "frame": 0.625, + "audioClock": 0.6306666666666667, + "paused": false + }, + { + "frame": 0.6666666666666666, + "audioClock": 0.6813333333333333, + "paused": false + }, + { + "frame": 0.7083333333333334, + "audioClock": 0.7106666666666667, + "paused": false + }, + { + "frame": 0.75, + "audioClock": 0.7506666666666667, + "paused": false + }, + { + "frame": 0.7916666666666666, + "audioClock": 0.8013333333333333, + "paused": false + }, + { + "frame": 0.8333333333333334, + "audioClock": 0.8493333333333334, + "paused": false + }, + { + "frame": 0.875, + "audioClock": 0.8813333333333334, + "paused": false + } + ], + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": { + "samples": 8, + "maxAbsoluteDeltaSeconds": 0.018000000000000016, + "scope": "Short SDK audio-clock comparison at observed native draws, not acoustic or long-run AV sync" + } + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "stream", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-stream-lock-control", + "state": { + "events": [ + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 300, + 150, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "ReadableStream.getReader: Cannot get a new reader for a readable stream already locked by another reader." + }, + "readyState": 0, + "audioState": "suspended", + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "audio", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "native-input-playback-and-seek", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:play", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:playing", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:timeupdate", + "currentTime": 0.25866666666666666, + "readyState": 4 + }, + { + "name": "video:pause", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeking", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:waiting", + "currentTime": 0.3893333333333333, + "readyState": 4 + }, + { + "name": "video:seeked", + "currentTime": 0.5, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0.5, + "duration": 16, + "error": null, + "readyState": 4, + "audioState": "running", + "frameClockSamples": [], + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "hls", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-unsupported-hls-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 300, + 150, + 0, + 0 + ], + "currentTime": 0, + "duration": null, + "error": { + "code": 4, + "message": "Input has an unsupported or unrecognizable format." + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": { + "kind": "generated-hls-media", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "duration": 12, + "commands": [ + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=160x90:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "low-%02d.mpegts", + "low.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=320x180:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "high-%02d.mpegts", + "high.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=440:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "english-%02d.mpegts", + "english.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=880:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "french-%02d.mpegts", + "french.m3u8" + ] + ], + "files": { + "english-00.mpegts": { + "sha256": "cc599f7c270385e85c28f710a34c5bd90b09d4d27adb3b1e6af3de65584b8207", + "bytes": 13912 + }, + "english-01.mpegts": { + "sha256": "01b17c28defc8a8ebf4978c5236eb759d80521a1cb840898095c35dac420cec5", + "bytes": 14100 + }, + "english-02.mpegts": { + "sha256": "90751b8b5abedd6b2f2e4eb83ccd609098ec7f2901163aaebf977cb9a11c46eb", + "bytes": 14100 + }, + "english-03.mpegts": { + "sha256": "9b1d86b7b261df66dbdace4ef1e846796cd710ffb72b22fc69532c1fe7d1c55e", + "bytes": 13912 + }, + "english-04.mpegts": { + "sha256": "dbfddd4f997942dd0b912f4c8bdbc5c11ee2a3fc51ac67df48d3aed2756715b9", + "bytes": 14100 + }, + "english-05.mpegts": { + "sha256": "9b53790d4f50f172852b7d4ff51bdd4bedd39e4c7a1efbfe734edf7b9a68a533", + "bytes": 14100 + }, + "english-06.mpegts": { + "sha256": "50baaa5e9fe7ca49b22c4d0817c44103b3edc763aee7f1b17d22f796d4189d4a", + "bytes": 752 + }, + "english.m3u8": { + "sha256": "5aae9d117d458f65f7febae68555ea4e48b2055b4cfb123fb919e385a1edda21", + "bytes": 365 + }, + "french-00.mpegts": { + "sha256": "7278acd094bc7caeeeea424a2c11ac4285fc45a8becb6c8ec55068f295ae35cd", + "bytes": 13912 + }, + "french-01.mpegts": { + "sha256": "e9464d109e36a53d7f151442b544d47ce79324bbaa805e0a98f171621c9c7a13", + "bytes": 14100 + }, + "french-02.mpegts": { + "sha256": "3ac48cab6aac942950b59f79ac6bd950dcae425f14821b83b1b5bb72d6815eb0", + "bytes": 14100 + }, + "french-03.mpegts": { + "sha256": "906f2d8b1f29bb7d57240b145563bab975d8f7dfff78cebd1505b6d2a3feb43b", + "bytes": 13912 + }, + "french-04.mpegts": { + "sha256": "cbf82876118d41af254bdef51f6cd08d842e8c6edf53250667fad2b8088e3601", + "bytes": 14100 + }, + "french-05.mpegts": { + "sha256": "a91e564ec54d845837217c45b8e25b08fe208f2b5f97562f513baabd515427d9", + "bytes": 14100 + }, + "french-06.mpegts": { + "sha256": "2c8edc11b06bacf1e62c4db67594ce187aa93e0241012011ebcf587b64ccff46", + "bytes": 752 + }, + "french.m3u8": { + "sha256": "6f7fb3eacb944597fa3105cb6d708eac3a8dc413e1706a11b6fb0e631214634e", + "bytes": 358 + }, + "high-00.mpegts": { + "sha256": "c5a8faac85b0594818255117696dce43fda6b363df40e2f3ffc453bd236cc833", + "bytes": 45308 + }, + "high-01.mpegts": { + "sha256": "5714640c3f17d86c56036453dc17d45f871af63b461318c43527af3482f8661c", + "bytes": 52264 + }, + "high-02.mpegts": { + "sha256": "fea1cbfb199bc867a322c7a646d43594a1d0d1d23fa0bcb6e770f2669b489440", + "bytes": 48128 + }, + "high-03.mpegts": { + "sha256": "4a74a28e7ad6bc626358e32365a0b07df1da82c92753e28032983e22404958b5", + "bytes": 54144 + }, + "high-04.mpegts": { + "sha256": "d04889b3b996d3e79c12bc297f9577690d3ae4f4172cdc0484b584954dab789c", + "bytes": 47376 + }, + "high-05.mpegts": { + "sha256": "36ee0c64b8c3637d0e2282c611e9250650ac493440095fc2efbe9de1c54add15", + "bytes": 48128 + }, + "high.m3u8": { + "sha256": "672c0e8b99242be05b16fc747a00715b2c25579b1ecc1623c0579fa34f0cb11d", + "bytes": 311 + }, + "low-00.mpegts": { + "sha256": "cbd62f5f4641cbe188a15640139bea393b5927fce600ff7513ef9ade9b33fb62", + "bytes": 28952 + }, + "low-01.mpegts": { + "sha256": "f7821fba38c63f5d80daef21cdd3430880bdc9fd5f5adfa939ed6481106c2507", + "bytes": 32900 + }, + "low-02.mpegts": { + "sha256": "3dc93f9f0fd065678b01fc6c568c12350e9ab0b324d1e0fa0e9f77787da7e7d2", + "bytes": 30268 + }, + "low-03.mpegts": { + "sha256": "d94c8913f7fde98161550041287529b90a58d537d6083d4382540c5fce0b430b", + "bytes": 32336 + }, + "low-04.mpegts": { + "sha256": "11596c59b547c2ff23bbba1f70e15f061a3e87bbdc1f4f59daa9b5279a6003af", + "bytes": 29704 + }, + "low-05.mpegts": { + "sha256": "5c6ec25a69fdad73a23cfbc34f0f3c6d8abe44592650c92fa9110a38d6bd9e45", + "bytes": 29516 + }, + "low.m3u8": { + "sha256": "404a8d868ed2af3598269aee89caba0563c2805dac223fe4c00c9a9eda73554f", + "bytes": 305 + }, + "master.m3u8": { + "sha256": "f226bd38f3c76714ada2b5a6866ad1cb39b041023e4a18d971d175f26f917e38", + "bytes": 470 + }, + "video-only.m3u8": { + "sha256": "3d7bb9069f6218191dc65745389bf1ab0ba6d5ed66cbd14e2cf30211913da3fc", + "bytes": 108 + } + } + }, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "trackless", + "capabilities": { + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-trackless-readiness-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadeddata", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplay", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:canplaythrough", + "currentTime": 0, + "readyState": 4 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 4 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 0, + "error": null, + "readyState": 4, + "audioState": "suspended", + "hls": null + }, + "cleanup": { + "audioContext": "closed", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": { + "parentSha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "sha256": "8b03d7a9ce2998e592c081bb83e88ed6c15c7a4c9add6a1cc0fda88d88f678c0" + }, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "webm", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 1, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "blob", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 1 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 1, + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "stream", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 1 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 1, + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": true + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "audio", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 16, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "hls", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 12.031998, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0, + "hls": { + "levels": [ + { + "id": 1, + "height": 90 + }, + { + "id": 4, + "height": 180 + } + ], + "audios": [ + { + "id": 2, + "lang": "en" + }, + { + "id": 3, + "lang": "fr" + } + ] + } + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": { + "kind": "generated-hls-media", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "duration": 12, + "commands": [ + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=160x90:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "low-%02d.mpegts", + "low.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=320x180:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "high-%02d.mpegts", + "high.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=440:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "english-%02d.mpegts", + "english.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=880:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "french-%02d.mpegts", + "french.m3u8" + ] + ], + "files": { + "english-00.mpegts": { + "sha256": "cc599f7c270385e85c28f710a34c5bd90b09d4d27adb3b1e6af3de65584b8207", + "bytes": 13912 + }, + "english-01.mpegts": { + "sha256": "01b17c28defc8a8ebf4978c5236eb759d80521a1cb840898095c35dac420cec5", + "bytes": 14100 + }, + "english-02.mpegts": { + "sha256": "90751b8b5abedd6b2f2e4eb83ccd609098ec7f2901163aaebf977cb9a11c46eb", + "bytes": 14100 + }, + "english-03.mpegts": { + "sha256": "9b1d86b7b261df66dbdace4ef1e846796cd710ffb72b22fc69532c1fe7d1c55e", + "bytes": 13912 + }, + "english-04.mpegts": { + "sha256": "dbfddd4f997942dd0b912f4c8bdbc5c11ee2a3fc51ac67df48d3aed2756715b9", + "bytes": 14100 + }, + "english-05.mpegts": { + "sha256": "9b53790d4f50f172852b7d4ff51bdd4bedd39e4c7a1efbfe734edf7b9a68a533", + "bytes": 14100 + }, + "english-06.mpegts": { + "sha256": "50baaa5e9fe7ca49b22c4d0817c44103b3edc763aee7f1b17d22f796d4189d4a", + "bytes": 752 + }, + "english.m3u8": { + "sha256": "5aae9d117d458f65f7febae68555ea4e48b2055b4cfb123fb919e385a1edda21", + "bytes": 365 + }, + "french-00.mpegts": { + "sha256": "7278acd094bc7caeeeea424a2c11ac4285fc45a8becb6c8ec55068f295ae35cd", + "bytes": 13912 + }, + "french-01.mpegts": { + "sha256": "e9464d109e36a53d7f151442b544d47ce79324bbaa805e0a98f171621c9c7a13", + "bytes": 14100 + }, + "french-02.mpegts": { + "sha256": "3ac48cab6aac942950b59f79ac6bd950dcae425f14821b83b1b5bb72d6815eb0", + "bytes": 14100 + }, + "french-03.mpegts": { + "sha256": "906f2d8b1f29bb7d57240b145563bab975d8f7dfff78cebd1505b6d2a3feb43b", + "bytes": 13912 + }, + "french-04.mpegts": { + "sha256": "cbf82876118d41af254bdef51f6cd08d842e8c6edf53250667fad2b8088e3601", + "bytes": 14100 + }, + "french-05.mpegts": { + "sha256": "a91e564ec54d845837217c45b8e25b08fe208f2b5f97562f513baabd515427d9", + "bytes": 14100 + }, + "french-06.mpegts": { + "sha256": "2c8edc11b06bacf1e62c4db67594ce187aa93e0241012011ebcf587b64ccff46", + "bytes": 752 + }, + "french.m3u8": { + "sha256": "6f7fb3eacb944597fa3105cb6d708eac3a8dc413e1706a11b6fb0e631214634e", + "bytes": 358 + }, + "high-00.mpegts": { + "sha256": "c5a8faac85b0594818255117696dce43fda6b363df40e2f3ffc453bd236cc833", + "bytes": 45308 + }, + "high-01.mpegts": { + "sha256": "5714640c3f17d86c56036453dc17d45f871af63b461318c43527af3482f8661c", + "bytes": 52264 + }, + "high-02.mpegts": { + "sha256": "fea1cbfb199bc867a322c7a646d43594a1d0d1d23fa0bcb6e770f2669b489440", + "bytes": 48128 + }, + "high-03.mpegts": { + "sha256": "4a74a28e7ad6bc626358e32365a0b07df1da82c92753e28032983e22404958b5", + "bytes": 54144 + }, + "high-04.mpegts": { + "sha256": "d04889b3b996d3e79c12bc297f9577690d3ae4f4172cdc0484b584954dab789c", + "bytes": 47376 + }, + "high-05.mpegts": { + "sha256": "36ee0c64b8c3637d0e2282c611e9250650ac493440095fc2efbe9de1c54add15", + "bytes": 48128 + }, + "high.m3u8": { + "sha256": "672c0e8b99242be05b16fc747a00715b2c25579b1ecc1623c0579fa34f0cb11d", + "bytes": 311 + }, + "low-00.mpegts": { + "sha256": "cbd62f5f4641cbe188a15640139bea393b5927fce600ff7513ef9ade9b33fb62", + "bytes": 28952 + }, + "low-01.mpegts": { + "sha256": "f7821fba38c63f5d80daef21cdd3430880bdc9fd5f5adfa939ed6481106c2507", + "bytes": 32900 + }, + "low-02.mpegts": { + "sha256": "3dc93f9f0fd065678b01fc6c568c12350e9ab0b324d1e0fa0e9f77787da7e7d2", + "bytes": 30268 + }, + "low-03.mpegts": { + "sha256": "d94c8913f7fde98161550041287529b90a58d537d6083d4382540c5fce0b430b", + "bytes": 32336 + }, + "low-04.mpegts": { + "sha256": "11596c59b547c2ff23bbba1f70e15f061a3e87bbdc1f4f59daa9b5279a6003af", + "bytes": 29704 + }, + "low-05.mpegts": { + "sha256": "5c6ec25a69fdad73a23cfbc34f0f3c6d8abe44592650c92fa9110a38d6bd9e45", + "bytes": 29516 + }, + "low.m3u8": { + "sha256": "404a8d868ed2af3598269aee89caba0563c2805dac223fe4c00c9a9eda73554f", + "bytes": 305 + }, + "master.m3u8": { + "sha256": "f226bd38f3c76714ada2b5a6866ad1cb39b041023e4a18d971d175f26f917e38", + "bytes": 470 + }, + "video-only.m3u8": { + "sha256": "3d7bb9069f6218191dc65745389bf1ab0ba6d5ed66cbd14e2cf30211913da3fc", + "bytes": 108 + } + } + }, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "input": "trackless", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadedmetadata", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:durationchange", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:progress", + "currentTime": 0, + "readyState": 1 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 1 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": null, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 1, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": { + "parentSha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "sha256": "8b03d7a9ce2998e592c081bb83e88ed6c15c7a4c9add6a1cc0fda88d88f678c0" + }, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "webm", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 7.999666666, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "blob", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0, + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "stream", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-stream-lock-control", + "state": { + "events": [ + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 300, + 150, + 0, + 0 + ], + "currentTime": 0, + "duration": 8, + "error": { + "code": 4, + "message": "ReadableStream is locked" + }, + "readyState": 0, + "hls": null, + "inputBytes": 251538 + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "audio", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 16, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "hls", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "historical-unsupported-hls-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 300, + 150, + 0, + 0 + ], + "currentTime": 0, + "duration": null, + "error": { + "code": 4, + "message": "Input has an unsupported or unrecognizable format." + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": { + "kind": "generated-hls-media", + "version": "ffmpeg version 2025-11-12-git-6cdd2cbe32-full_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers", + "duration": 12, + "commands": [ + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=160x90:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "low-%02d.mpegts", + "low.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "testsrc2=size=320x180:rate=24", + "-t", + "12", + "-an", + "-c:v", + "libx264", + "-pix_fmt", + "yuv420p", + "-profile:v", + "baseline", + "-level:v", + "3.0", + "-g", + "48", + "-keyint_min", + "48", + "-sc_threshold", + "0", + "-crf", + "28", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "high-%02d.mpegts", + "high.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=440:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "english-%02d.mpegts", + "english.m3u8" + ], + [ + "-hide_banner", + "-loglevel", + "error", + "-n", + "-f", + "lavfi", + "-i", + "sine=frequency=880:sample_rate=48000", + "-t", + "12", + "-vn", + "-c:a", + "aac", + "-b:a", + "48k", + "-ac", + "2", + "-f", + "hls", + "-hls_time", + "2", + "-hls_playlist_type", + "vod", + "-hls_segment_filename", + "french-%02d.mpegts", + "french.m3u8" + ] + ], + "files": { + "english-00.mpegts": { + "sha256": "cc599f7c270385e85c28f710a34c5bd90b09d4d27adb3b1e6af3de65584b8207", + "bytes": 13912 + }, + "english-01.mpegts": { + "sha256": "01b17c28defc8a8ebf4978c5236eb759d80521a1cb840898095c35dac420cec5", + "bytes": 14100 + }, + "english-02.mpegts": { + "sha256": "90751b8b5abedd6b2f2e4eb83ccd609098ec7f2901163aaebf977cb9a11c46eb", + "bytes": 14100 + }, + "english-03.mpegts": { + "sha256": "9b1d86b7b261df66dbdace4ef1e846796cd710ffb72b22fc69532c1fe7d1c55e", + "bytes": 13912 + }, + "english-04.mpegts": { + "sha256": "dbfddd4f997942dd0b912f4c8bdbc5c11ee2a3fc51ac67df48d3aed2756715b9", + "bytes": 14100 + }, + "english-05.mpegts": { + "sha256": "9b53790d4f50f172852b7d4ff51bdd4bedd39e4c7a1efbfe734edf7b9a68a533", + "bytes": 14100 + }, + "english-06.mpegts": { + "sha256": "50baaa5e9fe7ca49b22c4d0817c44103b3edc763aee7f1b17d22f796d4189d4a", + "bytes": 752 + }, + "english.m3u8": { + "sha256": "5aae9d117d458f65f7febae68555ea4e48b2055b4cfb123fb919e385a1edda21", + "bytes": 365 + }, + "french-00.mpegts": { + "sha256": "7278acd094bc7caeeeea424a2c11ac4285fc45a8becb6c8ec55068f295ae35cd", + "bytes": 13912 + }, + "french-01.mpegts": { + "sha256": "e9464d109e36a53d7f151442b544d47ce79324bbaa805e0a98f171621c9c7a13", + "bytes": 14100 + }, + "french-02.mpegts": { + "sha256": "3ac48cab6aac942950b59f79ac6bd950dcae425f14821b83b1b5bb72d6815eb0", + "bytes": 14100 + }, + "french-03.mpegts": { + "sha256": "906f2d8b1f29bb7d57240b145563bab975d8f7dfff78cebd1505b6d2a3feb43b", + "bytes": 13912 + }, + "french-04.mpegts": { + "sha256": "cbf82876118d41af254bdef51f6cd08d842e8c6edf53250667fad2b8088e3601", + "bytes": 14100 + }, + "french-05.mpegts": { + "sha256": "a91e564ec54d845837217c45b8e25b08fe208f2b5f97562f513baabd515427d9", + "bytes": 14100 + }, + "french-06.mpegts": { + "sha256": "2c8edc11b06bacf1e62c4db67594ce187aa93e0241012011ebcf587b64ccff46", + "bytes": 752 + }, + "french.m3u8": { + "sha256": "6f7fb3eacb944597fa3105cb6d708eac3a8dc413e1706a11b6fb0e631214634e", + "bytes": 358 + }, + "high-00.mpegts": { + "sha256": "c5a8faac85b0594818255117696dce43fda6b363df40e2f3ffc453bd236cc833", + "bytes": 45308 + }, + "high-01.mpegts": { + "sha256": "5714640c3f17d86c56036453dc17d45f871af63b461318c43527af3482f8661c", + "bytes": 52264 + }, + "high-02.mpegts": { + "sha256": "fea1cbfb199bc867a322c7a646d43594a1d0d1d23fa0bcb6e770f2669b489440", + "bytes": 48128 + }, + "high-03.mpegts": { + "sha256": "4a74a28e7ad6bc626358e32365a0b07df1da82c92753e28032983e22404958b5", + "bytes": 54144 + }, + "high-04.mpegts": { + "sha256": "d04889b3b996d3e79c12bc297f9577690d3ae4f4172cdc0484b584954dab789c", + "bytes": 47376 + }, + "high-05.mpegts": { + "sha256": "36ee0c64b8c3637d0e2282c611e9250650ac493440095fc2efbe9de1c54add15", + "bytes": 48128 + }, + "high.m3u8": { + "sha256": "672c0e8b99242be05b16fc747a00715b2c25579b1ecc1623c0579fa34f0cb11d", + "bytes": 311 + }, + "low-00.mpegts": { + "sha256": "cbd62f5f4641cbe188a15640139bea393b5927fce600ff7513ef9ade9b33fb62", + "bytes": 28952 + }, + "low-01.mpegts": { + "sha256": "f7821fba38c63f5d80daef21cdd3430880bdc9fd5f5adfa939ed6481106c2507", + "bytes": 32900 + }, + "low-02.mpegts": { + "sha256": "3dc93f9f0fd065678b01fc6c568c12350e9ab0b324d1e0fa0e9f77787da7e7d2", + "bytes": 30268 + }, + "low-03.mpegts": { + "sha256": "d94c8913f7fde98161550041287529b90a58d537d6083d4382540c5fce0b430b", + "bytes": 32336 + }, + "low-04.mpegts": { + "sha256": "11596c59b547c2ff23bbba1f70e15f061a3e87bbdc1f4f59daa9b5279a6003af", + "bytes": 29704 + }, + "low-05.mpegts": { + "sha256": "5c6ec25a69fdad73a23cfbc34f0f3c6d8abe44592650c92fa9110a38d6bd9e45", + "bytes": 29516 + }, + "low.m3u8": { + "sha256": "404a8d868ed2af3598269aee89caba0563c2805dac223fe4c00c9a9eda73554f", + "bytes": 305 + }, + "master.m3u8": { + "sha256": "f226bd38f3c76714ada2b5a6866ad1cb39b041023e4a18d971d175f26f917e38", + "bytes": 470 + }, + "video-only.m3u8": { + "sha256": "3d7bb9069f6218191dc65745389bf1ab0ba6d5ed66cbd14e2cf30211913da3fc", + "bytes": 108 + } + } + }, + "tracklessFixture": null, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "input": "trackless", + "capabilities": { + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined" + }, + "outcome": "unsupported-capability-control", + "state": { + "events": [ + { + "name": "video:waiting", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:loadstart", + "currentTime": 0, + "readyState": 0 + }, + { + "name": "video:error", + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "currentTime": 0, + "duration": 0, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0, + "hls": null + }, + "cleanup": { + "audioContext": "not-created", + "pendingFrames": 0, + "streamCancelled": false + }, + "hlsManifest": null, + "tracklessFixture": { + "parentSha256": "0ad1d7ad286aec6e0fa9e27fc1e487e7277df2e603e30040fb942365763d0233", + "sha256": "8b03d7a9ce2998e592c081bb83e88ed6c15c7a4c9add6a1cc0fda88d88f678c0" + }, + "scope": "Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "capabilities": { + "secure": true, + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined", + "coreVersion": "5.4.0" + }, + "outcome": "native-mp4-playback-observed", + "state": { + "events": [ + { + "name": "waiting", + "time": 85.19999998807907, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 85.40000000596046, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "waiting", + "time": 85.5, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 85.5, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadedmetadata", + "time": 106.80000001192093, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "durationchange", + "time": 106.80000001192093, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "progress", + "time": 106.90000000596046, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "loadeddata", + "time": 118.69999998807907, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplay", + "time": 118.80000001192093, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplaythrough", + "time": 118.80000001192093, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "progress", + "time": 119, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "play", + "time": 170.19999998807907, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "playing", + "time": 170.19999998807907, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 181.09999999403954, + "currentTime": 0.02133333333333333, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 431.30000001192093, + "currentTime": 0.2693333333333333, + "readyState": 4 + }, + { + "name": "pause", + "time": 552.3000000119209, + "currentTime": 0.3893333333333333, + "readyState": 4 + } + ], + "actions": [], + "ready": true, + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "paused": true, + "currentTime": 0.3893333333333333, + "error": null, + "readyState": 4, + "audioState": "running" + }, + "scope": "Two actual published proxies with actual core5.4.0; native MP4 pixels/clock or explicitly unsupported Windows WebKit APIs. No candidate, HLS or AV-sync acceptance.", + "frameClock": null + }, + { + "project": "chromium", + "browser": "153.0.8010.12", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "capabilities": { + "secure": true, + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined", + "coreVersion": "5.4.0" + }, + "outcome": "native-mp4-playback-observed", + "state": { + "events": [ + { + "name": "waiting", + "time": 86.90000000596046, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 87, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "waiting", + "time": 87, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 87.09999999403954, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadedmetadata", + "time": 113.80000001192093, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "durationchange", + "time": 113.80000001192093, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "progress", + "time": 113.90000000596046, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "loadeddata", + "time": 124.90000000596046, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "loadeddata", + "time": 124.90000000596046, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplay", + "time": 125.19999998807907, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplaythrough", + "time": 125.19999998807907, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "progress", + "time": 125.19999998807907, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "play", + "time": 176.5, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "playing", + "time": 176.59999999403954, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 187.40000000596046, + "currentTime": 0.010666666666666665, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 453.09999999403954, + "currentTime": 0.27999999999999997, + "readyState": 4 + }, + { + "name": "pause", + "time": 572.1999999880791, + "currentTime": 0.3893333333333333, + "readyState": 4 + } + ], + "actions": [], + "ready": true, + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "paused": true, + "currentTime": 0.3893333333333333, + "error": null, + "readyState": 4, + "audioState": "running" + }, + "scope": "Two actual published proxies with actual core5.4.0; native MP4 pixels/clock or explicitly unsupported Windows WebKit APIs. No candidate, HLS or AV-sync acceptance.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "capabilities": { + "secure": true, + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined", + "coreVersion": "5.4.0" + }, + "outcome": "native-mp4-playback-observed", + "state": { + "events": [ + { + "name": "waiting", + "time": 155, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 155, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "waiting", + "time": 155, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 155, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadedmetadata", + "time": 175, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "durationchange", + "time": 175, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "progress", + "time": 175, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "loadeddata", + "time": 194, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplay", + "time": 194, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplaythrough", + "time": 194, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "progress", + "time": 195, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "play", + "time": 299, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "playing", + "time": 299, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 303, + "currentTime": 0.008000000000000007, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 553, + "currentTime": 0.25866666666666666, + "readyState": 4 + }, + { + "name": "pause", + "time": 702, + "currentTime": 0.408, + "readyState": 4 + } + ], + "actions": [], + "ready": true, + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "paused": true, + "currentTime": 0.408, + "error": null, + "readyState": 4, + "audioState": "running" + }, + "scope": "Two actual published proxies with actual core5.4.0; native MP4 pixels/clock or explicitly unsupported Windows WebKit APIs. No candidate, HLS or AV-sync acceptance.", + "frameClock": null + }, + { + "project": "firefox", + "browser": "155.0", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "capabilities": { + "secure": true, + "VideoDecoder": "function", + "AudioDecoder": "function", + "AudioContext": "function", + "webkitAudioContext": "undefined", + "coreVersion": "5.4.0" + }, + "outcome": "native-mp4-playback-observed", + "state": { + "events": [ + { + "name": "waiting", + "time": 137, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 137, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "waiting", + "time": 137, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 137, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadedmetadata", + "time": 163, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "durationchange", + "time": 163, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "progress", + "time": 163, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "loadeddata", + "time": 172, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "loadeddata", + "time": 172, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplay", + "time": 173, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "canplaythrough", + "time": 173, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "progress", + "time": 173, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "play", + "time": 254, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "playing", + "time": 254, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 255, + "currentTime": 0, + "readyState": 4 + }, + { + "name": "timeupdate", + "time": 512, + "currentTime": 0.25066666666666665, + "readyState": 4 + }, + { + "name": "pause", + "time": 650, + "currentTime": 0.3893333333333333, + "readyState": 4 + } + ], + "actions": [], + "ready": true, + "dimensions": [ + 320, + 180, + 320, + 180 + ], + "paused": true, + "currentTime": 0.3893333333333333, + "error": null, + "readyState": 4, + "audioState": "running" + }, + "scope": "Two actual published proxies with actual core5.4.0; native MP4 pixels/clock or explicitly unsupported Windows WebKit APIs. No candidate, HLS or AV-sync acceptance.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.2.0", + "sha256": "7d088c0abe2f3c1e2857cb0547405ce1e5588630f28e484a64211fc675322bbd", + "capabilities": { + "secure": true, + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined", + "coreVersion": "5.4.0" + }, + "outcome": "verified-unsupported-capability-control", + "state": { + "events": [ + { + "name": "waiting", + "time": 150, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 150, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "waiting", + "time": 154, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 154, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "error", + "time": 212, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadedmetadata", + "time": 214, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "durationchange", + "time": 214, + "currentTime": 0, + "readyState": 1 + }, + { + "name": "progress", + "time": 214, + "currentTime": 0, + "readyState": 1 + } + ], + "actions": [], + "ready": false, + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "paused": true, + "currentTime": 0, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 1 + }, + "scope": "Two actual published proxies with actual core5.4.0; native MP4 pixels/clock or explicitly unsupported Windows WebKit APIs. No candidate, HLS or AV-sync acceptance.", + "frameClock": null + }, + { + "project": "webkit", + "browser": "26.6", + "platform": "win32", + "implementation": "published-1.0.0", + "sha256": "7331465d8c7a6575505b9d3fd45986c5d3d9cb3839b2620ad5a52c581199562b", + "capabilities": { + "secure": true, + "VideoDecoder": "undefined", + "AudioDecoder": "undefined", + "AudioContext": "undefined", + "webkitAudioContext": "undefined", + "coreVersion": "5.4.0" + }, + "outcome": "verified-unsupported-capability-control", + "state": { + "events": [ + { + "name": "waiting", + "time": 154, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 154, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "waiting", + "time": 154, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "loadstart", + "time": 154, + "currentTime": 0, + "readyState": 0 + }, + { + "name": "error", + "time": 216, + "currentTime": 0, + "readyState": 0 + } + ], + "actions": [], + "ready": false, + "dimensions": [ + 0, + 0, + 0, + 0 + ], + "paused": true, + "currentTime": 0, + "error": { + "code": 4, + "message": "undefined is not a constructor (evaluating 'new t')" + }, + "readyState": 0 + }, + "scope": "Two actual published proxies with actual core5.4.0; native MP4 pixels/clock or explicitly unsupported Windows WebKit APIs. No candidate, HLS or AV-sync acceptance.", + "frameClock": null + } + ] + }, + "fixtureSha256LF": { + "test/mediabunny.test.js": "cfde988178f6d358fca55bff21473a7f8855b3ceedc0b9507e5a2871fd7ac52e", + "test/browser/mediabunny.spec.js": "0d9af2fc2c47a9a78953e8c1fd69148ba553dc3b5e3f5ff0c141f537597ae9fe", + "test/browser/mediabunny-inputs.spec.js": "341ec06c3ec6e95ffce563eb47f423618a585b60a5057341e2d847e5004cbf0e", + "test/helpers/mediabunny.js": "3e25bd5274d58be4d0bb85cd5fb2a825848cae1bfdbfaf5c91177a0c2b03a87a", + "test/helpers/trackless-mp4.js": "41e56b43ba3d7a7dbc1ba0620109384afbf279c5283d8be4fa3e18d356e0d2f8" + }, + "checks": [ + { + "command": "yarn test:mediabunny", + "result": "pass", + "tests": 24, + "scope": "Actual historical engines with controlled lifecycle interleavings and Range responses" + }, + { + "command": "focused eslint --no-fix", + "result": "pass", + "log": "refactor/.cache/mb02-lint-final.log" + }, + { + "command": "yarn test:browser test/browser/mediabunny-inputs.spec.js test/browser/mediabunny.spec.js", + "result": "pass", + "tests": 42, + "log": "refactor/.cache/mb02-browser-final.log" + }, + { + "command": "yarn ci:check", + "result": "pass", + "tests": { + "unit": 1030, + "engineering": 14, + "baseline": 141, + "mainTotal": 1185, + "repeatedContractExecutions": 44 + }, + "strictProductionTypeScriptFiles": 290, + "log": "refactor/.cache/mb02-ci-integrated.log" + }, + { + "command": "production/demo/artifact hashes compared with frozen source", + "result": "unchanged", + "files": 17 + } + ], + "limitations": [ + "Historical baseline, not candidate fixes or release acceptance.", + "36 native-input cases use a controlled ArtPlayer host; six MP4 cases use actual core5.4.0.", + "Short frame/audio-clock observations are not acoustic latency, long-run drift or a device support claim; complete AV sync remains MB-06/09.", + "Normal settled-playback AudioContext/RAF cleanup does not waive the reproduced pending-operation failures.", + "HLS state transitions tested; actual control/setting DOM and concurrent topology updates remain MB-07/09.", + "Canvas/Ambilight factory compatibility decision remains pending." + ], + "ciIntegration": "Added test/mediabunny.test.js to explicit test:unit list and added test:mediabunny; initial full CI passed without these cases, then integration was corrected and full CI rerun." +} diff --git a/refactor/changes/2026-09-12-PKG-MB-02-baseline.md b/refactor/changes/2026-09-12-PKG-MB-02-baseline.md new file mode 100644 index 000000000..2be8739c8 --- /dev/null +++ b/refactor/changes/2026-09-12-PKG-MB-02-baseline.md @@ -0,0 +1,71 @@ +# PKG-MB-02 媒体、事件与资源基线 + +此记录接续63c8938d检查点。完成状态以[验证记录](../baselines/mb-behavior-validation.json)和 +独立完成提交为准;历史负例通过表示问题已经复现,不表示生产实现已修复。 + +## 浏览器覆盖 + +两个实际npm proxy 1.0.0/1.2.0,三引擎,共42项: + +- 6项完整核心5.4.0组合:4次真实MP4播放/像素/暂停成功,2次Windows WebKit能力失败对照。 +- 36项真实SDK输入,使用实际核心utils/config与受控ArtPlayer宿主:WebM、MP4 Blob、4096字节分块 + ReadableStream、纯音频、HLS、无轨道容器。受控宿主用于隔离核心自动重连,不模拟浏览器解码器。 +- 后36项中16项完成真实输入播放、暂停、精确seek和恢复;10项缺失WebCodecs/Web Audio构造器; + 3项1.0.0流锁定错误,3项1.0.0 HLS不支持;4项无轨道容器错误地声称ready的历史行为。 +- 总计20次真实播放成功、12次环境能力对照、6次历史输入失败、4次无轨道就绪行为;不能称42次播放成功。 + +1.0.0的ReadableStream同时被旧音/视频输入读取,三个浏览器报精确的stream locked错误; +1.0.0的HLS错误为`Input has an unsupported or unrecognizable format.`。 +这些在1.2.0已正常,候选必须保持修正。Windows WebKit的构造器缺失单独判断,不能把同一环境 +中的历史stream/HLS错误都归为环境问题,也不能将Windows WebKit结论扩大为全部Safari。 + +## 就绪、seek、HLS与时钟 + +就绪顺序和次数使用逐事件断言:1.0.0 WebM/Blob初次有两个loadeddata,seek又发一次;1.2.0无该重复。 +视频为空但音频存在的正常容器单独验证;无任何轨道的容器由仓库MP4移除trak后确定性生成, +记录父文件和派生文件哈希,不下载不明媒体。两代均readyState=4且尺寸0,1.2.0的loadedmetadata +发两次、1.0.0一次。MB-READY-01保留后续协调修复责任。 + +seek测试观测公开currentTime setter调用实际engine.seek的Promise,不替换实现;验证目标时间、 +seeking/paused和精确事件序列。HLS使用既有哈希校验的本地12秒样本,实际切到90p、法语音轨, +核对manual模式,再切回MP4并确认HLS状态null。真实控件/设置DOM、并发选轨和组合长播仍由MB-07/09验收。 + +纯音频/HLS检查实际AudioBufferSink和已排程Web Audio节点。视频恢复播放时观测实际CanvasSink +迭代器的frame timestamp和真正drawImage时的audio.currentTime,保留原始样本与偏差统计。 +这是短时SDK时钟基线,不能当作声学音画延迟、长期漂移或各设备音频输出都已验证;对应后续MB-06/09。 + +settled playback完成后验证创建的AudioContext关闭、所观测代理RAF队列归零。 +不据此宣称所有内部资源或pending操作都已释放;后者有明确失败基线。 + +## 生命周期与Range + +24项Node测试使用三份实际历史主产物、原始engine方法,控制外部Promise、音频动作和timer: + +1. destroy后晚load失败仍回写error/networkState,waiting/loadstart两个timer仍执行。 +2. pending play遇到pause,晚返回仍video.start并发play/playing,paused却为true。 +3. pending play遇到destroy,晚返回仍video.start并发事件。 +4. audio.play拒绝后engine.paused保持false,第二次play不再重试。 +5. pending seek遇到destroy,晚返回仍seeked并恢复play。 +6. 成功load与destroy都未回收loadTimeout timer;已settled的race继续观察其晚拒绝。 +7. 正常超时仍保持code4/Load timeout,不被底层更晚的拒绝覆盖。 +8. HEAD Range预检拒绝缺失响应头、网络异常警告后继续;不设置engine.error;1.0.0仍预检HLS,1.2.0跳过。 + +前6组共18项复现历史问题;后2组6项保留正常/版本边界。不会将受控宿主发事件直接等同于 +完整ArtPlayer核心destroy后用户仍收到事件;也不会用模拟音频动作宣称真实音画同步通过。 + +## 检查与后续 + +```sh +node --test test/mediabunny.test.js +yarn test:browser test/browser/mediabunny-inputs.spec.js test/browser/mediabunny.spec.js +yarn ci:check +``` + +早期30项输入实验中的四个Chromium/Firefox 1.0.0错误已保留完整报告、trace及截图,随后才建立 +精确历史负例。各次浏览器report和整个results目录分别归档,未覆盖失败证据。 +下一步MB-03处理input、Range和取消,MB-04处理主状态/事件协调,05/06处理帧及音频调度, +07处理轨道/控件。这些缺陷均未在本步修改生产代码;工厂类型待决项仍只影响Canvas/Ambilight。 + +最终CI1185项(1030单元+14工程+141基线)通过,另44重复契约;290生产TS严格检查。 +新增test:mediabunny并将24项加入test:unit,补齐首次CI未包含该文件的入口遗漏后重跑全量CI。 +17个冻结生产/demo/产物和五个最终测试文件哈希已复核;本任务独立本地提交。 diff --git a/refactor/mb-validation.md b/refactor/mb-validation.md index 2d52842e3..f960ecbfe 100644 --- a/refactor/mb-validation.md +++ b/refactor/mb-validation.md @@ -1,7 +1,8 @@ # MediaBunny proxy 验证入口 开始改动前读取[冻结契约](baselines/mb-contract.md)、[接口快照](baselines/mb-surface.json)、 -[归档/源码哈希](baselines/mb-release.json)。当前阶段为PKG-MB-01;不得把接口基线称为真实媒体验收。 +[归档/源码哈希](baselines/mb-release.json)。MB-01接口基线与 +[MB-02行为基线](changes/2026-09-12-PKG-MB-02-baseline.md)分开记录;不得把接口测试称为真实媒体验收。 ## 可重复命令 @@ -10,6 +11,8 @@ ```sh node refactor/scripts/mb-contract.mjs node --test refactor/scripts/mb-contract.test.mjs +node --test test/mediabunny.test.js +yarn test:browser test/browser/mediabunny-inputs.spec.js test/browser/mediabunny.spec.js yarn ci:check ``` @@ -22,8 +25,9 @@ play/load/seek转发测试刻意截获engine方法;不得宣传为真实播放 ## 后续顺序 -1. MB-02建立真实MP4/WebM/HLS/Blob/Stream和失败样本;三浏览器能力分别记录。 - 复现pending load/destroy、超时后释放、无轨道、并发seek/选轨、metadata重复与晚帧/音频回调。 +1. MB-02的输入、seek、HLS轨道、无轨道和失败样本见行为基线。42项浏览器检查须区分 + 20次实际播放、12次能力对照、6次历史输入失败及4次无轨道就绪行为;24项生命周期测试含18个历史缺陷。 + 后续修改须复跑对应正常和负例,不把全部负例变为候选豁免;并发选轨、晚帧和音频回调的完整修复分别在04/05/06/07。 2. MB-03输入/取消,MB-04事件/状态协调,MB-05帧调度,MB-06音频时钟,MB-07配对轨道/控件。 按已批准计划分步迁移,不等到MB-08才一次性堆积全部源码修改。 3. MB-08完成严格TS和公开声明兼容矩阵;保留HTMLCanvasElement精确Result、可选工厂和全工厂 diff --git a/refactor/plan.md b/refactor/plan.md index d4bb1a00b..2aef873f7 100644 --- a/refactor/plan.md +++ b/refactor/plan.md @@ -4,7 +4,7 @@ 基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 222 项,范围 22 个包及工作区/示例。 -状态:todo 116 / doing 8 / blocked 0 / done 98 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 +状态:todo 116 / doing 7 / blocked 0 / done 99 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。 前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。 @@ -330,7 +330,7 @@ | ID | 范围 / 步骤 | 前置依赖 | 交付物 | 验收条件 | 风险 | 状态 | | --- | --- | --- | --- | --- | --- | --- | | PKG-MB-01 | artplayer-proxy-mediabunny
核对 shim 与媒体契约 | BASE-05 | 全部 option、art.mediabunny、canvas/shim 属性及事件表 | 公开暴露成员和实际发布依赖/资源范围明确;核实 third-party.json 所记录依赖 MPL-2.0 元数据与实际 bundle 的许可/通知范围,不从根 MIT 推断 | H | done | -| PKG-MB-02 | artplayer-proxy-mediabunny
建立真实媒体与事件基线 | PKG-MB-01, ENG-05, ENG-08 | MP4/WebM/HLS/Blob/Stream、seek/错误/轨道切换样本 | ready 事件顺序、音画同步、超时和释放可重跑 | H | doing | +| PKG-MB-02 | artplayer-proxy-mediabunny
建立真实媒体与事件基线 | PKG-MB-01, ENG-05, ENG-08 | MP4/WebM/HLS/Blob/Stream、seek/错误/轨道切换样本 | ready 事件顺序、音画同步、超时和释放可重跑 | H | done | | PKG-MB-03 | artplayer-proxy-mediabunny
整理 input 与加载取消 | PKG-MB-02, CORE-09 | input.js 源检测、输入资源、Range 与取消 | HLS 检测在 input 边界,旧来源类型和超时保持 | H | todo | | PKG-MB-04 | artplayer-proxy-mediabunny
整理 VideoShim/EventTarget/Engine 协调 | PKG-MB-03, CORE-06, CORE-11 | shim 描述符、事件桥、加载状态和操作隔离 | 公开属性/同步异步返回与事件重入顺序保持 | H | todo | | PKG-MB-05 | artplayer-proxy-mediabunny
整理视频解码、seek 和帧释放 | PKG-MB-04 | VideoEngine 调度、队列、晚帧处理和资源释放 | 暂停/seek/切源无旧帧覆盖,默认丢帧策略不变 | H | todo | @@ -521,5 +521,5 @@ - PKG-CANVAS-03: [记录](changes/2026-09-12-PKG-CANVAS-03-lifecycle.md) [记录](baselines/canvas-lifecycle-validation.json) [记录](canvas-validation.md) - PKG-CANVAS-04: [记录](changes/2026-09-12-PKG-CANVAS-04-types.md) [记录](baselines/canvas-types-validation.json) [记录](canvas-validation.md) - PKG-MB-01: [记录](baselines/mb-release.json) [记录](baselines/mb-surface.json) [记录](baselines/mb-contract.md) [记录](baselines/mb-contract-validation.json) [记录](mb-validation.md) [记录](changes/2026-09-12-PKG-MB-01-contract.md) -- PKG-MB-02: [记录](changes/2026-09-12-PKG-MB-02-checkpoint.md) [记录](baselines/mb-media-checkpoint.json) [记录](mb-validation.md) +- PKG-MB-02: [记录](changes/2026-09-12-PKG-MB-02-checkpoint.md) [记录](baselines/mb-media-checkpoint.json) [记录](mb-validation.md) [记录](changes/2026-09-12-PKG-MB-02-baseline.md) [记录](baselines/mb-behavior-validation.json) - PKG-FACTORY-01: [记录](baselines/factory-assignment-gaps.json) [记录](baselines/factory-compatibility-proposals.json) [记录](factory-compatibility-decision.md) [记录](changes/2026-09-12-PKG-FACTORY-01-decision.md) diff --git a/refactor/progress.md b/refactor/progress.md index e59fe95e9..006e910dd 100644 --- a/refactor/progress.md +++ b/refactor/progress.md @@ -1,5 +1,15 @@ # 进度与证据 +## 最新完成:PKG-MB-02 媒体、事件与资源基线 + +24项历史生命周期检查通过,已接入统一CI;42项真实浏览器检查包含20次播放、12次环境能力 +对照、6次历史输入失败和4次无轨道就绪行为,不能当作42次播放成功。短时帧/音频时钟、seek、 +HLS轨道状态及正常AudioContext/RAF释放均有证据;待完成操作的泄漏和陈旧回调已复现。 +完整CI1185项(1030单元+14工程+141基线)通过,另44重复契约,290生产TS。 +见[任务记录](changes/2026-09-12-PKG-MB-02-baseline.md)和[验证证据](baselines/mb-behavior-validation.json)。 +生产源码未在本步变更;接着MB-03输入与加载取消。222项:99 done、7 doing、116 todo。 +Canvas/Ambilight类型决定仍待确认;未推送或发布。 + ## 当前检查点:PKG-MB-02 真实MP4与销毁负例 22项Node(含3个销毁后晚加载历史缺陷)通过;6项浏览器检查中,4项Chromium/Firefox diff --git a/refactor/risk-table.md b/refactor/risk-table.md index 59fc2ac7f..09a7ff4a4 100644 --- a/refactor/risk-table.md +++ b/refactor/risk-table.md @@ -172,3 +172,4 @@ | MB-LIFE-01 | open / 已复现 | MediaBunny load, track replacement, timeout, RAF and audio callbacks lack one shared terminal owner | PKG-MB-02, PKG-MB-03, PKG-MB-04, PKG-MB-05, PKG-MB-06, PKG-MB-07, PKG-MB-09 | | MB-TYPE-01 | open / 已复现 | MediaBunny proxy declares only Canvas while exposing a shim and changes CommonJS export generation between releases | PKG-MB-08, PKG-MB-10 | | MB-CAP-01 | open / 已复现 | Current Windows WebKit lacks WebCodecs and Web Audio constructors needed by historical MediaBunny proxies | PKG-MB-02, PKG-MB-09 | +| MB-READY-01 | open / 已复现 | MediaBunny historical readiness can repeat for trackless input and occur after capability errors | PKG-MB-04, PKG-MB-09 | diff --git a/refactor/risks.json b/refactor/risks.json index 846950375..3097670cf 100644 --- a/refactor/risks.json +++ b/refactor/risks.json @@ -3648,7 +3648,7 @@ "PKG-MB-07", "PKG-MB-09" ], - "compatibleResolution": "Reproduce pending operations and destroy/source-switch races before migrating each owner; preserve public event and promise behavior while preventing stale resource use. MB-02 now reproduces late load rejection and uncancelled waiting/loadstart timers after destroy in all three historical implementations using a controlled host. Other interleavings and full-core native behavior are not yet verified.", + "compatibleResolution": "Reproduce pending operations and destroy/source-switch races before migrating each owner; preserve public event and promise behavior while preventing stale resource use. MB-02 now reproduces late load rejection and uncancelled waiting/loadstart timers after destroy in all three historical implementations using a controlled host. Other interleavings and full-core native behavior are not yet verified. Expanded MB-02 baseline reproduces play-after-pause/destroy, rejected-play false state, seek-after-destroy and retained successful-load timeout timers in all three actual historical implementations; Range and active-timeout normal controls remain separate.", "closureCriteria": "Historical failing interleavings and candidate cancellation/cleanup pass with real media and event evidence, including long playback and track topology.", "status": "open", "evidence": [ @@ -3656,7 +3656,9 @@ "refactor/baselines/mb-contract.md", "refactor/changes/2026-09-12-PKG-MB-01-contract.md", "refactor/changes/2026-09-12-PKG-MB-02-checkpoint.md", - "refactor/baselines/mb-media-checkpoint.json" + "refactor/baselines/mb-media-checkpoint.json", + "refactor/changes/2026-09-12-PKG-MB-02-baseline.md", + "refactor/baselines/mb-behavior-validation.json" ] }, { @@ -3689,7 +3691,25 @@ "closureCriteria": "Per-browser native media/support matrix and predictable unsupported-capability behavior verified, including target Safari evidence where support is claimed.", "evidence": [ "refactor/changes/2026-09-12-PKG-MB-02-checkpoint.md", - "refactor/baselines/mb-media-checkpoint.json" + "refactor/baselines/mb-media-checkpoint.json", + "refactor/changes/2026-09-12-PKG-MB-02-baseline.md", + "refactor/baselines/mb-behavior-validation.json" + ] + }, + { + "id": "MB-READY-01", + "title": "MediaBunny historical readiness can repeat for trackless input and occur after capability errors", + "status": "open", + "confirmation": "reproduced", + "owners": [ + "PKG-MB-04", + "PKG-MB-09" + ], + "compatibleResolution": "Use explicit coordinated readiness and failure state, preserving valid event order while preventing duplicate or stale callbacks; evaluate trackless behavior separately from normal media.", + "closureCriteria": "Candidate metadata/data/canplay ordering and counts pass normal, absent-track and failure interleavings in native browsers and controlled race tests.", + "evidence": [ + "refactor/changes/2026-09-12-PKG-MB-02-baseline.md", + "refactor/baselines/mb-behavior-validation.json" ] } ] diff --git a/refactor/tasks.json b/refactor/tasks.json index cf796d1ae..1717a6ef0 100644 --- a/refactor/tasks.json +++ b/refactor/tasks.json @@ -3416,14 +3416,16 @@ "ENG-05", "ENG-08" ], - "status": "doing", + "status": "done", "risk": "H", "deliverable": "MP4/WebM/HLS/Blob/Stream、seek/错误/轨道切换样本", "acceptance": "ready 事件顺序、音画同步、超时和释放可重跑", "evidence": [ "changes/2026-09-12-PKG-MB-02-checkpoint.md", "baselines/mb-media-checkpoint.json", - "mb-validation.md" + "mb-validation.md", + "changes/2026-09-12-PKG-MB-02-baseline.md", + "baselines/mb-behavior-validation.json" ] }, { diff --git a/test/browser/mediabunny-inputs.spec.js b/test/browser/mediabunny-inputs.spec.js new file mode 100644 index 000000000..53242df3e --- /dev/null +++ b/test/browser/mediabunny-inputs.spec.js @@ -0,0 +1,215 @@ +import assert from 'node:assert/strict' +import fs from 'node:fs' +import { hash } from '../../refactor/scripts/releases.mjs' +import { mbHistorical } from '../helpers/mediabunny.js' +import { tracklessMp4 } from '../helpers/trackless-mp4.js' +import { expect, test } from './fixtures.js' + +const implementations = (await mbHistorical()).filter(item => item.name.startsWith('published')) +const manifest = JSON.parse(fs.readFileSync(new URL('./media/hls/manifest.json', import.meta.url))) +const hls = new Map(Object.entries(manifest.files).map(([name, expected]) => { + const bytes = fs.readFileSync(new URL(`./media/hls/${name}`, import.meta.url)) + assert.equal(hash(bytes), expected.sha256) + return [name, bytes] +})) +const pattern = fs.readFileSync(new URL('./media/pattern.mp4', import.meta.url)) +const trackless = tracklessMp4(pattern) + +for (const implementation of implementations) { + for (const input of ['webm', 'blob', 'stream', 'audio', 'hls', 'trackless']) { + test(`MediaBunny ${implementation.name}: native ${input} input and seek baseline`, async ({ page, browserName }, testInfo) => { + await page.route('**/mb-hls/**', async (route) => { + const name = new URL(route.request().url()).pathname.split('/').at(-1) + const body = hls.get(name) + await route.fulfill({ status: body ? 200 : 404, body: body || 'Missing fixture', contentType: name.endsWith('.m3u8') ? 'application/vnd.apple.mpegurl' : 'video/mp2t' }) + }) + await page.route('**/mb-trackless.mp4', route => route.fulfill({ status: 200, body: trackless, contentType: 'video/mp4' })) + await page.goto('/test/player.html?core=published') + await page.addScriptTag({ content: `(() => { + const pendingFrames = new Set(); + const requestAnimationFrame = callback => { + const id = window.requestAnimationFrame(time => { pendingFrames.delete(id); callback(time); }); + pendingFrames.add(id); return id; + }; + const cancelAnimationFrame = id => { pendingFrames.delete(id); window.cancelAnimationFrame(id); }; + window.mbPendingFrames = pendingFrames; + const module = { exports: {} }; const exports = module.exports; + ${implementation.code}; window.mbFactory = module.exports.default || module.exports; + })();` }) + const capabilities = await page.evaluate(() => ({ VideoDecoder: typeof VideoDecoder, AudioDecoder: typeof AudioDecoder, AudioContext: typeof AudioContext, webkitAudioContext: typeof window.webkitAudioContext })) + let outcome = 'unverified' + try { + await page.evaluate(async (input) => { + const listeners = new Map() + window.mbEvents = [] + window.mbActions = [] + window.mbHost = { + constructor: window.Artplayer, + option: { url: '', autoSize: false }, + template: { $player: document.querySelector('.player') }, + on(name, fn) { + const list = listeners.get(name) || [] + list.push(fn) + listeners.set(name, list) + }, + emit(name, ...args) { + window.mbEvents.push({ name, currentTime: window.mbCanvas?.currentTime, readyState: window.mbCanvas?.readyState }) + for (const fn of listeners.get(name) || []) fn(...args) + }, + } + const canvas = window.mbFactory({ muted: true })(window.mbHost) + window.mbCanvas = canvas + document.querySelector('.player').appendChild(canvas) + let source = input === 'webm' ? '/test/pattern.webm' : input === 'audio' ? '/test/audio-tone.m4a' : input === 'hls' ? '/mb-hls/master.m3u8' : input === 'trackless' ? '/mb-trackless.mp4' : '/test/pattern.mp4' + if (input === 'blob' || input === 'stream') { + const bytes = new Uint8Array(await (await fetch(source)).arrayBuffer()) + window.mbInputBytes = bytes.length + source = input === 'blob' + ? new Blob([bytes], { type: 'video/mp4' }) + : new ReadableStream({ + start(controller) { + for (let offset = 0; offset < bytes.length; offset += 4096) controller.enqueue(bytes.slice(offset, offset + 4096)) + controller.close() + }, + cancel() { window.mbStreamCancelled = true }, + }) + } + const load = canvas.engine.load.bind(canvas.engine) + canvas.engine.load = (source) => { + window.mbLoad = load(source) + return window.mbLoad + } + canvas.src = source + await window.mbLoad + document.querySelector('#play').onclick = () => canvas.play().catch(error => window.mbActions.push({ name: error.name, message: error.message })) + }, input) + const loaded = await page.evaluate(() => ({ error: window.mbCanvas.error, readyState: window.mbCanvas.readyState, dimensions: [window.mbCanvas.videoWidth, window.mbCanvas.videoHeight] })) + if (implementation.name === 'published-1.0.0' && ['stream', 'hls'].includes(input)) { + const messages = { + chromium: 'Failed to execute \'getReader\' on \'ReadableStream\': ReadableStreamDefaultReader constructor can only accept readable streams that are not yet locked to a reader', + firefox: 'ReadableStream.getReader: Cannot get a new reader for a readable stream already locked by another reader.', + webkit: 'ReadableStream is locked', + } + expect(loaded.error).toEqual({ code: 4, message: input === 'hls' ? 'Input has an unsupported or unrecognizable format.' : messages[browserName] }) + expect(loaded.readyState).toBe(0) + expect(loaded.dimensions).toEqual([0, 0]) + outcome = input === 'hls' ? 'historical-unsupported-hls-control' : 'historical-stream-lock-control' + } + else if (capabilities.AudioContext === 'undefined' && capabilities.webkitAudioContext === 'undefined') { + expect(browserName).toBe('webkit') + expect(capabilities).toEqual({ VideoDecoder: 'undefined', AudioDecoder: 'undefined', AudioContext: 'undefined', webkitAudioContext: 'undefined' }) + expect(loaded.error).toEqual({ code: 4, message: 'undefined is not a constructor (evaluating \'new t\')' }) + expect(loaded.readyState).toBeLessThan(4) + outcome = 'unsupported-capability-control' + } + else { + expect(loaded.error).toBeNull() + expect(loaded.readyState).toBe(4) + if (input === 'trackless') { + expect(loaded.dimensions).toEqual([0, 0]) + expect(await page.evaluate(() => window.mbEvents.filter(item => item.name === 'video:loadedmetadata').length)).toBe(implementation.name === 'published-1.2.0' ? 2 : 1) + expect(await page.evaluate(() => window.mbEvents.filter(item => item.name === 'video:canplay').length)).toBe(1) + outcome = 'historical-trackless-readiness-control' + return + } + const readiness = await page.evaluate(() => window.mbEvents.map(item => item.name).filter(name => ['video:loadedmetadata', 'video:loadeddata', 'video:canplay', 'video:canplaythrough'].includes(name))) + const repeatedData = implementation.name === 'published-1.0.0' && input !== 'audio' + expect(readiness).toEqual(['video:loadedmetadata', 'video:loadeddata', ...(repeatedData ? ['video:loadeddata'] : []), 'video:canplay', 'video:canplaythrough']) + if (input === 'audio') + expect(loaded.dimensions).toEqual([0, 0]) + else expect(loaded.dimensions[0]).toBeGreaterThan(0) + await page.click('#play') + await expect.poll(() => page.evaluate(() => window.mbCanvas.currentTime)).toBeGreaterThan(0.15) + if (['audio', 'hls'].includes(input)) { + expect(await page.evaluate(() => Boolean(window.mbCanvas.engine.audio.audioSink))).toBe(true) + expect(await page.evaluate(() => window.mbCanvas.engine.audio.queuedNodes.size)).toBeGreaterThan(0) + } + await page.evaluate(() => window.mbCanvas.pause()) + await page.evaluate(async () => { + const canvas = window.mbCanvas + window.mbSeekEventsStart = window.mbEvents.length + window.mbFrameClockSamples = [] + const video = canvas.engine.video + if (video.videoSink) { + const times = new WeakMap() + const canvases = video.videoSink.canvases.bind(video.videoSink) + video.videoSink.canvases = (...args) => { + const iterator = canvases(...args) + const next = iterator.next.bind(iterator) + iterator.next = async (...values) => { + const result = await next(...values) + if (!result.done && result.value) + times.set(result.value.canvas, result.value.timestamp) + return result + } + return iterator + } + const draw = video.ctx.drawImage.bind(video.ctx) + video.ctx.drawImage = (...args) => { + const result = draw(...args) + if (times.has(args[0])) + window.mbFrameClockSamples.push({ frame: times.get(args[0]), audioClock: canvas.engine.audio.currentTime, paused: canvas.paused }) + return result + } + } + const seek = canvas.engine.seek.bind(canvas.engine) + canvas.engine.seek = (time) => { + window.mbSeek = seek(time) + return window.mbSeek + } + window.mbSeekTarget = Math.min(0.5, canvas.duration / 2) + canvas.currentTime = window.mbSeekTarget + await window.mbSeek + }) + expect(await page.evaluate(() => window.mbCanvas.seeking)).toBe(false) + expect(await page.evaluate(() => window.mbCanvas.paused)).toBe(true) + expect(await page.evaluate(() => window.mbCanvas.currentTime)).toBeGreaterThan(0.2) + expect(await page.evaluate(() => window.mbCanvas.currentTime === window.mbSeekTarget)).toBe(true) + expect(await page.evaluate(() => window.mbEvents.slice(window.mbSeekEventsStart).map(item => item.name))).toEqual(['video:seeking', 'video:waiting', ...(repeatedData ? ['video:loadeddata'] : []), 'video:seeked']) + if (input !== 'audio') { + await page.click('#play') + await expect.poll(() => page.evaluate(() => window.mbFrameClockSamples.filter(sample => !sample.paused).length)).toBeGreaterThan(2) + await page.evaluate(() => window.mbCanvas.pause()) + } + if (input === 'hls') { + const tracks = await page.evaluate(async () => { + const canvas = window.mbCanvas + const initial = await canvas.getM3u8State() + const low = initial.levels.find(level => level.height === 90) + await canvas.switchM3u8Quality(low.id) + const quality = await canvas.getM3u8State() + const french = quality.audios.find(track => track.lang === 'fr') + await canvas.switchM3u8Audio(french.id) + const audio = await canvas.getM3u8State() + window.mbTrackTransitions = { initial: initial.currentLevel.height, quality: quality.currentLevel.height, videoMode: quality.videoMode, language: audio.currentAudio.lang, audioMode: audio.audioMode } + canvas.src = '/test/pattern.mp4' + await window.mbLoad + window.mbTrackTransitions.afterSourceSwitch = await canvas.getM3u8State() + return window.mbTrackTransitions + }) + expect(tracks).toEqual({ initial: 180, quality: 90, videoMode: 'manual', language: 'fr', audioMode: 'manual', afterSourceSwitch: null }) + } + expect(await page.evaluate(() => window.mbActions)).toEqual([]) + outcome = 'native-input-playback-and-seek' + } + } + finally { + const state = await page.evaluate(async () => { + const canvas = window.mbCanvas + if (!canvas) + return null + const hls = canvas.getM3u8State ? await canvas.getM3u8State().catch(error => ({ error: error.message })) : null + return { events: window.mbEvents, actions: window.mbActions, dimensions: [canvas.width, canvas.height, canvas.videoWidth, canvas.videoHeight], currentTime: canvas.currentTime, duration: canvas.duration, error: canvas.error, readyState: canvas.readyState, audioState: canvas.engine.audio.audioContext?.state, frameClockSamples: window.mbFrameClockSamples, tracks: window.mbTrackTransitions, hls: hls && { levels: hls.levels?.map(({ id, height }) => ({ id, height })), audios: hls.audios?.map(({ id, lang }) => ({ id, lang })), error: hls.error }, inputBytes: window.mbInputBytes } + }).catch(error => ({ error: error.message })) + await page.evaluate(() => { + window.mbContext = window.mbCanvas?.engine.audio.audioContext + window.mbHost?.emit('destroy') + }) + await expect.poll(() => page.evaluate(() => window.mbContext?.state || 'not-created')).toMatch(/^(?:closed|not-created)$/) + expect(await page.evaluate(() => window.mbPendingFrames.size)).toBe(0) + const cleanup = await page.evaluate(() => ({ audioContext: window.mbContext?.state || 'not-created', pendingFrames: window.mbPendingFrames.size, streamCancelled: window.mbStreamCancelled || false })) + await testInfo.attach('mediabunny-native-input', { contentType: 'application/json', body: JSON.stringify({ implementation: implementation.name, sha256: hash(implementation.code), input, capabilities, outcome, state, cleanup, hlsManifest: input === 'hls' ? manifest : null, tracklessFixture: input === 'trackless' ? { parentSha256: hash(pattern), sha256: hash(trackless) } : null, scope: 'Actual published proxy with native browser media and controlled ArtPlayer host using actual core utilities/config; frame timestamps sampled against the SDK audio clock, not acoustic/long-run AV-sync acceptance. Cleanup checks settled playback, not pending-operation races.' }) }) + } + }) + } +} diff --git a/test/helpers/trackless-mp4.js b/test/helpers/trackless-mp4.js new file mode 100644 index 000000000..0ea02cbc4 --- /dev/null +++ b/test/helpers/trackless-mp4.js @@ -0,0 +1,29 @@ +import assert from 'node:assert/strict' +import { Buffer } from 'node:buffer' + +// Derive a trackless container from the small, repository-owned MP4 fixture. +export function tracklessMp4(bytes) { + function boxes(bytes) { + const result = [] + let offset = 0 + while (offset < bytes.length) { + assert(offset + 8 <= bytes.length) + const size = bytes.readUInt32BE(offset) + assert(size >= 8 && offset + size <= bytes.length, 'Fixture requires bounded 32-bit boxes') + result.push({ type: bytes.toString('ascii', offset + 4, offset + 8), bytes: bytes.subarray(offset, offset + size) }) + offset += size + } + return result + } + const top = boxes(bytes) + const ftyp = top.find(box => box.type === 'ftyp') + const moov = top.find(box => box.type === 'moov') + assert(ftyp && moov) + const children = boxes(moov.bytes.subarray(8)) + assert(children.some(box => box.type === 'trak')) + const body = Buffer.concat(children.filter(box => box.type !== 'trak').map(box => box.bytes)) + const header = Buffer.alloc(8) + header.writeUInt32BE(body.length + 8) + header.write('moov', 4) + return Buffer.concat([ftyp.bytes, header, body]) +} diff --git a/test/mediabunny.test.js b/test/mediabunny.test.js index 0cdde8907..6c087ecc5 100644 --- a/test/mediabunny.test.js +++ b/test/mediabunny.test.js @@ -3,6 +3,32 @@ import assert from 'node:assert/strict' import test from 'node:test' import { mbEnvironment, mbHistorical } from './helpers/mediabunny.js' +function deferred() { + let resolve + let reject + const promise = new Promise((yes, no) => { + resolve = yes + reject = no + }) + return { promise, resolve, reject } +} + +function timedEnvironment(implementation, option) { + const timers = new Map() + let sequence = 0 + const env = mbEnvironment(implementation, { + setTimeout(fn, delay) { + const id = sequence++ + timers.set(id, { fn, delay }) + return id + }, + clearTimeout(id) { timers.delete(id) }, + }) + env.eventNames.push('playing') + const canvas = env.factory(option)(env.art) + return { ...env, canvas, engine: canvas.engine, timers } +} + for (const implementation of await mbHistorical()) { test(`MediaBunny historical ${implementation.name}: destroy still permits late load errors and scheduled events`, async () => { const timers = new Map() @@ -40,4 +66,137 @@ for (const implementation of await mbHistorical()) { assert.deepEqual({ ...engine.error }, { code: 4, message: 'late controlled rejection' }) assert.equal(engine.networkState, 3) }) + + test(`MediaBunny historical ${implementation.name}: pending play starts video after a newer pause`, async () => { + const { engine, emitted } = timedEnvironment(implementation) + const audio = deferred() + let starts = 0 + engine.audio.play = () => audio.promise + engine.video.start = () => starts++ + const playing = engine.play() + assert.equal(engine.paused, false) + engine.pause() + audio.resolve() + await playing + assert.equal(engine.paused, true) + assert.equal(starts, 1) + assert.deepEqual(emitted.map(item => item.name), ['video:pause', 'video:play', 'video:playing']) + }) + + test(`MediaBunny historical ${implementation.name}: pending play starts video after destroy`, async () => { + const { art, engine, emitted } = timedEnvironment(implementation) + const audio = deferred() + let starts = 0 + engine.audio.play = () => audio.promise + engine.video.start = () => starts++ + const playing = engine.play() + art.emit('destroy') + const cursor = emitted.length + audio.resolve() + await playing + assert.equal(starts, 1) + assert.deepEqual(emitted.slice(cursor).map(item => item.name), ['video:play', 'video:playing']) + assert.equal(engine.paused, true) + }) + + test(`MediaBunny historical ${implementation.name}: rejected audio play leaves false paused state and prevents retry`, async () => { + const { engine } = timedEnvironment(implementation) + const error = new Error('controlled audio resume rejection') + let attempts = 0 + engine.audio.play = () => { + attempts++ + return Promise.reject(error) + } + await assert.rejects(engine.play(), item => item === error) + assert.equal(engine.paused, false) + await engine.play() + assert.equal(attempts, 1) + }) + + test(`MediaBunny historical ${implementation.name}: pending seek emits and resumes playback after destroy`, async () => { + const { art, engine, canvas } = timedEnvironment(implementation) + const audio = deferred() + const events = [] + for (const name of ['seeking', 'waiting', 'pause', 'seeked']) + canvas.events.addEventListener(name, () => events.push(name)) + engine.paused = false + engine.audio.seek = () => audio.promise + engine.video.seek = () => Promise.resolve() + engine.play = () => { + events.push('resumed-after-destroy') + return Promise.resolve() + } + const seeking = engine.seek(1) + art.emit('destroy') + audio.resolve() + await seeking + assert.deepEqual(events, ['seeking', 'waiting', 'pause', 'seeked', 'resumed-after-destroy']) + assert.equal(engine.seeking, false) + }) + + test(`MediaBunny historical ${implementation.name}: successful load and destroy retain their timeout timer`, async () => { + const { art, engine, timers } = timedEnvironment(implementation, { loadTimeout: 1234 }) + engine.performLoad = () => Promise.resolve() + await engine.load('controlled-input') + assert.equal(timers.size, 3) + assert.equal([...timers.values()].filter(item => item.delay === 1234).length, 1) + art.emit('destroy') + assert.equal(timers.size, 3) + for (const { fn } of timers.values()) fn() + timers.clear() + await Promise.resolve() + assert.equal(engine.error, null, 'Settled Promise.race observes the late timeout rejection without changing the successful result') + }) + + test(`MediaBunny historical ${implementation.name}: active timeout keeps its error when the underlying load rejects later`, async () => { + const { engine, timers } = timedEnvironment(implementation, { loadTimeout: 5678 }) + const pending = deferred() + engine.performLoad = () => pending.promise + const loading = engine.load('controlled-input') + const timeout = [...timers.values()].find(item => item.delay === 5678) + timeout.fn() + await loading + assert.deepEqual({ ...engine.error }, { code: 4, message: 'Load timeout' }) + const error = engine.error + pending.reject(new Error('late underlying rejection')) + await Promise.resolve() + await Promise.resolve() + assert.equal(engine.error, error) + timers.clear() + }) + + test(`MediaBunny historical ${implementation.name}: Range preflight rejects absent support, tolerates fetch errors and keeps its HLS version boundary`, async () => { + const { engine, canvas, globals } = timedEnvironment(implementation, { preflightRange: true }) + const calls = [] + const errors = [] + const warnings = [] + canvas.events.addEventListener('error', event => errors.push(event.detail.type)) + globals.console = { ...console, warn: (...args) => warnings.push(args) } + globals.fetch = async (url, options) => { + calls.push({ url, options: { ...options } }) + return { headers: { get: () => 'bytes' } } + } + assert.equal(await engine.video.preflight('https://example.invalid/media.mp4'), true) + assert.deepEqual(calls, [{ url: 'https://example.invalid/media.mp4', options: { method: 'HEAD' } }]) + globals.fetch = async () => ({ headers: { get: () => null } }) + assert.equal(await engine.video.preflight('https://example.invalid/media.mp4'), false) + assert.deepEqual(errors, ['RangeNotSupported']) + assert.equal(engine.error, null, 'Range refusal is an event, not engine.error state') + const failure = new Error('controlled HEAD rejection') + globals.fetch = async () => { + throw failure + } + assert.equal(await engine.video.preflight('https://example.invalid/media.mp4'), true) + assert.equal(warnings.length, 1) + assert.equal(warnings[0][1], failure) + let requests = 0 + globals.fetch = async () => { + requests++ + return { headers: { get: () => 'bytes' } } + } + assert.equal(await engine.video.preflight('https://example.invalid/media.m3u8'), true) + assert.equal(requests, implementation.name === 'published-1.0.0' ? 1 : 0) + assert.equal(await engine.video.preflight(new Blob([])), true) + assert.equal(requests, implementation.name === 'published-1.0.0' ? 1 : 0) + }) }