Expose the compatibility path's actual one-slot pending-image queue to diagnostics and adaptive feedback while retaining the WebCodecs two-slot contract. Cover pending, overwrite, load, error, reset, and feedback projection transitions.
- commit
- 76ec14f51f05fd48e3e01c656915c1a18f1dcd8e
- parent
- a57de273beda3658070338713a18994ba7d97ccb
- author
- Dami <dami.etoile@gmail.com>
| M | portal/ | 27 | +++++++++++++++++++++++++++ |
| M | portal/ | 9 | +++++++-- |
| M | portal/ | 18 | +++++++++++++++++- |
@@ -335,3 +335,30 @@ test('adaptive feedback preserves bounded queue fallbacks and pressure signals',
335335 resyncActive: true,336336 });337337 });338+339+test('adaptive feedback projects the JPEG one-slot queue and overwrite counter', () => {340+ const { runtime, events } = subject();341+ runtime.prepareConnection();342+ const session = runtime.openFrameSession();343+ activate(runtime, session, 6);344+ events.length = 0;345+346+ assert.equal(runtime.publishAdaptiveFeedback(videoSnapshot({347+ presenterQueueDepth: 1,348+ presenterQueueCapacity: 1,349+ presentationDroppedFrames: 3,350+ })), true);351+ assert.equal(events[0].snapshot.presenterQueueDepth, 1);352+ assert.equal(events[0].snapshot.presenterQueueCapacity, 1);353+ assert.equal(events[0].snapshot.presenterDroppedTotal, 3);354+355+ events.length = 0;356+ assert.equal(runtime.publishAdaptiveFeedback(videoSnapshot({357+ presenterQueueDepth: 0,358+ presenterQueueCapacity: 1,359+ presentationDroppedFrames: 3,360+ })), true);361+ assert.equal(events[0].snapshot.presenterQueueDepth, 0);362+ assert.equal(events[0].snapshot.presenterQueueCapacity, 1);363+ assert.equal(events[0].snapshot.presenterDroppedTotal, 3);364+});@@ -23,6 +23,7 @@ import {
2323 export const MAX_DECODE_QUEUE_SIZE = 2;2424 const MAX_DECODE_TIMINGS = 8;2525 const PRESENTER_QUEUE_CAPACITY = 2;26+const JPEG_PRESENTER_QUEUE_CAPACITY = 1;2627 2728 export function createVideoPipelineSession({2829 hasWebCodecs,@@ -484,8 +485,12 @@ export function createVideoPipelineSession({
484485 avSkewPercentiles: avSkew.summary(at),485486 decoderQueueDepth: videoDecoder?.decodeQueueSize ?? 0,486487 decoderQueueCapacity: MAX_DECODE_QUEUE_SIZE,487- presenterQueueDepth: framePresenter.depth,488- presenterQueueCapacity: PRESENTER_QUEUE_CAPACITY,488+ presenterQueueDepth: hasWebCodecs489+ ? framePresenter.depth490+ : Number(pendingJpegFrame !== null),491+ presenterQueueCapacity: hasWebCodecs492+ ? PRESENTER_QUEUE_CAPACITY493+ : JPEG_PRESENTER_QUEUE_CAPACITY,489494 recovering: decoderRecovery.recovering,490495 };491496 }@@ -136,6 +136,8 @@ test('configured H.264 keyframes commit format only after decode enqueue', () =>
136136 assert.equal(stats.droppedFrames, 0);137137 assert.equal(stats.recovering, false);138138 assert.equal(stats.decoderQueueCapacity, MAX_DECODE_QUEUE_SIZE);139+ assert.equal(stats.presenterQueueDepth, 0);140+ assert.equal(stats.presenterQueueCapacity, 2);139141 });140142 141143 test('unsupported codecs are dropped before decoder construction', () => {@@ -222,12 +224,16 @@ test('JPEG fallback keeps its asynchronous base64 draw behavior', () => {
222224 assert.equal(subject.images[0].src, 'blob:test-frame-1');223225 assert.deepEqual(subject.draws, []);224226 assert.deepEqual(subject.revokedUrls, []);227+ assert.equal(subject.pipeline.snapshot().presenterQueueDepth, 1);228+ assert.equal(subject.pipeline.snapshot().presenterQueueCapacity, 1);225229 226230 subject.advance();227231 subject.images[0].onload();228232 assert.equal(subject.draws.length, 1);229233 assert.deepEqual(subject.revokedUrls, ['blob:test-frame-1']);230234 assert.equal(subject.pipeline.snapshot().presentedFrames, 1);235+ assert.equal(subject.pipeline.snapshot().presenterQueueDepth, 0);236+ assert.equal(subject.pipeline.snapshot().presenterQueueCapacity, 1);231237 });232238 233239 test('JPEG fallback presents only the newest frame when loads complete out of order', () => {@@ -246,7 +252,10 @@ test('JPEG fallback presents only the newest frame when loads complete out of or
246252 subject.pipeline.processFramePayload(payload);247253 const newestLoad = subject.images[1].onload;248254 assert.deepEqual(subject.revokedUrls, ['blob:test-frame-1']);249- assert.equal(subject.pipeline.snapshot().presentationDroppedFrames, 1);255+ const afterOverwrite = subject.pipeline.snapshot();256+ assert.equal(afterOverwrite.presentationDroppedFrames, 1);257+ assert.equal(afterOverwrite.presenterQueueDepth, 1);258+ assert.equal(afterOverwrite.presenterQueueCapacity, 1);250259 251260 subject.advance(5);252261 newestLoad();@@ -256,6 +265,8 @@ test('JPEG fallback presents only the newest frame when loads complete out of or
256265 assert.equal(afterNewest.presentPercentiles.count, 1);257266 assert.equal(afterNewest.presentPercentiles.p50, 5);258267 assert.equal(afterNewest.presentationDroppedFrames, 1);268+ assert.equal(afterNewest.presenterQueueDepth, 0);269+ assert.equal(afterNewest.presenterQueueCapacity, 1);259270 260271 subject.advance(100);261272 staleLoad();@@ -294,6 +305,9 @@ test('JPEG fallback error callbacks affect only the current pending frame', () =
294305 const afterFailure = subject.pipeline.snapshot();295306 assert.equal(afterFailure.droppedFrames, 1);296307 assert.equal(afterFailure.presentedFrames, 0);308+ assert.equal(afterFailure.presentationDroppedFrames, 1);309+ assert.equal(afterFailure.presenterQueueDepth, 0);310+ assert.equal(afterFailure.presenterQueueCapacity, 1);297311 assert.deepEqual(subject.draws, []);298312 assert.deepEqual(subject.revokedUrls, [299313 'blob:test-frame-1',@@ -322,6 +336,8 @@ test('JPEG fallback callbacks cannot survive a session reset', () => {
322336 assert.equal(stats.presentedFrames, 0);323337 assert.equal(stats.droppedFrames, 0);324338 assert.equal(stats.presentPercentiles.count, 0);339+ assert.equal(stats.presenterQueueDepth, 0);340+ assert.equal(stats.presenterQueueCapacity, 1);325341 assert.deepEqual(subject.draws, []);326342 assert.deepEqual(subject.revokedUrls, ['blob:test-frame-1']);327343 });