diff --git a/images/chromium-headful/client/src/components/video.vue b/images/chromium-headful/client/src/components/video.vue index fda512fa..a2a739db 100644 --- a/images/chromium-headful/client/src/components/video.vue +++ b/images/chromium-headful/client/src/components/video.vue @@ -260,6 +260,7 @@ private focused = false private fullscreen = false private mutedOverlay = true + private isVideoSyncing = false get admin() { return this.$accessor.user.admin @@ -431,6 +432,10 @@ @Watch('playing') async onPlayingChanged(playing: boolean) { + // In Safari, native events can fire slightly before the `video.paused` property flips. + // This anti-echo guard prevents the watcher from fighting the video element's own state changes. + if (this.isVideoSyncing) return; + if (this._video && this._video.paused && playing) { // if autoplay is disabled, play() will throw an error // and we need to properly save the state otherwise we @@ -511,11 +516,15 @@ }) this._video.addEventListener('playing', () => { + this.isVideoSyncing = true this.$accessor.video.play() + this.$nextTick(() => { this.isVideoSyncing = false }) }) this._video.addEventListener('pause', () => { + this.isVideoSyncing = true this.$accessor.video.pause() + this.$nextTick(() => { this.isVideoSyncing = false }) }) /* Initialize Guacamole Keyboard */