docs: serial identity, enhance hop/window, optional systemd unit

This commit is contained in:
Hermes
2026-08-28 05:21:36 +00:00
parent 106790cab8
commit 30b128bc9e
2 changed files with 50 additions and 7 deletions
+34 -7
View File
@@ -8,6 +8,9 @@ publishes:
- a camera video track (1280x720 @ 30 fps by default, MJPG from V4L2)
- a microphone audio track (16 kHz mono, cleaned with speechbrain)
Identity is the USB serial, pinned by udev (`/dev/camNN` + `slots.json`).
`--cameras 1,5` means participants `cam-01` and `cam-05`, not discovery order.
## Layout
```
@@ -20,6 +23,9 @@ config.py .env / environment configuration
prefetch_model.py one-time speechbrain model download
generate_udev_rules.py (re)generate udev pinning + slots.json from live state
slots.json stable slot map: cam-NN -> USB serial, /dev/camNN, ALSA card
smoke_test.py one-camera LiveKit publish with enhancement ON
scripts/bench_enhance.py RTF bench (1 s window / 200 ms hop)
deploy/livekit-cameras.service optional systemd unit (do not enable blindly)
```
## Setup
@@ -52,6 +58,9 @@ sudo udevadm trigger --subsystem-match=video4linux --action=add
sudo udevadm trigger --subsystem-match=sound --action=add
```
The generator bakes the **current physical wiring** as canonical. Do not
re-run `--write` unless you intend to remap slots.
## Run
```bash
@@ -62,11 +71,28 @@ sudo udevadm trigger --subsystem-match=sound --action=add
## Audio cleanup
The mic audio is cleaned per chunk (default 200 ms) by
`speechbrain/metricgan-plus-voicebank` (16 kHz, CPU). One worker process per
camera loads the model once and reuses it; on this 28-core box all 20 stay
real-time. `ENHANCE_MODE=off` (or a failed model load with `auto`) falls back
to a lightweight high-pass + soft-clip DSP path so streams still work.
The mic audio is cleaned per hop (default 200 ms) by
`speechbrain/metricgan-plus-voicebank` (16 kHz, CPU) over a 1 s rolling
window (`ENHANCE_CHUNK_S=1.0`, `ENHANCE_HOP_S=0.2`). One worker process
per camera loads the model once and reuses it. `enhance_batch` must be
called with `lengths=torch.tensor([1.0])` (relative, not sample count).
`ENHANCE_MODE=off` (or a failed model load with `auto`) falls back to a
lightweight high-pass + soft-clip DSP path so streams still work.
Until the 1 s window is full, hops use the DSP fallback so LiveKit is
not silent on startup.
## systemd (optional, not enabled)
```bash
sudo cp deploy/livekit-cameras.service /etc/systemd/system/
sudo systemctl daemon-reload
# only if you want 24/7:
sudo systemctl enable --now livekit-cameras
```
Requires a LiveKit server already listening (this host uses
`/tmp/livekit-server --config /tmp/livekit-test.yaml` on :7880).
## Notes
@@ -74,6 +100,7 @@ to a lightweight high-pass + soft-clip DSP path so streams still work.
-input_format mjpeg`) — cheap, and converts to BGRA for LiveKit.
- Audio: ALSA mics on these C920s deliver 16 kHz **stereo** only; the worker
downmixes to mono for LiveKit.
- Camera <-> card pairing is resolved by matching USB port paths under /sys,
so each mic belongs to its own camera.
- Camera identity is USB serial via `slots.json` / udev; USB port is
fallback only for cameras not yet in the map.
- Workers auto-restart (up to 10 times) if a camera drops.
- Local smoke: `.venv/bin/python smoke_test.py` (needs livekit-server on 7880).
+16
View File
@@ -0,0 +1,16 @@
[Unit]
Description=Publish C920 cameras (speechbrain audio) to LiveKit
After=network-online.target sound.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/home/fdenkena/livekit-cameras
ExecStart=/home/fdenkena/livekit-cameras/.venv/bin/python /home/fdenkena/livekit-cameras/run.py
Restart=on-failure
RestartSec=5
Environment=PYTHONUNBUFFERED=1
Environment=LIVEKIT_URL=ws://127.0.0.1:7880
[Install]
WantedBy=multi-user.target