VMS cameras
The VMS tab of the streams tile manages third-party IP cameras — NVR CCTV feeds, ONVIF PTZ cameras, embed-only streams from proprietary systems. You can add, test, edit, and delete cameras per mission, and each camera has a full geolocation + field-of-view profile so it renders as an FOV cone on the map.
The camera grid
Every camera attached to this mission renders as a card showing:
- Thumbnail (live if the stream resolves).
- Name + group tag.
- Stream type badge (HLS / MJPEG / MP4 / Embed).
- Location + bearing chip if geocoded.
- Edit (pencil) and delete (trash) buttons.
Cards are driven by a subscription to Firestore — any edit you make, or anything a teammate makes, shows up within a second.
Add-camera form
Click Add camera in the tab header. A side panel slides in with the form. All fields:
Basics
- Name — required. Shown on the card and map cone tooltip.
- URL — required. The raw stream URL. For HLS it’s an
.m3u8; for MJPEG it’s the camera’s motion-JPEG endpoint; for MP4 it’s a direct-play URL; for embed it’s an iframe URL. - Stream type — dropdown: HLS / MJPEG / MP4 / Embed.
- Enabled — toggle. Disabled cameras stay in the list but don’t render their stream or FOV cone.
- Channel — numeric. Useful when multiple cameras share a common NVR naming scheme.
- Group — free text (e.g. “North perimeter”, “Gate cameras”).
- Location — free text location label.
- Notes — free text, up to a few hundred chars.
The four stream types
| Type | What you provide | How it renders |
|---|---|---|
| HLS | .m3u8 playlist URL | Adaptive-bitrate playback via hls.js. Works in every browser. |
| MJPEG | motion-JPEG HTTP endpoint | Frame-at-a-time via <img> tag. High CPU on the viewer but universal. |
| MP4 | Direct MP4 URL (file or live-MP4) | Native <video> element. Low latency if your server produces live fragmented MP4. |
| Embed | Arbitrary iframe URL | <iframe> — used for proprietary web players that can’t be extracted into a direct stream. |
Authentication
- Auth type — dropdown:
none/basic/token. - Username + password — shown only for
basic. HTTP Basic Auth. - Auth token — shown only for
token. Attached as a Bearer token via theAuthorizationheader (or appended as a query-string if the camera can’t handle header auth; the player tries both).
PTZ
- PTZ enabled — toggle. Reveals the rest of the PTZ block.
- PTZ URL — optional. For HTTP-controlled PTZ, the URL template with
{direction}/{speed}placeholders. For ONVIF, leave blank. - PTZ type — dropdown:
onvif/http. ONVIF speaks SOAPContinuousMovecommands; http substitutes into the URL template. - PTZ speed — 1-10 slider. Sent with every PTZ command.
- PTZ profile token — ONVIF only. Most ONVIF cameras auto-expose a default profile; only set this if your camera has multiple profiles and you want to target a specific one.
Location + field-of-view
Fill these to render the camera on the map as an FOV cone on the ground:
- Lat / Lng — required for map rendering.
- Height (m) — default 3 m. The camera’s height above ground.
- Bearing (degrees) — 0-360, default 0. Compass heading the camera points at.
- Tilt (degrees) — -90 to 0. Downward pitch; -30 is a common angle for perimeter cams.
- Horizontal FOV (degrees) — 10-180. The camera’s horizontal cone angle.
Missing location fields just skip map rendering — the card and player still work.
The test-stream flow
Click Test after filling URL + auth. The tile calls
vmsService.checkHealth(fakeCam) and the testResult signal cycles through these
states:
| State | Meaning |
|---|---|
none | Not tested yet. |
live | Test succeeded — stream is reachable and returns video. |
auth_error | 401/403 from the camera. Your credentials are wrong. |
offline | Connection refused / timeout / DNS failure. Camera is unreachable. |
error | Something else broke — invalid URL, unsupported codec, corrupt stream. |
The result badge stays until you change a field or click Test again. A successful test doesn’t guarantee the camera will work in production (transient network blips) but it catches the common config-error cases.
Saving
Click Save. The camera is written to Firestore under
missions/{missionId}/vms_cameras/{cameraId}. It appears on every participant’s
grid within a second and, if location fields are filled, on the map as a cone
cone.
Editing
Click the pencil icon on any card. The form reopens pre-filled with all current values. Saving updates the Firestore doc in place — the camera’s ID is preserved so flags and any other docs that reference it stay valid.
Deleting
Click the trash icon. A confirmation prompt appears (two-step for safety). On confirm, the camera is removed from Firestore and from everyone’s grid. Deleting a camera does NOT delete any recordings — those live separately.
Sharing across missions
Cameras added via the VMS tab live inside the mission. To share across missions, add them at the org level via Admin → Organisation → VMS library — those appear in every mission automatically.
Per-camera playback
Click a card to open the VMS player in-tile. Controls:
- Play / Pause.
- Mute / Unmute.
- Full-screen.
- Snapshot (PNG of the current frame).
- PTZ arrows + zoom rocker if PTZ is configured and enabled.
- Recording (start / stop) — delegates to the VMS service for server-side recording.
PTZ commands go through an ARGUS proxy (your browser can’t speak ONVIF SOAP
directly). The proxy lives in argus-api’s /api/vms surface.
Known limitations
- No auto-cycle for streams that drop connection — if the NVR reboots, you must manually click into the camera to force a retry.
- No RTSP direct — only HLS / MJPEG / MP4 / Embed. For RTSP cameras, put a
transcoder (e.g.
go2rtcorRTSPtoWeb) in front of them and point ARGUS at the HLS output. - No multi-camera preset tour — each camera is played individually; there’s no “tour four cameras sequentially” mode.
Related
- Streams overview
- Camera stream tile — dedicate a tile to one camera.
- Admin → Organisation → VMS library for org-wide cameras shared across missions.