You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Uses `cv2.VideoCapture` to capture frames from camera source (default device `0`, configurable via `VIDEO_SOURCE`)
57
-
- Converts frames to `av.VideoFrame` (BGR24 format) with proper PTS/time_base timestamps
58
-
-`recv()` loops until a frame is captured (no recursion)
59
-
-`stop()` releases `VideoCapture` to avoid device handle leaks when the PC is replaced
55
+
-`cv2.VideoCapture` can only be opened **once** per process on this hardware. Multi-viewer support is handled by `SharedCameraSource`:
56
+
- Opens the capture device once; runs a `_read_loop` background task that reads frames and fan-outs to per-viewer `asyncio.Queue(maxsize=4)`.
57
+
- Subscribers call `subscribe(key) → Queue` / `unsubscribe(key)`. If a queue is full, the oldest frame is dropped (never blocks the read loop).
58
+
- Released via `stop()` when all viewers disconnect; recreated on next connection.
59
+
-`CameraVideoStreamTrack` extends `aiortc.VideoStreamTrack`; subscribes to a `SharedCameraSource` on init, unsubscribes in `stop()`.
60
+
- Converts frames to `av.VideoFrame` (BGR24 format) with proper PTS/time_base timestamps.
61
+
-`PiClient._get_or_create_camera_source()` — lazily opens the camera; `_release_camera_if_idle()` — stops and nulls it when `peer_connections` is empty.
-`send(event, message="", level="INFO")` — synchronous; called via `asyncio.to_thread` from async contexts
@@ -135,3 +137,10 @@ devices:
135
137
## `.envrc`
136
138
137
139
**Never modify `.envrc`.** It contains local-only developer environment config and must always reflect the developer's own setup.
140
+
141
+
## CI/CD Observability
142
+
143
+
Both workflows send a structured event to Honeycomb's Events API (`github-actions` dataset) at the end of every job (pass or fail). Fields: `workflow`, `job`, `status`, `duration_ms`, `sha`, `ref`, `actor`, `repository`, `run_id`, `run_number`, `commit_message`. Requires the `HONEYCOMB_API_KEY` GitHub Actions secret. Honeycomb failures are non-fatal.
144
+
145
+
- `build-docker.yml`— one job (`build-and-push`), one event per run
146
+
- `build-deb.yml`— two jobs (`test`, `build`), one event per job per run
Requires `/dev/video0` on the host (mapped into the container). Tokens and OAuth config are shared with the `utility` service via Docker volumes.
24
+
25
+
## Camera Architecture
26
+
27
+
A single `SharedCameraSource` opens `cv2.VideoCapture` once and fans frames to per-viewer `asyncio.Queue`s. Each `CameraVideoStreamTrack` subscribes with a unique viewer key. This supports multiple simultaneous viewers without attempting to re-open the device. The camera is released when all viewers disconnect, and re-opened on the next connection.
28
+
29
+
## CI/CD
30
+
31
+
Push to `master` triggers two workflows:
32
+
33
+
**`build-docker.yml`** — builds and pushes `docker.kmanning.ie:5000/intercom-python-client:{latest,sha,version}` (ARM runner)
34
+
35
+
**`build-deb.yml`** — runs pytest, then builds a native ARM64 binary with Nuitka and packages it as a `.deb` for Raspberry Pi installation. Uploads the artifact with 30-day retention.
36
+
37
+
Both workflows send a structured event to Honeycomb (`github-actions` dataset) at job completion — requires `HONEYCOMB_API_KEY` GitHub secret.
0 commit comments