Add Docker Compose stack and Pi notes
LiveKit on host networking so WebRTC can advertise a reachable address, plus the server and website.
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
LIVEKIT_API_KEY=devkey
|
||||
LIVEKIT_API_SECRET=devsecretdevsecretdevsecretdevsecret
|
||||
|
||||
PUBLIC_LIVEKIT_URL=ws://localhost:7880
|
||||
PUBLIC_API_URL=http://localhost:8080
|
||||
|
||||
SESSION_SECRET=change-me-to-a-long-random-string
|
||||
SESSION_TTL_HOURS=12
|
||||
|
||||
BOOTSTRAP_ADMIN_EMAIL=admin@pistation.local
|
||||
BOOTSTRAP_ADMIN_PASSWORD=changeme
|
||||
|
||||
PIN_ROTATION_SECONDS=45
|
||||
PIN_GRACE_SECONDS=15
|
||||
|
||||
CORS_ORIGINS=http://localhost:3000,http://localhost:5173
|
||||
@@ -0,0 +1,58 @@
|
||||
name: pistation
|
||||
|
||||
services:
|
||||
livekit:
|
||||
image: livekit/livekit-server:latest
|
||||
restart: unless-stopped
|
||||
command: --config /etc/livekit.yaml
|
||||
environment:
|
||||
LIVEKIT_KEYS: "${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}"
|
||||
volumes:
|
||||
- ./livekit.yaml:/etc/livekit.yaml:ro
|
||||
network_mode: host
|
||||
|
||||
server:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: server/Dockerfile
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- livekit
|
||||
environment:
|
||||
BIND_ADDRESS: 0.0.0.0:8080
|
||||
DATABASE_URL: sqlite:///data/pistation.db?mode=rwc
|
||||
MEDIA_DIR: /data/media
|
||||
PACKAGE_DIR: /data/packages
|
||||
PUBLIC_API_URL: ${PUBLIC_API_URL}
|
||||
LIVEKIT_URL: ${PUBLIC_LIVEKIT_URL}
|
||||
LIVEKIT_API_KEY: ${LIVEKIT_API_KEY}
|
||||
LIVEKIT_API_SECRET: ${LIVEKIT_API_SECRET}
|
||||
SESSION_SECRET: ${SESSION_SECRET}
|
||||
SESSION_TTL_HOURS: ${SESSION_TTL_HOURS}
|
||||
BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL}
|
||||
BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD}
|
||||
PIN_ROTATION_SECONDS: ${PIN_ROTATION_SECONDS}
|
||||
PIN_GRACE_SECONDS: ${PIN_GRACE_SECONDS}
|
||||
CORS_ORIGINS: ${CORS_ORIGINS}
|
||||
volumes:
|
||||
- server-data:/data
|
||||
ports:
|
||||
- "8080:8080"
|
||||
|
||||
web:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: apps/web-client/Dockerfile
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- server
|
||||
environment:
|
||||
PORT: 3000
|
||||
HOST: 0.0.0.0
|
||||
PUBLIC_API_URL: ${PUBLIC_API_URL}
|
||||
PUBLIC_LIVEKIT_URL: ${PUBLIC_LIVEKIT_URL}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
volumes:
|
||||
server-data:
|
||||
@@ -0,0 +1,22 @@
|
||||
port: 7880
|
||||
bind_addresses:
|
||||
- 0.0.0.0
|
||||
|
||||
rtc:
|
||||
tcp_port: 7881
|
||||
port_range_start: 50000
|
||||
port_range_end: 50100
|
||||
use_external_ip: false
|
||||
|
||||
turn:
|
||||
enabled: true
|
||||
udp_port: 3478
|
||||
domain: localhost
|
||||
|
||||
room:
|
||||
auto_create: true
|
||||
empty_timeout: 300
|
||||
max_participants: 50
|
||||
|
||||
logging:
|
||||
level: info
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"serverUrl": "http://pistation.local:8080",
|
||||
"enrollmentToken": "paste-the-token-from-the-admin-panel",
|
||||
"joinUrl": "pistation.local:3000"
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
# Spike: video performance on the Pi Zero 2W
|
||||
|
||||
The original question was whether WebKitGTK could reach hardware H.264 decode. That turned
|
||||
out to be moot: WebKitGTK ships without WebRTC at all, so the kiosk cannot receive media in
|
||||
the webview.
|
||||
|
||||
The kiosk now joins the room from Rust with the native LiveKit SDK. Decoding happens there,
|
||||
each frame is scaled and JPEG encoded, and the result is pushed to the webview to be drawn
|
||||
on a canvas. The question this spike answers has therefore changed: can a Zero 2W decode the
|
||||
incoming stream **and** re-encode it fast enough to look live.
|
||||
|
||||
The decode half is still worth measuring with the commands below, because libwebrtc uses the
|
||||
same V4L2 path. The encode half is measured from the app itself, by lowering
|
||||
`PISTATION_VIDEO_MAX_WIDTH`, `PISTATION_VIDEO_FPS` and `PISTATION_VIDEO_QUALITY` until the
|
||||
picture keeps up.
|
||||
|
||||
## Baseline
|
||||
|
||||
The Zero 2W has a VideoCore IV class block exposed through V4L2 stateful decode at
|
||||
`/dev/video10`, reached through GStreamer's `v4l2h264dec`.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Confirm the kernel exposes the decoder.
|
||||
|
||||
```
|
||||
ls -l /dev/video10 /dev/video11 /dev/video12
|
||||
v4l2-ctl -d /dev/video10 --all | head -40
|
||||
```
|
||||
|
||||
`/dev/video10` must report `Codec Decoder` capabilities.
|
||||
|
||||
2. Confirm GStreamer picks the hardware element over the software one.
|
||||
|
||||
```
|
||||
gst-inspect-1.0 v4l2h264dec
|
||||
gst-launch-1.0 videotestsrc num-buffers=600 ! video/x-raw,width=1280,height=720 \
|
||||
! x264enc tune=zerolatency ! h264parse ! v4l2h264dec ! fpsdisplaysink text-overlay=false
|
||||
```
|
||||
|
||||
Record the reported average FPS. Under 25 means the decode path is not viable.
|
||||
|
||||
3. Run the same clip through the software decoder for comparison.
|
||||
|
||||
```
|
||||
gst-launch-1.0 videotestsrc num-buffers=600 ! video/x-raw,width=1280,height=720 \
|
||||
! x264enc tune=zerolatency ! h264parse ! avdec_h264 ! fpsdisplaysink text-overlay=false
|
||||
```
|
||||
|
||||
If step 2 and step 3 report similar numbers, WebKit is almost certainly using
|
||||
software decode and the hardware element is not being selected.
|
||||
|
||||
4. Measure the real path. Start the kiosk, join from a laptop, share a 1280x720
|
||||
screen, and sample CPU while the stream is live.
|
||||
|
||||
```
|
||||
systemctl start pistation-kiosk
|
||||
top -b -n 30 -d 1 | grep -E "WebKitWebProcess|pistation-kiosk"
|
||||
```
|
||||
|
||||
Sustained WebKitWebProcess CPU above roughly 85 percent of one core means the
|
||||
decode is running in software.
|
||||
|
||||
5. Force the issue if step 4 is inconclusive.
|
||||
|
||||
```
|
||||
GST_DEBUG=v4l2*:5 systemctl start pistation-kiosk
|
||||
journalctl -u pistation-kiosk | grep -i v4l2h264dec
|
||||
```
|
||||
|
||||
## Recording the result
|
||||
|
||||
| Measurement | Value | Pass threshold |
|
||||
| --- | --- | --- |
|
||||
| `v4l2h264dec` 720p30 FPS | | 25 or higher |
|
||||
| WebKitWebProcess CPU, 720p live share | | under 85 percent of one core |
|
||||
| Frames dropped over 5 minutes | | under 1 percent |
|
||||
| Annotation input to on-screen latency | | under 250 ms |
|
||||
|
||||
## If the spike fails
|
||||
|
||||
1. Try 960x540 at 20 fps by capping the publisher in `apps/web-client` before
|
||||
declaring failure. The Zero 2W often passes at that resolution.
|
||||
2. If it still fails, build `services/compositor-bot`. GStreamer composites the
|
||||
screen share and the annotation canvas server side and sends the Pi one stream,
|
||||
which drops the Pi's job to plain video playback.
|
||||
Reference in New Issue
Block a user