From 7a58335cbd68176b0f7cd4672d3f62048fe05e25 Mon Sep 17 00:00:00 2001 From: masnwilliams <43387599+masnwilliams@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:41:08 +0000 Subject: [PATCH] Stop reloading the live view video on every interaction in Safari --- .../client/src/utils/video-resume.ts | 7 ++++++- .../client/tests/video-resume.test.ts | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/images/chromium-headful/client/src/utils/video-resume.ts b/images/chromium-headful/client/src/utils/video-resume.ts index 510b7bcc..ec886b89 100644 --- a/images/chromium-headful/client/src/utils/video-resume.ts +++ b/images/chromium-headful/client/src/utils/video-resume.ts @@ -3,7 +3,9 @@ // tab can come back from the background paused. Input still reaches the remote // over the data channel meanwhile, so the picture just stays on its last frame. // A video that is not paused but has decoded no frame since a check at least -// STALL_MS earlier is reloaded from its stream. +// STALL_MS earlier is reloaded from its stream. Safari reports no frames for a +// MediaStream (totalVideoFrames stays 0), so a counter that has never reported +// a frame says nothing about a stall. export const STALL_MS = 1000 @@ -19,6 +21,7 @@ export interface ResumableVideo { export class VideoResume { private progress = NaN private progressAt = -Infinity + private counting = false constructor( private video: ResumableVideo, @@ -59,6 +62,8 @@ export class VideoResume { ? video.getVideoPlaybackQuality().totalVideoFrames : video.currentTime const at = this.now() + if (progress > 0) this.counting = true + if (!this.counting) return false if (video.paused || progress !== this.progress) { this.progress = progress this.progressAt = at diff --git a/images/chromium-headful/client/tests/video-resume.test.ts b/images/chromium-headful/client/tests/video-resume.test.ts index 5f75c4b8..60d98874 100644 --- a/images/chromium-headful/client/tests/video-resume.test.ts +++ b/images/chromium-headful/client/tests/video-resume.test.ts @@ -109,6 +109,19 @@ describe('video resume', () => { expect(calls).toEqual(['blocked false']) }) + test('leaves a video alone whose browser counts no frames', async () => { + // Safari reports no frames for a MediaStream + const video = chromeVideo() + video.frames = 0 + const { resume, calls, tick } = resumer(video) + for (let i = 0; i < 3; i++) { + await resume.resume() + tick(STALL_MS) + } + expect(video.loads).toBe(0) + expect(calls).toEqual([]) + }) + test('does nothing without a stream', async () => { const video = chromeVideo() video.srcObject = null