Skip to content

Commit bc5e9fc

Browse files
pliablepixelsclaude
andcommitted
fix(events): scrub with seek alone, no pause/play wrapper
Each scrub gesture sent CMD_PAUSE on grab and CMD_PLAY on release around the CMD_SEEK. Those three unordered requests raced and were unnecessary: ZMS handles a seek without bracketing it, so a single CMD_SEEK per position is enough. Drop the pause/resume; the scrub-start/end handlers now only gate the status poll so it does not overwrite the playhead mid-drag. refs #196 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7d4e5c9 commit bc5e9fc

2 files changed

Lines changed: 16 additions & 17 deletions

File tree

app/src/components/events/ZmsEventPlayer.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,8 @@ export function ZmsEventPlayer({
7979

8080
// While the user drags the scrub bar, the status poll must not write the
8181
// playhead back from the stream: that fight makes the cursor and video jump
82-
// around mid-drag (refs #196). The grab also pauses the stream so it does not
83-
// play forward between seeks. wasPlayingRef remembers whether to resume.
82+
// around mid-drag (refs #196). Each scrub position is sent as a CMD_SEEK.
8483
const isScrubbingRef = useRef(false);
85-
const wasPlayingRef = useRef(false);
8684

8785
// Unique connection key for this stream, stable for the component's lifetime.
8886
// Speed changes are sent as CMD_VARPLAY over this same connkey instead of
@@ -323,19 +321,17 @@ export function ZmsEventPlayer({
323321
goToFrame(totalFrames);
324322
}, [goToFrame, totalFrames]);
325323

326-
// Grab the scrub bar: pause the stream so it shows a single still frame per
327-
// seek instead of playing forward between drags, and silence the status poll.
324+
// Grab the scrub bar: just silence the status poll so it does not write the
325+
// playhead back mid-drag. Each scrub position is a CMD_SEEK; ZMS handles the
326+
// seek without a surrounding pause/play, so we do not send them (refs #196).
328327
const handleScrubStart = useCallback(() => {
329328
isScrubbingRef.current = true;
330-
wasPlayingRef.current = isPlaying;
331-
if (isPlaying) sendCommand(ZMS_COMMANDS.cmdPause);
332-
}, [isPlaying, sendCommand]);
329+
}, []);
333330

334-
// Release: resume playback only if it was playing when the drag began.
331+
// Release: re-enable the status poll. Playback state is unchanged by scrubbing.
335332
const handleScrubEnd = useCallback(() => {
336333
isScrubbingRef.current = false;
337-
if (wasPlayingRef.current) sendCommand(ZMS_COMMANDS.cmdPlay);
338-
}, [sendCommand]);
334+
}, []);
339335

340336
// Jump to alarm frame
341337
const jumpToAlarmFrame = useCallback(() => {

app/src/components/events/__tests__/ZmsEventPlayer.test.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ vi.mock('react-i18next', () => ({
1919
vi.mock('../../../lib/logger', () => ({
2020
log: {
2121
zmsEventPlayer: vi.fn(),
22+
eventProgressBar: vi.fn(),
2223
},
2324
LogLevel: {
2425
DEBUG: 0,
@@ -155,19 +156,21 @@ describe('ZmsEventPlayer', () => {
155156
expect(new URL(seek![0] as string).searchParams.get('offset')).toBe('20');
156157
});
157158

158-
it('pauses the stream while scrubbing and resumes playing on release', () => {
159+
it('scrubs with seek alone, without pausing or resuming the stream', () => {
159160
renderPlayer();
160161
fireEvent.load(getStreamImg());
161162
const track = stubTrack();
162163

163-
// Grabbing the scrub bar pauses the running stream (CMD_PAUSE = 1) so the
164-
// video does not play forward between seeks.
164+
// Grabbing/moving the scrub bar issues a seek (CMD_SEEK = 14)...
165165
fireEvent.mouseDown(track, { clientX: 100 });
166-
expect(callsForCommand('1').length).toBeGreaterThan(0);
166+
expect(callsForCommand('14').length).toBeGreaterThan(0);
167167

168-
// Releasing resumes playback (CMD_PLAY = 2).
169168
fireEvent.mouseUp(window);
170-
expect(callsForCommand('2').length).toBeGreaterThan(0);
169+
170+
// ...but never pauses (CMD_PAUSE = 1) or resumes (CMD_PLAY = 2): the seek
171+
// drives playback by itself (refs #196).
172+
expect(callsForCommand('1')).toHaveLength(0);
173+
expect(callsForCommand('2')).toHaveLength(0);
171174
});
172175

173176
it('keeps the img src and connkey unchanged when playback speed changes', () => {

0 commit comments

Comments
 (0)