Playback on mobile
The mobile Playback screen plays the recorded history for one camera, scrubbing through stored MP4 segments. The playhead drives a vertical event-timeline on the right; tapping any event jumps to that moment.
Playback opens from the Playback quick-action button on the Live view, or from anywhere a deep link with cameraId and an optional startTs lands.
What you see
| Region | What it does |
|---|---|
| Header (top) | Back arrow, “Playback” title, a small Live pill that jumps to live view for the same camera |
| Video player | Plays the MP4 segment covering the current timestamp. Black with “No recording at this time” banner if the timestamp falls in a gap |
| Toolbar | Share (cloud icon) and the date chip showing the current timestamp (tap to open the Jump-to-time sheet) |
| Vertical timeline | Right-side scrollable list of recording segments. Tap any row to jump |
| Transport bar (bottom) | Skip back 1 min · Rewind 10 s · Play/Pause · Forward 10 s · Skip forward 1 min |
The Live pill in the header is a fast-path back to the live view — it uses a navigation reset so the back stack collapses to Tabs → LiveView (you do not pile up history). The dedicated Live tab at the bottom does the same thing but for whatever site filter is active.
How segments are loaded
Playback fetches the camera’s recordings in a 30-minute sliding window anchored on the user-selected timestamp. Whenever you skip, scrub, or jump, the window re-centres on the new timestamp and the cloud returns every clip whose start_ts falls inside it.
The vertical timeline shows one row per clip, labelled with the wall-clock start time. The current segment is highlighted. Gaps between segments — periods where the camera was offline, the event window didn’t fire, or motion didn’t trigger a recording — show no rows.
The covering clip is the segment whose [start_ts, end_ts] interval contains the current timestamp. When you skip into a gap, the player pauses and shows the “No recording at this time. Scrub to a marker to resume.” banner — tap an event row to resume.
Jump to a time
Tap the date chip in the toolbar. A bottom sheet opens with five fixed presets:
| Preset | What it does |
|---|---|
| Now | Jump to current wall-clock time (typically falls outside any recording window — Live view is what you want for “right now”) |
| 1 hour ago | Jump to now − 1h |
| 6 hours ago | Jump to now − 6h |
| 1 day ago | Jump to now − 24h |
| 1 week ago | Jump to now − 168h |
There is no calendar picker in v1. To reach an exact arbitrary date, navigate via the relative preset closest to your target, then use the skip-back-1-minute / forward-1-minute buttons to fine-tune.
Transport bar
Five buttons:
- ⏮ (Skip back 1 minute) — moves the anchor 60 seconds back
- ⏪ (Rewind 10 s) — moves the anchor 10 seconds back
- ▶ / ⏸ (Play / Pause) — controls the player. Disabled when the current timestamp is in a gap (no clip to play)
- ⏩ (Forward 10 s) — moves the anchor 10 seconds forward
- ⏭ (Skip forward 1 minute) — moves the anchor 60 seconds forward
The skip buttons change the anchor (the timestamp you’re scrubbing to), not the player offset. When you cross a segment boundary, the player switches to the new segment automatically and the offset inside the segment resets to 0.
Share the segment playing now
Tap the download / share button (cloud arrow) on the toolbar. In v1 this opens the OS share sheet with the presigned URL of the segment covering the current timestamp, plus a label like “NovaVMS clip — 2026-05-22 14:32”.
Limitation in v1: this share path uses a remote URL, not a local-file download like the Event detail share. Recipients on Android may not see the URL field on every share target, and the presigned URL expires in minutes. If a teammate needs the actual MP4 file, open the matching event from the Events tab and share from there.
This will be unified to the Event-detail download-then-share flow in a future release.
Tap an event row
The right-side timeline lists every clip in the 30-minute window. Tap any row:
- The anchor jumps to that segment’s start time.
- The in-clip offset resets to 0 so playback starts from the beginning of the segment.
- The player switches to the new segment’s presigned URL.
When the cloud cannot load a clip — expired URL, network failure, file missing — the player surfaces a “Clip unavailable” overlay with a Retry button. Tap Retry to re-fetch the segments list and try again.
Performance: streams on mobile
Playback uses the same expo-video stack as the H.265 live tile — AVPlayer on iOS, ExoPlayer on Android. Live and playback never run simultaneously: opening Playback releases the live tile’s decoder so the playback decoder can acquire one. Switching back via the Live pill releases the playback decoder before the live tile mounts.
On low-end Android devices (Pixel 4 / Galaxy S9 class), HEVC decoder contention can take 1–3 seconds to resolve when transitioning between live and playback. The transition is correct (no orphan decoder, no double-allocation crash) but visually you may see a brief black frame.
What this screen does NOT do (v1)
- No multi-camera playback. One camera at a time.
- No calendar / date picker. Use the relative presets + skip buttons.
- No bookmark. The Star action lives on Event detail (events have starring; raw segments don’t).
- No download to local file. Use the Event detail Share button for that.
- No frame-by-frame scrubbing. The scrubber moves at second resolution.
- No reverse playback. Skip back to a point, then play forward.