From a3465030d09bc13e2d71a63ad16a4879a9b4d257 Mon Sep 17 00:00:00 2001
From: stefpi <19478336+stefpi@users.noreply.github.com>
Date: Wed, 15 Apr 2026 13:50:34 -0700
Subject: [PATCH 1/5] testing html
---
video-test.html | 892 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 892 insertions(+)
create mode 100644 video-test.html
diff --git a/video-test.html b/video-test.html
new file mode 100644
index 00000000..be913597
--- /dev/null
+++ b/video-test.html
@@ -0,0 +1,892 @@
+
+
+
+
+
+
Drive Video Seek Lab
+
+ Paste a signed qcamera HLS URL and test seek behavior with smaller buffers, coalesced rapid scrubs,
+ and seek timing instrumentation. The goal is to see whether these changes reduce lag before we touch app code.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Current Stats
+ Load a route to populate stats.
+
+
+
+ Last Seek
+ No seek recorded yet.
+
+
+
+ Event Log
+ No events yet.
+
+
+
+
+
+
+
From e55a62c44074f3ed716d5788b96ff515c20be512 Mon Sep 17 00:00:00 2001
From: stefpi <19478336+stefpi@users.noreply.github.com>
Date: Wed, 15 Apr 2026 19:41:17 -0700
Subject: [PATCH 2/5] run sync video on timeupdate
---
src/components/DriveVideo/index.jsx | 42 +-
video-test.html | 892 ----------------------------
2 files changed, 33 insertions(+), 901 deletions(-)
delete mode 100644 video-test.html
diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx
index b35f95b7..9d4083b6 100644
--- a/src/components/DriveVideo/index.jsx
+++ b/src/components/DriveVideo/index.jsx
@@ -64,10 +64,11 @@ class DriveVideo extends Component {
this.onHlsError = this.onHlsError.bind(this);
this.onVideoError = this.onVideoError.bind(this);
this.onVideoResume = this.onVideoResume.bind(this);
- this.syncVideo = debounce(this.syncVideo.bind(this), 200, true);
+ this.syncVideo = this.syncVideo.bind(this);
this.firstSeek = true;
this.videoPlayer = React.createRef();
+ this.internalPlayer = null;
this.state = {
src: null,
@@ -82,7 +83,6 @@ class DriveVideo extends Component {
}
this.updateVideoSource({});
this.syncVideo();
- this.videoSyncIntv = setInterval(this.syncVideo, 500);
}
componentDidUpdate(prevProps) {
@@ -91,9 +91,10 @@ class DriveVideo extends Component {
}
componentWillUnmount() {
- if (this.videoSyncIntv) {
- clearTimeout(this.videoSyncIntv);
- this.videoSyncIntv = null;
+ if (this.internalPlayer) {
+ this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
+ this.internalPlayer.removeEventListener('seeked', this.syncVideo);
+ this.internalPlayer.removeEventListener('canplay', this.syncVideo);
}
}
@@ -179,8 +180,12 @@ class DriveVideo extends Component {
}
onVideoResume() {
+ const { dispatch, isBufferingVideo } = this.props;
const { videoError } = this.state;
if (videoError) this.setState({ videoError: null });
+ if (isBufferingVideo) {
+ dispatch(bufferVideo(false));
+ }
}
updateVideoSource(prevProps) {
@@ -194,6 +199,12 @@ class DriveVideo extends Component {
}
if (src === '' || !prevProps.currentRoute || prevProps.currentRoute?.fullname !== currentRoute.fullname) {
+ if (this.internalPlayer) {
+ this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
+ this.internalPlayer.removeEventListener('seeked', this.syncVideo);
+ this.internalPlayer.removeEventListener('canplay', this.syncVideo);
+ this.internalPlayer = null;
+ }
src = Video.getQcameraStreamUrl(currentRoute.fullname, currentRoute.share_exp, currentRoute.share_sig);
this.setState({ src, videoError: null });
this.syncVideo();
@@ -201,6 +212,7 @@ class DriveVideo extends Component {
}
syncVideo() {
+ console.log("sync da video")
const { dispatch, isBufferingVideo, isMuted } = this.props;
const videoPlayer = this.videoPlayer.current;
if (!videoPlayer || !videoPlayer.getInternalPlayer() || !videoPlayer.getDuration()) {
@@ -228,12 +240,12 @@ class DriveVideo extends Component {
const internalPlayer = videoPlayer.getInternalPlayer();
const { hasLoaded } = getVideoState(videoPlayer);
- if (isBufferingVideo && internalPlayer.readyState >= 4) {
+ if (internalPlayer.readyState >= 4 && isBufferingVideo) {
dispatch(bufferVideo(false));
- } else if (isBufferingVideo || !hasLoaded || internalPlayer.readyState < 2) {
+ } else if (internalPlayer.readyState < 2) {
if (!isBufferingVideo) {
dispatch(bufferVideo(true));
- }
+ }
newPlaybackRate = 0; // in some circumstances, iOS won't update readyState unless temporarily paused
}
@@ -275,8 +287,20 @@ class DriveVideo extends Component {
const { src, videoError } = this.state;
const onPlayerReady = (player) => {
+ const videoElement = player.getInternalPlayer();
+ if (videoElement) {
+ if (this.internalPlayer) {
+ this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
+ this.internalPlayer.removeEventListener('seeked', this.syncVideo);
+ this.internalPlayer.removeEventListener('canplay', this.syncVideo);
+ }
+ this.internalPlayer = videoElement;
+ videoElement.addEventListener('timeupdate', this.syncVideo);
+ videoElement.addEventListener('seeked', this.syncVideo);
+ videoElement.addEventListener('canplay', this.syncVideo);
+ }
+
if (isIos()) { // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible
- const videoElement = player.getInternalPlayer();
if (videoElement && videoElement.audioTracks && videoElement.audioTracks.length > 0) {
if (onAudioStatusChange) {
onAudioStatusChange(true);
diff --git a/video-test.html b/video-test.html
deleted file mode 100644
index be913597..00000000
--- a/video-test.html
+++ /dev/null
@@ -1,892 +0,0 @@
-
-
-
-
-
-
Drive Video Seek Lab
-
- Paste a signed qcamera HLS URL and test seek behavior with smaller buffers, coalesced rapid scrubs,
- and seek timing instrumentation. The goal is to see whether these changes reduce lag before we touch app code.
-
-
-
-
-
-
-
-
-
-
-
-
-
- Current Stats
- Load a route to populate stats.
-
-
-
- Last Seek
- No seek recorded yet.
-
-
-
- Event Log
- No events yet.
-
-
-
-
-
-
-
From 81a92fb25e50ff304059423ed6f4b38f7adfed37 Mon Sep 17 00:00:00 2001
From: stefpi <19478336+stefpi@users.noreply.github.com>
Date: Wed, 15 Apr 2026 20:07:53 -0700
Subject: [PATCH 3/5] remove canplay eventlistener
---
src/components/DriveVideo/index.jsx | 5 -----
1 file changed, 5 deletions(-)
diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx
index 9d4083b6..2d9dd975 100644
--- a/src/components/DriveVideo/index.jsx
+++ b/src/components/DriveVideo/index.jsx
@@ -94,7 +94,6 @@ class DriveVideo extends Component {
if (this.internalPlayer) {
this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
this.internalPlayer.removeEventListener('seeked', this.syncVideo);
- this.internalPlayer.removeEventListener('canplay', this.syncVideo);
}
}
@@ -202,7 +201,6 @@ class DriveVideo extends Component {
if (this.internalPlayer) {
this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
this.internalPlayer.removeEventListener('seeked', this.syncVideo);
- this.internalPlayer.removeEventListener('canplay', this.syncVideo);
this.internalPlayer = null;
}
src = Video.getQcameraStreamUrl(currentRoute.fullname, currentRoute.share_exp, currentRoute.share_sig);
@@ -212,7 +210,6 @@ class DriveVideo extends Component {
}
syncVideo() {
- console.log("sync da video")
const { dispatch, isBufferingVideo, isMuted } = this.props;
const videoPlayer = this.videoPlayer.current;
if (!videoPlayer || !videoPlayer.getInternalPlayer() || !videoPlayer.getDuration()) {
@@ -292,12 +289,10 @@ class DriveVideo extends Component {
if (this.internalPlayer) {
this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
this.internalPlayer.removeEventListener('seeked', this.syncVideo);
- this.internalPlayer.removeEventListener('canplay', this.syncVideo);
}
this.internalPlayer = videoElement;
videoElement.addEventListener('timeupdate', this.syncVideo);
videoElement.addEventListener('seeked', this.syncVideo);
- videoElement.addEventListener('canplay', this.syncVideo);
}
if (isIos()) { // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible
From 409a0a7924ae116cfeba86ac5a8c5fc6405985cd Mon Sep 17 00:00:00 2001
From: stefpi <19478336+stefpi@users.noreply.github.com>
Date: Wed, 15 Apr 2026 20:16:55 -0700
Subject: [PATCH 4/5] fix linter
---
src/components/DriveVideo/index.jsx | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx
index 2d9dd975..a974b195 100644
--- a/src/components/DriveVideo/index.jsx
+++ b/src/components/DriveVideo/index.jsx
@@ -2,7 +2,6 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { CircularProgress, Typography } from '@material-ui/core';
-import debounce from 'debounce';
import Obstruction from 'obstruction';
import ReactPlayer from 'react-player/file';
@@ -236,7 +235,6 @@ class DriveVideo extends Component {
const internalPlayer = videoPlayer.getInternalPlayer();
- const { hasLoaded } = getVideoState(videoPlayer);
if (internalPlayer.readyState >= 4 && isBufferingVideo) {
dispatch(bufferVideo(false));
} else if (internalPlayer.readyState < 2) {
From 685f6f2a3561dec1f0767e5c5f43307779f28602 Mon Sep 17 00:00:00 2001
From: stefpi <19478336+stefpi@users.noreply.github.com>
Date: Wed, 15 Apr 2026 20:42:53 -0700
Subject: [PATCH 5/5] add back canplay listener, lower ready state check
---
src/components/DriveVideo/index.jsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/components/DriveVideo/index.jsx b/src/components/DriveVideo/index.jsx
index a974b195..5334763e 100644
--- a/src/components/DriveVideo/index.jsx
+++ b/src/components/DriveVideo/index.jsx
@@ -93,6 +93,7 @@ class DriveVideo extends Component {
if (this.internalPlayer) {
this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
this.internalPlayer.removeEventListener('seeked', this.syncVideo);
+ this.internalPlayer.removeEventListener('canplay', this.syncVideo);
}
}
@@ -200,6 +201,7 @@ class DriveVideo extends Component {
if (this.internalPlayer) {
this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
this.internalPlayer.removeEventListener('seeked', this.syncVideo);
+ this.internalPlayer.removeEventListener('canplay', this.syncVideo);
this.internalPlayer = null;
}
src = Video.getQcameraStreamUrl(currentRoute.fullname, currentRoute.share_exp, currentRoute.share_sig);
@@ -235,7 +237,7 @@ class DriveVideo extends Component {
const internalPlayer = videoPlayer.getInternalPlayer();
- if (internalPlayer.readyState >= 4 && isBufferingVideo) {
+ if (internalPlayer.readyState >= 3 && isBufferingVideo) {
dispatch(bufferVideo(false));
} else if (internalPlayer.readyState < 2) {
if (!isBufferingVideo) {
@@ -287,10 +289,12 @@ class DriveVideo extends Component {
if (this.internalPlayer) {
this.internalPlayer.removeEventListener('timeupdate', this.syncVideo);
this.internalPlayer.removeEventListener('seeked', this.syncVideo);
+ this.internalPlayer.removeEventListener('canplay', this.syncVideo);
}
this.internalPlayer = videoElement;
videoElement.addEventListener('timeupdate', this.syncVideo);
videoElement.addEventListener('seeked', this.syncVideo);
+ videoElement.addEventListener('canplay', this.syncVideo);
}
if (isIos()) { // ios does not support hls.js and on other browsers hls.js does not directly play the m3u8 so audioTracks are not visible