zebra-spaces: 120s mute window for screen + game (static content), 15s stays for camera
Screen shares and game shares can sit static for long stretches — a still desktop, a paused video, a code editor with no caret movement. The encoder genuinely stops emitting RTP, the subscriber's track goes muted, and the 15s camera window would falsely reap the live tile. watchVideoTrackForRemoval now takes a per-call windowMs; the sub-PC ontrack handler passes VIDEO_REMOVE_MUTE_WINDOW_SCREEN_MS (120s) for screen + game and VIDEO_REMOVE_MUTE_WINDOW_MS (15s) for camera. A genuine unshare still resolves through the 'ended' path within a frame, so the longer window only affects the slow-failure case. Tests bumped to 18: new screen-window assertions + invalid-windowMs fallback to the default rather than disabling removal entirely.
This commit is contained in:
parent
9419a415bf
commit
0878996e96
2 changed files with 78 additions and 21 deletions
|
|
@ -40,13 +40,17 @@ function extract(re){
|
|||
|
||||
const watchSrc = extract(/function watchVideoTrackForRemoval\(/);
|
||||
|
||||
/* The shipped constant. Read it from source so the test always validates
|
||||
* what's actually live — if the window changes the assertion below
|
||||
* catches an accidental shorten. */
|
||||
/* Shipped constants. Read from source so the tests always validate
|
||||
* what's actually live — if either window changes the assertions below
|
||||
* catch an accidental shorten. */
|
||||
const winM = src.match(/const\s+VIDEO_REMOVE_MUTE_WINDOW_MS\s*=\s*(\d+)\s*;/);
|
||||
if (!winM) throw new Error('VIDEO_REMOVE_MUTE_WINDOW_MS not found in source');
|
||||
const SHIPPED_WINDOW_MS = parseInt(winM[1], 10);
|
||||
|
||||
const winScreenM = src.match(/const\s+VIDEO_REMOVE_MUTE_WINDOW_SCREEN_MS\s*=\s*(\d+)\s*;/);
|
||||
if (!winScreenM) throw new Error('VIDEO_REMOVE_MUTE_WINDOW_SCREEN_MS not found in source');
|
||||
const SHIPPED_WINDOW_SCREEN_MS = parseInt(winScreenM[1], 10);
|
||||
|
||||
/* ============================ fake clock ============================ */
|
||||
let fakeNow = 0;
|
||||
let pending = new Map(); // id -> { fireAt, fn }
|
||||
|
|
@ -82,11 +86,13 @@ function resetLogs(){ logs = []; }
|
|||
/* harness — Function-constructor scope so the function's free
|
||||
* references resolve to our fakes, not the host's real globals. */
|
||||
const harness = new Function(
|
||||
'setTimeout', 'clearTimeout', 'logLine', 'VIDEO_REMOVE_MUTE_WINDOW_MS',
|
||||
'setTimeout', 'clearTimeout', 'logLine',
|
||||
'VIDEO_REMOVE_MUTE_WINDOW_MS', 'VIDEO_REMOVE_MUTE_WINDOW_SCREEN_MS',
|
||||
watchSrc + '\nreturn watchVideoTrackForRemoval;'
|
||||
);
|
||||
const watchVideoTrackForRemoval = harness(
|
||||
fakeSetTimeout, fakeClearTimeout, logLine, SHIPPED_WINDOW_MS,
|
||||
fakeSetTimeout, fakeClearTimeout, logLine,
|
||||
SHIPPED_WINDOW_MS, SHIPPED_WINDOW_SCREEN_MS,
|
||||
);
|
||||
|
||||
/* ============================ fake track ============================ */
|
||||
|
|
@ -127,6 +133,41 @@ test('shipped mute-window is at least 10s — anything less is too aggressive',
|
|||
truthy(SHIPPED_WINDOW_MS >= 10000, 'window ' + SHIPPED_WINDOW_MS + ' < 10000');
|
||||
});
|
||||
|
||||
test('shipped screen-window is at least 60s — static screens stay quiet', () => {
|
||||
truthy(SHIPPED_WINDOW_SCREEN_MS >= 60000,
|
||||
'screen window ' + SHIPPED_WINDOW_SCREEN_MS + ' < 60000');
|
||||
truthy(SHIPPED_WINDOW_SCREEN_MS > SHIPPED_WINDOW_MS,
|
||||
'screen window must be longer than camera window');
|
||||
});
|
||||
|
||||
test('callers can override the window per-kind (screen window honored)', () => {
|
||||
const t = makeTrack();
|
||||
let removed = 0;
|
||||
watchVideoTrackForRemoval(t, () => removed++, SHIPPED_WINDOW_SCREEN_MS);
|
||||
t.setMuted(false); t.fire('unmute');
|
||||
t.setMuted(true); t.fire('mute');
|
||||
/* the camera window has passed — but we passed the screen window, so
|
||||
* the tile must survive */
|
||||
advance(SHIPPED_WINDOW_MS + 1000);
|
||||
eq(removed, 0, 'camera-window elapsed but screen-window in effect — must not remove');
|
||||
/* still inside the screen window */
|
||||
advance(SHIPPED_WINDOW_SCREEN_MS - SHIPPED_WINDOW_MS - 2000);
|
||||
eq(removed, 0, 'still inside screen window');
|
||||
/* now we cross the screen window */
|
||||
advance(2000);
|
||||
eq(removed, 1, 'screen window elapsed — removed');
|
||||
});
|
||||
|
||||
test('invalid window argument falls back to camera default', () => {
|
||||
const t = makeTrack();
|
||||
let removed = 0;
|
||||
watchVideoTrackForRemoval(t, () => removed++, 'not a number');
|
||||
t.setMuted(false); t.fire('unmute');
|
||||
t.setMuted(true); t.fire('mute');
|
||||
advance(SHIPPED_WINDOW_MS + 100);
|
||||
eq(removed, 1, 'bad windowMs should fall back to default, not disable removal');
|
||||
});
|
||||
|
||||
test('initial mute (never flowed) does NOT schedule a removal', () => {
|
||||
const t = makeTrack();
|
||||
let removed = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue