feat: point the fleet at wss LiveKit room uwh-telhai

Publish and subscribe over wss://livekit.uni-wh.de:7800 and refuse
cleartext ws://. Conference room is uwh-telhai. Includes the uncommitted
encoded H.264 publish path, Rally hairpin, and KMS wall overlay.
This commit is contained in:
root
2026-10-11 00:48:50 +00:00
parent ef9573c294
commit 95bb7c50ee
89 changed files with 9883 additions and 243 deletions
Binary file not shown.
+23
View File
@@ -0,0 +1,23 @@
"""Annex-B access-unit split."""
from annexb import AnnexBSplitter, is_keyframe, nal_unit_type
def test_splitter_emits_complete_nal():
s = AnnexBSplitter()
assert s.push(b"") == []
first = b"\x00\x00\x00\x01\x67SPS"
second = b"\x00\x00\x00\x01\x68PPS"
assert s.push(first + second) == [first]
assert s.push(b"\x00\x00\x00\x01\x65IDR") == [second]
def test_is_keyframe_idr():
au = b"\x00\x00\x00\x01\x67\x00\x00\x00\x01\x65\x88"
assert is_keyframe(au) is True
assert nal_unit_type(au) == 7
def test_is_keyframe_delta():
au = b"\x00\x00\x00\x01\x41\x00"
assert is_keyframe(au) is False
assert nal_unit_type(au) == 1
+73
View File
@@ -0,0 +1,73 @@
"""Hop energy gate so neighboring C920s do not publish bleed."""
import numpy as np
from audio_gate import HopGate, gate_enabled_for, rms_dbfs
def _sine(n=1600, amp=8000):
return (np.sin(2 * np.pi * 440 * np.arange(n) / 16000) * amp).astype(np.int16)
def test_rms_dbfs_silence_is_floor():
assert rms_dbfs(np.zeros(1600, dtype=np.int16)) <= -120.0
def test_rms_dbfs_sine_is_near_minus_15():
db = rms_dbfs(_sine())
assert -16.5 < db < -14.0
def test_gate_silences_quiet_hop():
g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=3)
quiet = (np.random.randn(1600) * 80).astype(np.int16)
out = g.apply(quiet)
assert int(np.max(np.abs(out))) == 0
assert g.open is False
def test_gate_passes_loud_hop():
g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=3)
loud = _sine()
out = g.apply(loud)
assert int(np.max(np.abs(out))) > 1000
assert g.open is True
def test_gate_hold_then_closes():
g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=2)
g.apply(_sine())
quiet = np.zeros(1600, dtype=np.int16)
assert int(np.max(np.abs(g.apply(quiet)))) == 0 or g.open is True
g.apply(quiet)
g.apply(quiet)
assert g.open is False
assert int(np.max(np.abs(g.apply(quiet)))) == 0
def test_gate_skips_rally():
assert gate_enabled_for("rally", "rally", True) is False
assert gate_enabled_for("cam-07", "rally", True) is True
assert gate_enabled_for("cam-07", "rally", False) is False
def test_cleaner_gates_quiet_after_dsp():
from audio_cleanup import AudioCleaner
c = AudioCleaner(mode="off", beamform="off", gate=HopGate(open_db=-32.0, close_db=-40.0, hold_hops=1))
quiet = (np.random.randn(1600) * 80).astype(np.int16)
out = c.process(quiet)
assert out.shape == (1600,)
assert int(np.max(np.abs(out))) == 0
loud = _sine(1600, 8000)
out = c.process(loud)
assert int(np.max(np.abs(out))) > 1000
def test_cleaner_gate_uses_raw_energy_not_dsp_makeup():
"""Room floor ~-34 dBFS must stay closed even though DSP makeup is ~+3 dB."""
from audio_cleanup import AudioCleaner
c = AudioCleaner(mode="off", beamform="off", gate=HopGate(open_db=-32.0, close_db=-40.0, hold_hops=1))
# sine RMS -34 dBFS => amplitude ~924
floor = _sine(1600, 924)
assert -35.5 < rms_dbfs(floor) < -32.5
out = c.process(floor)
assert int(np.max(np.abs(out))) == 0
+19
View File
@@ -0,0 +1,19 @@
from audio_gst import grouped_audio, shared_audio_cmd
def test_shared_audio_cmd_no_video_elements():
cams = [("cam-01", 4), ("cam-02", 5)]
cmd = shared_audio_cmd(cams, 16000, [8, 9])
joined = " ".join(cmd)
assert joined.count("alsasrc") == 2
assert "device=hw:4,0" in joined
assert "device=hw:5,0" in joined
assert "h264enc" not in joined
assert "v4l2src" not in joined
def test_grouped_audio_splits():
cams = [(f"cam-{i:02d}", i + 1) for i in range(1, 21)]
fds = list(range(20))
groups = grouped_audio(cams, fds, 5)
assert len(groups) == 4
+50
View File
@@ -0,0 +1,50 @@
from capture_va import grouped_cameras, shared_capture_cmd, video_capture_cmd
def test_video_capture_cmd_latest_frame_no_sidecar_h264():
cmd = video_capture_cmd("/dev/cam01", 640, 360, 30)
joined = " ".join(cmd)
assert "v4l2src" in joined
assert "device=/dev/cam01" in joined
assert "jpegdec" in joined
assert "videoconvert" in joined
assert "I420" in joined
assert "leaky=downstream" in joined
assert "max-size-buffers=1" in joined
assert "max-size-time=0" in joined
assert "fdsink" in joined
assert "h264enc" not in joined
assert "tee" not in joined
def test_capture_does_not_gst_crop_or_box():
"""MCU crop is Python-side on 07/14/15 only; gst stays full 360."""
for dev in ("/dev/cam01", "/dev/cam07"):
joined = " ".join(video_capture_cmd(dev, 640, 360, 30))
assert "videocrop" not in joined
assert "videobox" not in joined
assert "videoscale" not in joined
def test_shared_capture_cmd_one_process_no_sidecar_h264():
cams = [("cam-01", "/dev/cam01"), ("cam-02", "/dev/cam02")]
cmd = shared_capture_cmd(cams, 640, 360, 30, [8, 9])
joined = " ".join(cmd)
assert cmd[0].endswith("gst-launch-1.0") or "gst-launch-1.0" in cmd[0]
assert joined.count("v4l2src") == 2
assert joined.count("jpegdec") == 2
assert joined.count("videoconvert") == 2
assert joined.count("fdsink") == 2
assert "fd=8" in joined and "fd=9" in joined
assert "h264enc" not in joined
assert "tee" not in joined
def test_grouped_cameras_splits_into_small_pool():
cams = [(f"cam-{i:02d}", f"/dev/cam{i:02d}") for i in range(1, 21)]
fds = list(range(20, 40))
groups = grouped_cameras(cams, fds, 5)
assert len(groups) == 4
assert all(len(c) == 5 and len(f) == 5 for c, f in groups)
assert groups[0][0][0][0] == "cam-01"
assert groups[-1][0][-1][0] == "cam-20"
+124 -1
View File
@@ -1,4 +1,4 @@
from config import Config, _parse_cameras
from config import Config, _parse_cameras, load_config
def test_parse_cameras_list():
@@ -17,3 +17,126 @@ def test_torch_num_threads_default_one():
def test_enhance_infer_default_auto():
assert Config().enhance_infer == "auto"
def test_latency_flag_defaults():
c = Config()
assert c.audio_queue_ms is None
assert c.video_hold_s is None
assert c.worker_split_executor is False
assert c.enhance_speaker_only is False
assert c.audio_gate is False
assert c.audio_gate_open_db == -28.0
assert c.audio_gate_close_db == -34.0
assert c.audio_gate_hold_s == 0.3
assert c.display_video_capacity == 0
assert c.display_video_format == ""
assert c.display_gst_queue_buffers == 2
assert c.display_speaker_push == "timer"
assert c.participant_tags == ["uwh"]
assert c.display_hide_tags == []
assert c.display_hand_raise is True
assert c.display_hand_raise_hz == 4.0
assert c.display_hand_raise_hold_s == 1.0
assert c.display_hand_raise_model == "thunder"
assert c.display_speak_min_db == -40.0
assert c.display_speak_margin_db == 6.0
assert c.display_speak_hold_s == 0.6
assert c.display_speak_rise_db == 3.0
assert c.display_speak_corr == 0.4
assert c.display_speak_confirm == 2
assert c.portrait_blur is True
assert c.portrait_shm_dir == "/run/livekit-cameras/portrait"
assert c.portrait_hz == 8.0
assert c.portrait_blur_px == 7
assert c.portrait_hold_s == 0.8
def test_enhance_daemon_defaults():
c = Config()
assert c.enhance_daemon is True
assert c.enhance_socket == "/tmp/livekit-enhance.sock"
assert c.capture_daemon is True
assert c.capture_shm_dir == "/run/livekit-cameras/raw"
assert c.audio_daemon is True
assert c.audio_shm_dir == "/run/livekit-cameras/pcm"
assert c.single_publisher is True
def test_load_config_enhance_daemon_env(monkeypatch, tmp_path):
env = tmp_path / ".env"
env.write_text("")
monkeypatch.setenv("ENHANCE_DAEMON", "0")
monkeypatch.setenv("ENHANCE_SOCKET", "/run/foo.sock")
cfg = load_config(env)
assert cfg.enhance_daemon is False
assert cfg.enhance_socket == "/run/foo.sock"
def test_load_config_latency_env(monkeypatch, tmp_path):
env = tmp_path / ".env"
env.write_text("")
monkeypatch.setenv("AUDIO_QUEUE_MS", "60")
monkeypatch.setenv("VIDEO_HOLD_S", "0")
monkeypatch.setenv("WORKER_SPLIT_EXECUTOR", "1")
monkeypatch.setenv("ENHANCE_SPEAKER_ONLY", "true")
monkeypatch.setenv("AUDIO_GATE", "0")
monkeypatch.setenv("AUDIO_GATE_OPEN_DB", "-28")
monkeypatch.setenv("AUDIO_GATE_HOLD_S", "0.5")
monkeypatch.setenv("DISPLAY_VIDEO_CAPACITY", "1")
monkeypatch.setenv("DISPLAY_VIDEO_FORMAT", "BGRA")
monkeypatch.setenv("DISPLAY_GST_QUEUE_BUFFERS", "1")
monkeypatch.setenv("DISPLAY_SPEAKER_PUSH", "arrival")
cfg = load_config(env)
assert cfg.audio_queue_ms == 60
assert cfg.video_hold_s == 0.0
assert cfg.worker_split_executor is True
assert cfg.enhance_speaker_only is True
assert cfg.audio_gate is False
assert cfg.audio_gate_open_db == -28.0
assert cfg.audio_gate_hold_s == 0.5
assert cfg.display_video_capacity == 1
assert cfg.display_video_format == "bgra"
assert cfg.display_gst_queue_buffers == 1
assert cfg.display_speaker_push == "arrival"
def test_load_config_site_tags(monkeypatch, tmp_path):
env = tmp_path / ".env"
env.write_text("")
monkeypatch.setenv("PARTICIPANT_TAGS", "uwh")
monkeypatch.setenv("DISPLAY_HIDE_TAGS", "")
cfg = load_config(env)
assert cfg.participant_tags == ["uwh"]
assert cfg.display_hide_tags == []
monkeypatch.setenv("DISPLAY_HIDE_TAGS", "uwh")
cfg = load_config(env)
assert cfg.display_hide_tags == ["uwh"]
def test_load_config_hand_raise_env(monkeypatch, tmp_path):
env = tmp_path / ".env"
env.write_text("")
monkeypatch.setenv("DISPLAY_HAND_RAISE", "0")
monkeypatch.setenv("DISPLAY_HAND_RAISE_HZ", "3")
monkeypatch.setenv("DISPLAY_HAND_RAISE_HOLD_S", "1.2")
cfg = load_config(env)
assert cfg.display_hand_raise is False
assert cfg.display_hand_raise_hz == 3.0
assert cfg.display_hand_raise_hold_s == 1.2
def test_load_config_portrait_env(monkeypatch, tmp_path):
env = tmp_path / ".env"
env.write_text("")
monkeypatch.setenv("PORTRAIT_BLUR", "0")
monkeypatch.setenv("PORTRAIT_SHM_DIR", "/tmp/portrait")
monkeypatch.setenv("PORTRAIT_HZ", "5")
monkeypatch.setenv("PORTRAIT_BLUR_PX", "11")
monkeypatch.setenv("PORTRAIT_HOLD_S", "0.4")
cfg = load_config(env)
assert cfg.portrait_blur is False
assert cfg.portrait_shm_dir == "/tmp/portrait"
assert cfg.portrait_hz == 5.0
assert cfg.portrait_blur_px == 11
assert cfg.portrait_hold_s == 0.4
+147
View File
@@ -3,11 +3,18 @@ import numpy as np
from display_grid import (
CameraGrid,
bgra_to_i420,
camera_ids,
describe_livekit_error,
display_name,
format_livekit_status,
grid_shape,
i420_nbytes,
is_camera_identity,
letterbox_bgra,
letterbox_i420,
placeholder,
status_screen,
)
@@ -75,7 +82,147 @@ def test_gap_separates_tiles():
assert tuple(canvas[y, x]) == (10, 10, 10, 255)
def test_inner_rect_cam01_is_top_left_inside_border():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4, gap=8, border=3)
x, y, w, h = g.inner_rect(0)
assert (x, y) == (g.gap + g.border, g.gap + g.border)
assert (w, h) == (g.inner_w, g.inner_h)
x2, y2, _, _ = g.inner_rect(1)
assert x2 == g.gap + (g.tile_w + g.gap) + g.border
assert y2 == y
def test_placeholder_draws_text():
img = placeholder(640, 360, ["Screen share", "stub"])
assert img.shape == (360, 640, 4)
assert img.sum() > 0
def test_letterbox_i420_size_and_even_uv():
src = np.zeros((360, 640, 4), dtype=np.uint8)
src[:] = (0, 255, 0, 255)
blob = bgra_to_i420(src)
out = letterbox_i420(blob, 640, 360, 368, 226)
assert len(out) == i420_nbytes(368, 226)
y = np.frombuffer(out, dtype=np.uint8, count=368 * 226).reshape(226, 368)
assert 0 not in y[0]
assert 0 not in y[-1]
def test_grid_i420_render_and_set_frame():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
buf = g.render_i420()
assert len(buf) == i420_nbytes(1920, 1080)
src = np.zeros((360, 640, 4), dtype=np.uint8)
src[:] = (255, 0, 0, 255)
g.set_frame_i420("cam-07", bgra_to_i420(src), 640, 360)
buf2 = g.render_i420()
assert buf2 != buf
g.clear("cam-07")
assert g.render_i420() == buf
def test_ensure_slot_binds_remote_to_empty_tile():
g = CameraGrid(width=640, height=360, cols=2, rows=1, identities=["cam-01", "cam-02"])
assert g.ensure_slot("alice") is True
assert "alice" in g._tiles
assert g.identities[0] == "alice"
frame = np.zeros((90, 160, 4), dtype=np.uint8)
g.set_frame("alice", frame)
assert "alice" in g._live
assert g.ensure_slot("alice") is True
def test_grid_shape_shrinks_with_live_count():
assert grid_shape(0) == (1, 1)
assert grid_shape(1) == (1, 1)
assert grid_shape(2) == (2, 1)
assert grid_shape(4) == (2, 2)
assert grid_shape(5) == (3, 2)
assert grid_shape(6) == (3, 2)
assert grid_shape(9) == (3, 3)
assert grid_shape(12) == (4, 3)
assert grid_shape(20) == (5, 4)
cols, rows = grid_shape(5)
assert cols * rows >= 5
assert cols <= 5 and rows <= 4
def test_set_identities_rebuilds_compact_layout():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
g.set_identities(["cam-08", "cam-09", "cam-10", "cam-11", "cam-13"])
assert g.identities == ["cam-08", "cam-09", "cam-10", "cam-11", "cam-13"]
assert (g.cols, g.rows) == (3, 2)
assert g.tile_w > CameraGrid(width=1920, height=1080, cols=5, rows=4).tile_w
g.set_identities(["cam-08", "cam-09"])
assert (g.cols, g.rows) == (2, 1)
assert g.identities == ["cam-08", "cam-09"]
g.set_identities([])
assert g.identities == []
assert (g.cols, g.rows) == (1, 1)
def test_status_overlay_replaces_mosaic_until_cleared():
g = CameraGrid(width=320, height=180, cols=2, rows=1, identities=["cam-01", "cam-02"])
mosaic = g.render()
g.set_status(["LIVEKIT DISCONNECTED", "ws://10.200.0.21:7880", "host unreachable"])
overlay = g.render()
assert overlay != mosaic
assert len(overlay) == 320 * 180 * 4
i420 = g.render_i420()
assert len(i420) == i420_nbytes(320, 180)
g.set_status(None)
assert g.render() == mosaic
def test_format_livekit_status_and_errors():
assert format_livekit_status(url="ws://10.200.0.21:7880", state="connected") == []
connecting = format_livekit_status(url="ws://10.200.0.21:7880", state="connecting")
assert connecting[0] == "CONNECTING TO LIVEKIT"
assert "10.200.0.21:7880" in connecting[1]
lines = format_livekit_status(
url="ws://10.200.0.21:7880",
state="disconnected",
detail="host unreachable",
retry_s=5,
)
assert lines[0] == "LIVEKIT DISCONNECTED"
assert "host unreachable" in lines
assert any("retry" in ln.lower() for ln in lines)
assert "unreachable" in describe_livekit_error(
OSError("No route to host")).lower() or "host" in describe_livekit_error(
OSError("[Errno 113] No route to host")).lower()
assert "timed out" in describe_livekit_error(TimeoutError("timed out")).lower()
assert "refused" in describe_livekit_error(ConnectionRefusedError("Connection refused")).lower()
def test_status_screen_disconnected_uses_composed_layout():
img = status_screen(1920, 1080, [
"LIVEKIT DISCONNECTED",
"ws://10.200.0.21:7880",
"host unreachable",
"retrying in 5s",
])
assert img.shape == (1080, 1920, 4)
assert img.dtype == np.uint8
# Composed: background, accent rail, card — not a flat fill.
assert len(np.unique(img.reshape(-1, 4), axis=0)) > 12
bg = img[24, 80, :3]
card = img[540, 960, :3]
assert tuple(int(x) for x in bg) != tuple(int(x) for x in card)
# Disconnected accent rail is warm amber (BGRA: R > G > B).
stripe = img[540, :8, :3].mean(axis=0)
b, g, r = (float(x) for x in stripe)
assert r > g > b
assert r > 180
def test_status_screen_connecting_uses_cool_accent():
img = status_screen(1920, 1080, [
"CONNECTING TO LIVEKIT",
"ws://10.200.0.21:7880",
])
stripe = img[540, :8, :3].mean(axis=0)
b, g, r = (float(x) for x in stripe)
assert b > r
assert b > 160
+26
View File
@@ -19,3 +19,29 @@ def test_select_three_prefers_xe_hdmi():
assert three[0].name == "HDMI-A-7" or three[0].connected
ids = [o.connector_id for o in three]
assert len(set(ids)) == 3
def test_named_disconnected_falls_back_to_connected_xe():
from drm_outputs import DrmOutput, pick_outputs
wall = DrmOutput(
name="HDMI-A-7", sysfs="card0-HDMI-A-7", node="/dev/dri/card0",
driver="xe", connector_id=538, status="connected", width=3840, height=2160,
)
stale_grid = DrmOutput(
name="HDMI-A-3", sysfs="card1-HDMI-A-3", node="/dev/dri/card1",
driver="i915", connector_id=530, status="disconnected",
)
stale_spk = DrmOutput(
name="HDMI-A-5", sysfs="card0-HDMI-A-5", node="/dev/dri/card0",
driver="xe", connector_id=520, status="disconnected",
)
picked = pick_outputs(
[stale_grid, stale_spk, wall],
n=2,
names=["HDMI-A-3", "HDMI-A-5"],
)
assert len(picked) == 1
assert picked[0].name == "HDMI-A-7"
assert picked[0].connected
assert picked[0].driver == "xe"
+44
View File
@@ -0,0 +1,44 @@
from encode_daemon import _one_enc
def test_h264_uses_igpu_va_not_x264_or_arc_av1():
cmd = _one_enc(640, 368, 30, 2000, 3, 4, "h264", render="/dev/dri/renderD129")
s = " ".join(cmd)
assert "varenderD129h264enc" in cmd
assert "x264enc" not in cmd
assert "vaav1enc" not in cmd
assert "format=nv12" in s
assert "key-int-max=1" in cmd
assert "b-frames=0" in cmd
def test_h264_factory_follows_render_node():
cmd = _one_enc(640, 368, 30, 2000, 3, 4, "h264", render="/dev/dri/renderD128")
assert "varenderD128h264enc" in cmd
def test_c920_stays_fast_gop1():
cmd = _one_enc(640, 368, 30, 2000, 3, 4, "h264", render="/dev/dri/renderD129")
assert "bitrate=2000" in cmd
assert "key-int-max=1" in cmd
assert "target-usage=7" in cmd
def test_rally_1080_uses_higher_bitrate_and_no_motion_trails():
cmd = _one_enc(1920, 1088, 30, 2000, 3, 4, "h264", render="/dev/dri/renderD129")
assert "bitrate=20000" in cmd
assert "key-int-max=1" in cmd
assert "target-usage=2" in cmd
assert "b-frames=0" in cmd
def test_rally_bitrate_rollbacks_via_hi_kbps():
cmd = _one_enc(1920, 1088, 30, 2000, 3, 4, "h264",
render="/dev/dri/renderD129", hi_kbps=12000)
assert "bitrate=12000" in cmd
def test_av1_stays_on_arc_vaav1enc():
cmd = _one_enc(640, 368, 30, 2000, 3, 4, "av1")
assert "vaav1enc" in cmd
assert "varenderD129h264enc" not in cmd
+135
View File
@@ -0,0 +1,135 @@
import os
import threading
import time
import numpy as np
import pytest
def test_frame_roundtrip_stereo_hop():
from enhance_ipc import dump_frame, load_frame
hop = 1600
t = np.arange(hop, dtype=np.int16)
pcm = np.stack([t, t + 1], axis=1)
blob = dump_frame("cam-07", pcm)
ident, out = load_frame(blob)
assert ident == "cam-07"
assert out.dtype == np.int16
assert out.shape == (hop, 2)
np.testing.assert_array_equal(out, pcm)
def test_unix_client_gets_handler_output(tmp_path):
from enhance_daemon import serve_unix
from enhance_ipc import EnhanceClient
sock = str(tmp_path / "enhance.sock")
stop = threading.Event()
def handler(ident, pcm):
assert ident == "cam-03"
# fake "enhance": average channels, invert
if pcm.ndim == 2:
mono = pcm.mean(axis=1)
else:
mono = pcm
return (-mono).astype(np.int16)
t = threading.Thread(target=serve_unix, args=(sock, handler, stop), daemon=True)
t.start()
deadline = time.time() + 2
while time.time() < deadline and not (tmp_path / "enhance.sock").exists():
time.sleep(0.01)
hop = 800
pcm = np.stack([np.full(hop, 1000, np.int16), np.full(hop, 3000, np.int16)], axis=1)
client = EnhanceClient(sock)
try:
out = client.process("cam-03", pcm)
finally:
client.close()
stop.set()
assert out.dtype == np.int16
assert out.shape == (hop,)
assert int(out[0]) == -2000
def _start_echo_daemon(sock, stop):
from enhance_daemon import serve_unix
def handler(ident, pcm):
if pcm.ndim == 2:
mono = pcm.mean(axis=1)
else:
mono = pcm
return np.asarray(mono, dtype=np.int16)
t = threading.Thread(target=serve_unix, args=(sock, handler, stop), daemon=True)
t.start()
deadline = time.time() + 2
while time.time() < deadline and not os.path.exists(sock):
time.sleep(0.01)
return t
def test_audio_cleaner_remote_does_not_load_model(tmp_path):
from audio_cleanup import AudioCleaner
sock = str(tmp_path / "enhance.sock")
stop = threading.Event()
_start_echo_daemon(sock, stop)
try:
c = AudioCleaner(
mode="force", beamform="force", enhance_socket=sock,
identity="cam-09")
assert c._enhancer is None
assert c._beamformer is None
assert c.backend == "daemon"
hop = 1600
stereo = np.stack([
np.full(hop, 400, np.int16),
np.full(hop, 800, np.int16),
], axis=1)
out = c.process(stereo)
assert out.shape == (hop,)
assert out.dtype == np.int16
assert int(out[0]) == 600
finally:
stop.set()
def test_shared_engine_constructs_one_cleaner_for_two_cams():
from audio_cleanup import AudioCleaner
from enhance_daemon import SharedEnhanceEngine
n = {"c": 0}
def make():
n["c"] += 1
return AudioCleaner(mode="off", beamform="off")
eng = SharedEnhanceEngine(make_cleaner=make)
hop = np.zeros(800, dtype=np.int16)
out_a = eng.process("cam-01", hop)
out_b = eng.process("cam-02", hop)
out_a2 = eng.process("cam-01", hop)
assert n["c"] == 1
assert set(eng.identities()) == {"cam-01", "cam-02"}
assert out_a.shape == (800,)
assert out_b.shape == (800,)
assert out_a2.shape == (800,)
def test_wait_for_socket_false_then_true(tmp_path):
from enhance_daemon import wait_for_socket, serve_unix
sock = str(tmp_path / "missing.sock")
assert wait_for_socket(sock, timeout=0.15) is False
stop = threading.Event()
t = threading.Thread(
target=serve_unix, args=(sock, lambda i, p: p, stop), daemon=True)
t.start()
try:
assert wait_for_socket(sock, timeout=2.0) is True
finally:
stop.set()
+23
View File
@@ -0,0 +1,23 @@
from frame_shm import LatestFrameReader, LatestFrameWriter, frame_bytes
def test_latest_frame_roundtrip(tmp_path):
path = str(tmp_path / "cam-01.i420")
w, h = 16, 16
n = frame_bytes(w, h)
writer = LatestFrameWriter(path, w, h)
payload = bytes(range(256)) * (n // 256 + 1)
payload = payload[:n]
seq = writer.write(payload)
assert seq == 1
reader = LatestFrameReader(path)
got = reader.latest()
assert got is not None
assert got[0] == 1
assert got[1] == payload
seq2 = writer.write(bytes([3]) * n)
got2 = reader.latest()
assert got2 is not None
assert got2[0] == seq2
assert got2[1][0] == 3
writer.close()
+66
View File
@@ -0,0 +1,66 @@
from display_grid import CameraGrid
from drm_outputs import DrmOutput
from gst_sink import appsrc_cmd, va_grid_cmd
def _out():
return DrmOutput(
name="HDMI-A-7",
sysfs="card0-HDMI-A-7",
node="/dev/dri/card0",
driver="xe",
connector_id=538,
status="connected",
)
def test_appsrc_queue_buffers_default_two():
cmd = appsrc_cmd(_out(), 1920, 1080, 30)
assert "max-size-buffers=2" in cmd
def test_appsrc_queue_buffers_one():
cmd = appsrc_cmd(_out(), 1920, 1080, 30, queue_buffers=1)
assert "max-size-buffers=1" in cmd
assert "max-size-buffers=2" not in cmd
def test_appsrc_i420_blocksize():
cmd = appsrc_cmd(_out(), 1920, 1080, 30, pixel_format="i420")
joined = " ".join(cmd)
assert "format=i420" in joined
assert "blocksize=3110400" in joined # 1920*1080*3//2
assert "format=bgra" not in joined
def test_va_grid_cmd_pins_arc_compositor_and_twenty_tiles():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
tile_fds = list(range(4, 24))
cmd = va_grid_cmd(
_out(), g, ingest_w=640, ingest_h=360, fps=15,
tile_fds=tile_fds, chrome_fd=3, queue_buffers=1)
joined = " ".join(cmd)
assert "varenderD129compositor" in joined
assert "varenderD129postproc" in joined
assert "kmssink" in joined
assert "connector-id=538" in joined
assert "driver-name=xe" in joined
assert joined.count("fdsrc") == 21 # chrome + 20 tiles
x, y, w, h = g.inner_rect(0)
assert f"xpos={x}" in joined
assert f"ypos={y}" in joined
assert "format=i420" in joined
assert "blocksize=345600" in joined # 640*360*1.5
def test_va_grid_cmd_h264_uses_arc_decoder():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
paths = [f"/tmp/cam-{i:02d}.h264" for i in range(1, 21)]
cmd = va_grid_cmd(
_out(), g, ingest_w=640, ingest_h=360, fps=15,
tile_h264_paths=paths, chrome_fd=3)
joined = " ".join(cmd)
assert "varenderD129h264dec" in joined
assert joined.count("h264parse") == 20
assert "fdsrc" in joined # chrome only
assert joined.count("filesrc") == 20
+30
View File
@@ -0,0 +1,30 @@
import os
import stat
from h264_fifo import hold_fifo
def test_hold_fifo_creates_rdwr_pipe(tmp_path):
path = str(tmp_path / "cam-01.h264")
fd = hold_fifo(path)
try:
st = os.stat(path)
assert stat.S_ISFIFO(st.st_mode)
os.write(fd, b"\x00\x01")
assert os.read(fd, 2) == b"\x00\x01"
finally:
os.close(fd)
def test_hold_fifo_does_not_replace_existing_fifo(tmp_path):
path = str(tmp_path / "cam-02.h264")
a = hold_fifo(path)
ino = os.stat(path).st_ino
b = hold_fifo(path)
try:
assert os.stat(path).st_ino == ino
os.write(a, b"ab")
assert os.read(b, 2) == b"ab"
finally:
os.close(a)
os.close(b)
+171
View File
@@ -0,0 +1,171 @@
"""Hand-raise rule, latch, and yellow I420 chrome."""
import time
import numpy as np
from display_grid import FRAME_RAISE, CameraGrid, bgra_to_i420, i420_nbytes
from hand_raise import RaiseLatch, letterbox_rgb, wrist_is_raised
def _kpts() -> np.ndarray:
k = np.zeros((17, 3), dtype=np.float32)
k[:, 2] = 0.8
k[0] = [0.35, 0.50, 0.9] # nose
k[5] = [0.50, 0.35, 0.9] # L shoulder
k[6] = [0.50, 0.65, 0.9] # R shoulder
k[7] = [0.62, 0.30, 0.9] # L elbow
k[8] = [0.62, 0.70, 0.9]
k[9] = [0.70, 0.28, 0.9] # L wrist down
k[10] = [0.70, 0.72, 0.9]
return k
def test_wrist_down_is_not_raised():
assert wrist_is_raised(_kpts()) is False
def test_left_wrist_above_shoulder_is_raised():
k = _kpts()
k[7] = [0.32, 0.30, 0.9] # elbow up
k[9] = [0.18, 0.32, 0.9] # wrist above shoulder (y 0.50)
assert wrist_is_raised(k) is True
def test_modest_wrist_lift_is_raised():
"""Webcam framing: hand just above the shoulder still counts."""
k = _kpts()
k[7] = [0.46, 0.30, 0.9]
k[9] = [0.43, 0.32, 0.9] # 0.07 above shoulder y=0.50
assert wrist_is_raised(k) is True
def test_wrist_on_face_rejected():
k = _kpts()
k[7] = [0.38, 0.48, 0.9]
k[9] = [0.28, 0.50, 0.9] # up, but next to the nose
assert wrist_is_raised(k) is False
def test_wrist_above_head_without_shoulders():
"""Close-up webcam: shoulders off-frame, hand still clearly up."""
k = np.zeros((17, 3), dtype=np.float32)
k[0] = [0.55, 0.50, 0.85] # nose
k[9] = [0.18, 0.62, 0.7] # wrist high, not on the face
assert wrist_is_raised(k) is True
def test_low_score_not_raised():
k = _kpts()
k[:, 2] = 0.05
assert wrist_is_raised(k) is False
assert wrist_is_raised(np.zeros((17, 3), dtype=np.float32)) is False
def test_raise_latch_needs_hits_then_holds():
latch = RaiseLatch(hits=2, hold_s=0.4, window=2)
t = 10.0
assert latch.update(True, t) is False
assert latch.update(True, t + 0.1) is True
assert latch.update(False, t + 0.2) is True
assert latch.update(False, t + 0.55) is False
def test_raise_latch_survives_one_miss():
latch = RaiseLatch(hits=3, hold_s=1.0, window=5)
t = 10.0
assert latch.update(True, t) is False
assert latch.update(True, t + 0.1) is False
assert latch.update(False, t + 0.2) is False
assert latch.update(True, t + 0.3) is True
assert latch.update(True, t + 0.4) is True
assert latch.update(False, t + 0.5) is True
def test_letterbox_rgb_pads_16x9():
rgb = np.full((360, 640, 3), 200, dtype=np.uint8)
out = letterbox_rgb(rgb, 192)
assert out.shape == (192, 192, 3)
assert int(out[0, 96, 0]) == 0
assert int(out[96, 96, 0]) == 200
thunder = letterbox_rgb(rgb, 256)
assert thunder.shape == (256, 256, 3)
def test_resolve_movenet_thunder_is_256():
from pathlib import Path
from hand_raise import resolve_movenet
path, size, name = resolve_movenet("thunder")
assert name == "thunder"
assert size == 256
assert path.name == "movenet_singlepose_thunder.onnx"
path, size, name = resolve_movenet("lightning")
assert name == "lightning" and size == 192
assert Path(path).name == "movenet_singlepose_lightning.onnx"
def test_set_highlight_paints_yellow_i420_border():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
src = np.zeros((360, 640, 4), dtype=np.uint8)
src[:] = (40, 40, 40, 255)
g.set_frame_i420("cam-07", bgra_to_i420(src), 640, 360)
before = np.frombuffer(g.render_i420(), dtype=np.uint8).copy()
g.set_highlight("cam-07", True)
assert g.highlighted("cam-07") is True
after = np.frombuffer(g.render_i420(), dtype=np.uint8)
assert not np.array_equal(before, after)
idx = g.identities.index("cam-07")
ox, oy = g.tile_origin(idx)
yplane = after[: g.width * g.height].reshape(g.height, g.width)
yv, _, _ = g._yuv_raise
# Top edge of the tile chrome should be yellow-luma, not gray live.
assert int(yplane[oy, ox + g.tile_w // 2]) == yv
assert int(yplane[oy - 2, ox + g.tile_w // 2]) == yv
ix, iy, iw, _ih = g.inner_rect(idx)
assert int(yplane[iy, ix + iw // 2]) != yv
g.set_highlight("cam-07", False)
assert g.highlighted("cam-07") is False
restored = np.frombuffer(g.render_i420(), dtype=np.uint8)
assert int(restored[: g.width * g.height].reshape(g.height, g.width)[oy, ox + g.tile_w // 2]) != yv
def test_clear_drops_yellow():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
src = np.zeros((360, 640, 4), dtype=np.uint8)
g.set_frame_i420("cam-01", bgra_to_i420(src), 640, 360)
g.set_highlight("cam-01", True)
g.clear("cam-01")
assert g.highlighted("cam-01") is False
assert len(g.render_i420()) == i420_nbytes(1920, 1080)
def test_fp32_movenet_sees_person_not_raised():
"""INT8 Xenova weights scored ~0.05 on a real person; FP32 must lock on."""
from pathlib import Path
from hand_raise import HandRaiseMonitor, MODEL_PATH
fixture = Path(__file__).parent / "fixtures" / "movenet_warrior_192.npy"
assert MODEL_PATH.name == "movenet_singlepose_lightning.onnx"
rgb = np.load(fixture)
mon = HandRaiseMonitor(enabled=True, model="lightning")
assert mon.enabled
k = mon.infer_rgb(rgb)
assert float(k[:, 2].max()) > 0.4
assert float(k[0, 2]) > 0.3 # nose
assert wrist_is_raised(k) is False # warrior: arms out, not up
def test_fp32_thunder_sees_person_not_raised():
from pathlib import Path
from hand_raise import HandRaiseMonitor, resolve_movenet
path, size, name = resolve_movenet("thunder")
assert path.is_file()
assert size == 256 and name == "thunder"
rgb = np.load(Path(__file__).parent / "fixtures" / "movenet_warrior_192.npy")
mon = HandRaiseMonitor(enabled=True, model="thunder")
assert mon.enabled
assert mon._input_size == 256
k = mon.infer_rgb(rgb)
assert float(k[:, 2].max()) > 0.4
assert float(k[0, 2]) > 0.3
assert wrist_is_raised(k) is False
+47
View File
@@ -0,0 +1,47 @@
from hop_shm import HopReader, HopWriter, hop_bytes
def test_hop_ring_preserves_order(tmp_path):
path = str(tmp_path / "cam-01.pcm")
n = hop_bytes(16000, 2, 0.1)
w = HopWriter(path, n, nslots=4)
r = HopReader(path)
for i in range(3):
payload = bytes([i]) * n
w.write(payload)
got = [r.read() for _ in range(3)]
assert got[0] is not None and got[0][0] == 0
assert got[1] is not None and got[1][0] == 1
assert got[2] is not None and got[2][0] == 2
assert r.read() is None
w.close()
def test_hop_ring_skips_when_reader_lags(tmp_path):
path = str(tmp_path / "cam-01.pcm")
n = 32
w = HopWriter(path, n, nslots=4)
r = HopReader(path)
for i in range(10):
w.write(bytes([i]) * n)
last = r.read()
assert last is not None
w.close()
def test_reader_follows_writer_restart(tmp_path):
"""Cameras-only restart zeros seq; the wall must not stay stuck on _last."""
path = str(tmp_path / "cam-01.pcm")
n = 32
w = HopWriter(path, n, nslots=4)
r = HopReader(path)
for i in range(8):
w.write(bytes([i]) * n)
assert r.read() is not None
w.close()
w2 = HopWriter(path, n, nslots=4)
w2.write(bytes([99]) * n)
got = r.read()
assert got is not None and got[0] == 99
assert r.read() is None
w2.close()
+56
View File
@@ -0,0 +1,56 @@
from i420_nv12 import (
coded_dim,
drop_va_pad_i420,
i420_to_nv12_into,
nv12_bytes,
va_visible_height,
)
def test_coded_dim_pads_up():
assert coded_dim(360) == 368
assert coded_dim(1080) == 1088
assert coded_dim(640) == 640
assert coded_dim(352) == 352
def test_i420_to_nv12_pads_last_row():
w, h = 640, 360
ysz = w * h
uv = (w // 2) * (h // 2)
src = bytearray(ysz + 2 * uv)
src[:ysz] = b"\x80" * ysz
src[(h - 1) * w:ysz] = b"\x90" * w
src[ysz:ysz + uv] = b"\x40" * uv
src[ysz + uv:] = b"\xc0" * uv
cw, ch = 640, 368
out = bytearray(nv12_bytes(cw, ch))
n = i420_to_nv12_into(src, w, h, out)
assert n == nv12_bytes(cw, ch)
assert out[0] == 0x80
# cloned pad rows 360-367
assert out[360 * cw] == 0x90
assert out[367 * cw] == 0x90
assert out[cw * ch] == 0x40
assert out[cw * ch + 1] == 0xc0
def test_drop_va_pad_restores_360():
w, h = 640, 368
vis = 360
ysz = w * h
uv = (w // 2) * (h // 2)
src = bytearray(ysz + 2 * uv)
src[: w * vis] = b"\x77" * (w * vis)
src[w * vis:ysz] = b"\x11" * (w * 8)
out, ow, oh = drop_va_pad_i420(src, w, h)
assert (ow, oh) == (w, vis)
assert len(out) == w * vis * 3 // 2
assert out[0] == 0x77
assert 0x11 not in out[: w * vis]
def test_va_visible_height():
assert va_visible_height(640, 368) == 360
assert va_visible_height(1920, 1088) == 1080
assert va_visible_height(640, 360) == 360
assert va_visible_height(640, 352) == 352
+99
View File
@@ -0,0 +1,99 @@
from capture_va import (
crop_scale_i420_drop_bottom,
jpeg_mcu_bottom_crop,
needs_jpeg_mcu_fix,
repeat_i420_bottom_from_last_good,
)
def _i420(width, height, y=16, u=128, v=128):
y_size = width * height
uv = (width // 2) * (height // 2)
buf = bytearray(y_size + 2 * uv)
buf[:y_size] = bytes([y]) * y_size
buf[y_size:y_size + uv] = bytes([u]) * uv
buf[y_size + uv:] = bytes([v]) * uv
return buf
def test_repeat_clones_last_good_y_and_chroma_over_black_pad():
w, h, crop = 640, 360, 8
buf = _i420(w, h, y=16, u=128, v=128)
last_good = h - crop - 1
y_stride = w
# last good Y row = 90; last good UV row = 40 (chroma 4:2:0)
src = last_good * y_stride
buf[src:src + y_stride] = bytes([90]) * y_stride
uv_w = w // 2
uv_h = h // 2
uv_crop = crop // 2
last_uv = uv_h - uv_crop - 1
y_size = w * h
u0 = y_size + last_uv * uv_w
v0 = y_size + uv_w * uv_h + last_uv * uv_w
buf[u0:u0 + uv_w] = bytes([40]) * uv_w
buf[v0:v0 + uv_w] = bytes([200]) * uv_w
repeat_i420_bottom_from_last_good(buf, w, h, crop)
for r in range(h - crop, h):
row = buf[r * y_stride:(r + 1) * y_stride]
assert set(row) == {90}, r
for r in range(uv_h - uv_crop, uv_h):
u = buf[y_size + r * uv_w:y_size + (r + 1) * uv_w]
v = buf[y_size + uv_w * uv_h + r * uv_w:
y_size + uv_w * uv_h + (r + 1) * uv_w]
assert set(u) == {40}, r
assert set(v) == {200}, r
# rows above the pad stay put
mid = (h // 2) * y_stride
assert set(buf[mid:mid + y_stride]) == {16}
def test_360p_crops_partial_mcu_and_last_full_mcu():
"""360 % 16 = 8 leftover; last full 16-row MCU is also garbage on 07/14/15."""
assert jpeg_mcu_bottom_crop(360) == 24
assert jpeg_mcu_bottom_crop(480) == 0
assert jpeg_mcu_bottom_crop(352) == 0
assert jpeg_mcu_bottom_crop(8) == 0
buf = _i420(640, 480, y=77)
before = bytes(buf)
repeat_i420_bottom_from_last_good(buf, 640, 480, jpeg_mcu_bottom_crop(480))
assert bytes(buf) == before
def test_mcu_fix_cams_off():
assert not needs_jpeg_mcu_fix("cam-07")
assert not needs_jpeg_mcu_fix("cam-12")
assert not needs_jpeg_mcu_fix("cam-14")
assert not needs_jpeg_mcu_fix("cam-15")
assert not needs_jpeg_mcu_fix("cam-01")
assert not needs_jpeg_mcu_fix("cam-20")
def test_crop_scale_drops_garbage_without_cloned_stripe():
w, h = 640, 360
crop = 24
buf = _i420(w, h, y=40, u=100, v=140)
y_size = w * h
# garbage last 24 Y rows
buf[(h - crop) * w:y_size] = bytes([250]) * (crop * w)
out = crop_scale_i420_drop_bottom(buf, w, h, crop)
assert len(out) == len(buf)
y = memoryview(out)[:y_size]
last = bytes(y[(h - 8) * w:h * w])
assert last.count(250) == 0
assert set(last) == {16}
def test_live_path_clones_not_studio_black():
w, h, crop = 640, 360, 24
buf = _i420(w, h, y=40, u=100, v=140)
last_good = h - crop - 1
buf[last_good * w:(last_good + 1) * w] = bytes([90]) * w
buf[(h - crop) * w:h * w] = bytes([250]) * (crop * w)
repeat_i420_bottom_from_last_good(buf, w, h, crop)
visible = bytes(buf[(h - crop) * w:h * w])
assert set(visible) == {90}
assert 16 not in visible
assert 250 not in visible
+64
View File
@@ -0,0 +1,64 @@
"""Env-flagged low-latency knobs (hop/queue, hold, enhance scope)."""
from latency import (
audio_queue_size_ms,
effective_enhance_mode,
video_hold_seconds,
video_stream_kwargs,
)
def test_audio_queue_defaults_to_legacy_floor():
assert audio_queue_size_ms(0.1, audio_queue_ms=None) == 150
assert audio_queue_size_ms(0.2, audio_queue_ms=None) == 250
def test_audio_queue_env_overrides_floor():
assert audio_queue_size_ms(0.1, audio_queue_ms=60) == 60
assert audio_queue_size_ms(0.05, audio_queue_ms=60) == 60
def test_video_hold_matches_hop_when_audio_present():
assert video_hold_seconds(0.1, has_audio=True, video_hold_s=None) == 0.1
assert video_hold_seconds(0.05, has_audio=True, video_hold_s=None) == 0.05
def test_video_hold_zero_without_audio():
assert video_hold_seconds(0.1, has_audio=False, video_hold_s=None) == 0.0
assert video_hold_seconds(0.1, has_audio=False, video_hold_s=0.2) == 0.0
def test_video_hold_env_overrides_including_zero():
assert video_hold_seconds(0.1, has_audio=True, video_hold_s=0.0) == 0.0
assert video_hold_seconds(0.1, has_audio=True, video_hold_s=0.05) == 0.05
def test_enhance_speaker_only_rally_disables_c920s():
assert effective_enhance_mode(
"auto", "cam-01", speaker_only=True, speaker_camera="rally",
) == "off"
assert effective_enhance_mode(
"auto", "rally", speaker_only=True, speaker_camera="rally",
) == "auto"
def test_enhance_speaker_only_inactive_leaves_mode():
assert effective_enhance_mode(
"auto", "cam-07", speaker_only=False, speaker_camera="cam-01",
) == "auto"
def test_enhance_speaker_only_ignored_when_speaker_is_active():
assert effective_enhance_mode(
"auto", "cam-07", speaker_only=True, speaker_camera="active",
) == "auto"
def test_video_stream_legacy_unbounded_native():
assert video_stream_kwargs(capacity=0, format_name="") == {}
def test_video_stream_latest_bgra():
assert video_stream_kwargs(capacity=1, format_name="bgra") == {
"capacity": 1,
"format": "bgra",
}
+46
View File
@@ -0,0 +1,46 @@
"""Latest-AU H.264 mmap: overwrite unread payloads; seq is monotonic."""
from nal_shm import AU_MAX, NalReader, NalWriter
def test_writer_seq_starts_at_one_and_increments(tmp_path):
path = str(tmp_path / "cam-01.h264")
w = NalWriter(path, max_payload=64)
assert w.write(b"\x00\x00\x00\x01\x65" + b"x" * 10) == 1
assert w.write(b"\x00\x00\x00\x01\x41" + b"y" * 10) == 2
w.close()
def test_reader_returns_latest_payload(tmp_path):
path = str(tmp_path / "cam-01.h264")
w = NalWriter(path, max_payload=64)
w.write(b"first-access-unit-xxxx")
w.write(b"second-access-unit-yyy")
r = NalReader(path)
seq, payload = r.read()
assert seq == 2
assert payload.startswith(b"second-access-unit")
w.close()
r.close()
def test_reader_none_when_no_new_au(tmp_path):
path = str(tmp_path / "cam-01.h264")
w = NalWriter(path, max_payload=64)
w.write(b"only-once")
r = NalReader(path)
assert r.read()[0] == 1
assert r.read() is None
w.close()
r.close()
def test_write_drops_oversize_payload(tmp_path):
path = str(tmp_path / "cam-01.h264")
w = NalWriter(path, max_payload=8)
assert w.write(b"123456789") == 0
w.close()
def test_au_max_is_bounded():
assert AU_MAX >= 64 * 1024
assert AU_MAX <= 2 * 1024 * 1024
+88
View File
@@ -0,0 +1,88 @@
from participant_tags import (
should_hide_participant,
tags_from_fields,
token_attributes,
want_display_video,
)
def test_tags_from_attribute_tag():
assert tags_from_fields({"tag": "uwh"}, "") == {"uwh"}
def test_tags_from_comma_separated_tags_attr():
assert tags_from_fields({"tags": "uwh,lab"}, None) == {"uwh", "lab"}
def test_tags_from_json_metadata():
assert tags_from_fields({}, '{"tag": "uwh"}') == {"uwh"}
def test_hide_disabled_when_hide_tags_empty():
assert should_hide_participant({"tag": "uwh"}, "", []) is False
def test_hide_uwh_when_filter_enabled():
assert should_hide_participant({"tag": "uwh"}, "", ["uwh"]) is True
assert should_hide_participant({"tag": "nyc"}, "", ["uwh"]) is False
assert should_hide_participant({}, "", ["uwh"]) is False
def test_token_attributes_sets_tag_and_tags():
assert token_attributes(["uwh"]) == {"tag": "uwh", "tags": "uwh"}
assert token_attributes([]) == {}
def test_want_display_keeps_cameras_when_filter_off():
assert want_display_video(
identity="cam-01",
attributes={"tag": "uwh"},
metadata="",
hide_tags=[],
participant_prefix="cam",
display_identity="display-wall",
) is True
assert want_display_video(
identity="alice",
attributes={},
metadata="",
hide_tags=[],
participant_prefix="cam",
display_identity="display-wall",
) is False
assert want_display_video(
identity="rally",
attributes={},
metadata="",
hide_tags=[],
participant_prefix="cam",
display_identity="display-wall",
speaker_identity="rally",
) is True
assert want_display_video(
identity="rally",
attributes={},
metadata="",
hide_tags=[],
participant_prefix="cam",
display_identity="display-wall",
) is False
def test_want_display_hides_uwh_and_shows_remote_when_filter_on():
assert want_display_video(
identity="cam-01",
attributes={"tag": "uwh"},
metadata="",
hide_tags=["uwh"],
participant_prefix="cam",
display_identity="display-wall",
) is False
assert want_display_video(
identity="alice",
attributes={"tag": "nyc"},
metadata="",
hide_tags=["uwh"],
participant_prefix="cam",
display_identity="display-wall",
) is True
+209
View File
@@ -0,0 +1,209 @@
"""Person-aware background blur: composite, hold, I420, encode path."""
import numpy as np
from portrait import (
MaskHold,
apply_i420,
apply_portrait,
bgr_to_i420,
composite_bgr,
i420_nbytes,
i420_source_path,
i420_to_bgr,
person_present,
soft_blur_bgr,
)
def _checker(h: int, w: int) -> np.ndarray:
img = np.zeros((h, w, 3), dtype=np.uint8)
img[::4, :] = 255
img[:, ::4] = 255
return img
def test_composite_keeps_person_pixels():
h, w = 80, 128
bg = _checker(h, w)
person = bg.copy()
person[16:64, 32:96] = (40, 180, 40)
mask = np.zeros((h, w), dtype=np.float32)
mask[16:64, 32:96] = 1.0
out = composite_bgr(person, soft_blur_bgr(person, 9), mask)
roi = out[24:56, 40:88]
assert abs(int(roi[:, :, 1].mean()) - 180) < 8
assert abs(int(roi[:, :, 0].mean()) - 40) < 8
def test_composite_blurs_background_checker():
h, w = 80, 128
bg = _checker(h, w)
person = bg.copy()
person[16:64, 32:96] = (40, 180, 40)
mask = np.zeros((h, w), dtype=np.float32)
mask[16:64, 32:96] = 1.0
sharp_var = float(bg[0:12, :].var())
out = composite_bgr(person, soft_blur_bgr(person, 9), mask)
blur_var = float(out[0:12, :].var())
assert sharp_var > 1000
assert blur_var < sharp_var * 0.5
def test_empty_mask_is_fully_blurred():
img = _checker(40, 64)
mask = np.zeros((40, 64), dtype=np.float32)
out = apply_portrait(img, mask)
assert person_present(mask) is False
assert float(out.var()) < float(img.var()) * 0.5
assert not np.array_equal(out, img)
def test_tiny_blob_is_not_a_person():
mask = np.zeros((40, 64), dtype=np.float32)
mask[10:12, 10:12] = 0.9
assert person_present(mask) is False
def test_mask_hold_keeps_last_on_miss():
hold = MaskHold(hold_s=0.5, ema=1.0)
mask = np.ones((8, 8), dtype=np.float32)
got = hold.update(mask, True, 1.0)
assert got is not None
missed = hold.update(None, False, 1.2)
assert missed is not None
assert float(missed.mean()) == 1.0
assert hold.update(None, False, 1.6) is None
def test_ema_smooths_mask_flicker():
hold = MaskHold(hold_s=1.0, ema=0.5)
a = np.zeros((4, 4), dtype=np.float32)
b = np.ones((4, 4), dtype=np.float32)
hold.update(a, True, 0.0)
out = hold.update(b, True, 0.1)
assert 0.4 < float(out.mean()) < 0.6
def test_i420_roundtrip_keeps_640x360():
w, h = 640, 360
bgr = np.zeros((h, w, 3), dtype=np.uint8)
bgr[20:200, 80:400] = (30, 90, 200)
payload = bgr_to_i420(bgr)
assert len(payload) == i420_nbytes(w, h)
mask = np.zeros((h, w), dtype=np.float32)
mask[20:200, 80:400] = 1.0
out = apply_i420(payload, w, h, mask, radius=9)
assert len(out) == i420_nbytes(w, h)
back = i420_to_bgr(out, w, h)
assert back.shape == (h, w, 3)
def test_missing_mask_blurs_whole_frame():
w, h = 48, 32
bgr = _checker(h, w)
payload = bgr_to_i420(bgr)
out = apply_i420(payload, w, h, None, radius=7)
y0 = np.frombuffer(payload, dtype=np.uint8, count=w * h).reshape(h, w)
y1 = np.frombuffer(out, dtype=np.uint8, count=w * h).reshape(h, w)
assert float(y1.var()) < float(y0.var()) * 0.6
def test_apply_i420_blurs_y_background():
w, h = 64, 48
bgr = np.zeros((h, w, 3), dtype=np.uint8)
bgr[::3, :] = 255
bgr[:, ::3] = 255
bgr[8:40, 16:48] = (20, 200, 20)
payload = bgr_to_i420(bgr)
mask = np.zeros((h, w), dtype=np.float32)
mask[8:40, 16:48] = 1.0
out = apply_i420(payload, w, h, mask, radius=9)
y0 = np.frombuffer(payload, dtype=np.uint8, count=w * h).reshape(h, w)
y1 = np.frombuffer(out, dtype=np.uint8, count=w * h).reshape(h, w)
assert float(y1[0:6, :].var()) < float(y0[0:6, :].var()) * 0.6
assert abs(int(y1[12:36, 20:44].mean()) - int(y0[12:36, 20:44].mean())) < 12
def test_c920_uses_portrait_dir_rally_stays_raw():
assert i420_source_path("cam-01", "/run/raw", "/run/por") == "/run/por/cam-01.i420"
assert i420_source_path("cam-15", "/run/raw", "/run/por") == "/run/por/cam-15.i420"
assert i420_source_path("rally", "/run/raw", "/run/por") == "/run/raw/rally.i420"
assert i420_source_path("cam-01", "/run/raw", "") == "/run/raw/cam-01.i420"
def test_letterbox_mask_maps_back_to_16x9():
from portrait import letterbox_bgr, unletterbox_mask
bgr = np.zeros((360, 640, 3), dtype=np.uint8)
canvas, box = letterbox_bgr(bgr, 256)
assert canvas.shape == (256, 256, 3)
x0, y0, nw, nh = box
assert nw > nh
m = np.zeros((256, 256), dtype=np.float32)
cy, cx = y0 + nh // 2, x0 + nw // 2
m[cy - 2:cy + 3, cx - 2:cx + 3] = 1.0
full = unletterbox_mask(m, box, 360, 640)
assert full.shape == (360, 640)
assert float(full[180, 320]) > 0.5
assert float(full[2, 2]) < 0.1
def test_selfie_cpu_sees_warrior_not_empty():
import cv2
from pathlib import Path
from portrait import PersonSeg
rgb = np.load(Path(__file__).parent / "fixtures" / "movenet_warrior_192.npy")
bgr = cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR)
seg = PersonSeg()
assert seg.device == "CPU"
mask = seg.infer_bgr(bgr)
assert person_present(mask)
empty = np.full((360, 640, 3), 40, dtype=np.uint8)
assert person_present(seg.infer_bgr(empty)) is False
def test_pose_protect_keeps_wrists_and_face():
from portrait import pose_protect_mask
k = np.zeros((17, 3), dtype=np.float32)
k[0] = [0.30, 0.50, 0.9] # nose
k[9] = [0.12, 0.18, 0.9] # L wrist
k[10] = [0.12, 0.82, 0.9] # R wrist
m = pose_protect_mask(100, 200, k)
assert float(m[12, 36]) > 0.7
assert float(m[12, 164]) > 0.7
assert float(m[30, 100]) > 0.7
assert float(m[90, 10]) < 0.2
def test_union_masks_keeps_face_and_body():
from portrait import union_masks
body = np.zeros((40, 40), dtype=np.float32)
body[20:36, 10:30] = 1.0
face = np.zeros((40, 40), dtype=np.float32)
face[4:14, 14:26] = 1.0
out = union_masks(body, face)
assert float(out[8, 20]) == 1.0
assert float(out[28, 20]) == 1.0
assert float(out[2, 2]) == 0.0
def test_lighter_blur_keeps_more_background_detail():
w, h = 64, 48
bgr = np.zeros((h, w, 3), dtype=np.uint8)
bgr[::3, :] = 255
bgr[:, ::3] = 255
payload = bgr_to_i420(bgr)
mask = np.zeros((h, w), dtype=np.float32)
mask[8:40, 16:48] = 1.0
heavy = apply_i420(payload, w, h, mask, radius=15)
light = apply_i420(payload, w, h, mask, radius=7)
y0 = np.frombuffer(payload, dtype=np.uint8, count=w * h).reshape(h, w)
yh = np.frombuffer(heavy, dtype=np.uint8, count=w * h).reshape(h, w)
yl = np.frombuffer(light, dtype=np.uint8, count=w * h).reshape(h, w)
bg0 = float(y0[0:6, :].var())
assert float(yl[0:6, :].var()) > float(yh[0:6, :].var())
assert float(yl[0:6, :].var()) < bg0
+87
View File
@@ -0,0 +1,87 @@
"""SHM round-trip for portrait daemon with a fake mask."""
import time
import numpy as np
from frame_shm import LatestFrameReader, LatestFrameWriter, wait_for_ready
from portrait import bgr_to_i420, i420_nbytes, i420_to_bgr, person_present
from portrait_daemon import CamSlot, tick_once
def test_tick_blurs_bg_and_keeps_person(tmp_path):
w, h = 64, 48
bgr = np.zeros((h, w, 3), dtype=np.uint8)
bgr[::3, :] = 255
bgr[:, ::3] = 255
bgr[8:40, 16:48] = (20, 200, 20)
payload = bgr_to_i420(bgr)
src = tmp_path / "raw" / "cam-01.i420"
dst = tmp_path / "por" / "cam-01.i420"
writer = LatestFrameWriter(str(src), w, h)
writer.write(payload)
mask = np.zeros((h, w), dtype=np.float32)
mask[8:40, 16:48] = 1.0
def infer(_bgr):
return mask
slot = CamSlot(
identity="cam-01",
width=w,
height=h,
reader=LatestFrameReader(str(src)),
writer=LatestFrameWriter(str(dst), w, h),
infer_hz=30.0,
hold_s=0.8,
blur_px=9,
)
n = tick_once([slot], infer, time.monotonic(), infer_budget_s=0.05)
assert n == 1
out_r = LatestFrameReader(str(dst))
buf = bytearray(i420_nbytes(w, h))
seq = out_r.copy_into(buf)
assert seq == 1
out = i420_to_bgr(buf, w, h)
roi = out[12:36, 20:44]
assert abs(int(roi[:, :, 1].mean()) - 200) < 25
bg = out[0:6, :]
assert float(bg.var()) < float(bgr[0:6, :].var()) * 0.6
def test_tick_blurs_when_empty(tmp_path):
w, h = 32, 32
bgr = np.zeros((h, w, 3), dtype=np.uint8)
bgr[::3, :] = 255
bgr[:, ::3] = 255
payload = bgr_to_i420(bgr)
src = tmp_path / "raw" / "cam-02.i420"
dst = tmp_path / "por" / "cam-02.i420"
LatestFrameWriter(str(src), w, h).write(payload)
def infer(_bgr):
return np.zeros((h, w), dtype=np.float32)
slot = CamSlot(
identity="cam-02",
width=w,
height=h,
reader=LatestFrameReader(str(src)),
writer=LatestFrameWriter(str(dst), w, h),
infer_hz=30.0,
hold_s=0.2,
blur_px=9,
)
tick_once([slot], infer, time.monotonic(), infer_budget_s=0.05)
buf = bytearray(i420_nbytes(w, h))
assert LatestFrameReader(str(dst)).copy_into(buf) == 1
y0 = np.frombuffer(payload, dtype=np.uint8, count=w * h).reshape(h, w)
y1 = np.frombuffer(buf, dtype=np.uint8, count=w * h).reshape(h, w)
assert float(y1.var()) < float(y0.var()) * 0.6
assert person_present(np.zeros((h, w), dtype=np.float32)) is False
def test_wait_ready_helper(tmp_path):
p = tmp_path / "ready"
assert wait_for_ready(str(p), timeout=0.05) is False
p.write_text("ok\n")
assert wait_for_ready(str(p), timeout=0.2) is True
+36
View File
@@ -0,0 +1,36 @@
import pytest
from pathlib import Path
from discovery import Camera
from rally import dante_capture_card, discover_rally, rally_video_node
from run import fleet_cameras
from usb_ids import RALLY_IDENTITY
_HAVE_RALLY = rally_video_node() is not None
@pytest.mark.skipif(not _HAVE_RALLY, reason="Rally V-R0010 not on USB")
def test_rally_node_is_pinned_or_uvc():
node = rally_video_node()
assert node is not None
assert Path(node).exists()
@pytest.mark.skipif(not _HAVE_RALLY, reason="Rally V-R0010 not on USB")
def test_discover_rally_not_a_cam_slot():
cam = discover_rally()
assert cam is not None
assert cam.identity == RALLY_IDENTITY
assert cam.width == 1920
assert cam.height == 1080
assert cam.identity != "cam-01"
card = dante_capture_card()
assert cam.audio_card == card
def test_fleet_cameras_drops_rally():
cams = [
Camera(index=0, identity="cam-01", video_device="/dev/cam01", audio_card=1),
Camera(index=20, identity="rally", video_device="/dev/rally", audio_card=0),
]
assert [c.identity for c in fleet_cameras(cams)] == ["cam-01"]
+172
View File
@@ -0,0 +1,172 @@
"""YuNet face gates for Rally follow — reject ceiling/stand/noise."""
from __future__ import annotations
import numpy as np
from rally_follow import FaceGate, accept_yunet_face, select_yunet_face
def _face(
*,
x=400.0,
y=200.0,
w=80.0,
h=100.0,
score=0.93,
re=None,
le=None,
nose=None,
rm=None,
lm=None,
) -> np.ndarray:
"""YuNet 15-vector: box + 5 landmarks + score, in 960x540 detect space."""
if re is None:
re = (x + 0.30 * w, y + 0.38 * h)
if le is None:
le = (x + 0.70 * w, y + 0.38 * h)
if nose is None:
nose = (x + 0.50 * w, y + 0.55 * h)
if rm is None:
rm = (x + 0.35 * w, y + 0.78 * h)
if lm is None:
lm = (x + 0.65 * w, y + 0.78 * h)
row = np.zeros(15, dtype=np.float32)
row[0:4] = (x, y, w, h)
row[4:6] = re
row[6:8] = le
row[8:10] = nose
row[10:12] = rm
row[12:14] = lm
row[14] = score
return row
FW, FH = 960, 540
def test_good_face_accepted():
assert accept_yunet_face(_face(), FW, FH) is True
def test_tiny_blob_rejected():
# Live FP: 25x34 @ 0.805, nose not between the eyes.
row = _face(x=512, y=250, w=25, h=34, score=0.805,
re=(528.5, 264), le=(532.1, 263), nose=(536.1, 271),
rm=(529.7, 277), lm=(532.1, 278))
assert accept_yunet_face(row, FW, FH) is False
def test_low_score_rejected():
assert accept_yunet_face(_face(score=0.61), FW, FH) is False
def test_ceiling_band_rejected():
row = _face(x=400, y=2, w=80, h=100)
assert accept_yunet_face(row, FW, FH) is False
def test_stand_band_rejected():
row = _face(x=400, y=470, w=80, h=100)
assert accept_yunet_face(row, FW, FH) is False
def test_nose_not_between_eyes_rejected():
row = _face(re=(430, 238), le=(450, 238), nose=(470, 255))
assert accept_yunet_face(row, FW, FH) is False
def test_upside_down_landmarks_rejected():
row = _face(
re=(424, 270), le=(456, 270), nose=(440, 240),
rm=(428, 220), lm=(452, 220),
)
assert accept_yunet_face(row, FW, FH) is False
def test_select_skips_large_invalid_for_smaller_valid():
junk = _face(x=10, y=2, w=80, h=100, score=0.99) # ceiling
good = _face(x=400, y=200, w=80, h=100, score=0.88)
picked = select_yunet_face(np.stack([junk, good]), FW, FH)
assert picked is not None
assert float(picked[0]) == 400.0
def test_select_empty():
assert select_yunet_face(None, FW, FH) is None
assert select_yunet_face(np.zeros((0, 15)), FW, FH) is None
def test_face_gate_needs_confirm():
gate = FaceGate(need=3, max_jump=0.18)
box = (400, 200, 80, 100)
assert gate.update(box, 960, 540) is None
assert gate.update(box, 960, 540) is None
assert gate.update(box, 960, 540) == box
def test_face_gate_jump_resets():
gate = FaceGate(need=3, max_jump=0.18)
a = (400, 200, 80, 100)
b = (800, 400, 80, 100)
assert gate.update(a, 960, 540) is None
assert gate.update(a, 960, 540) is None
assert gate.update(b, 960, 540) is None # new target
assert gate.update(b, 960, 540) is None
assert gate.update(b, 960, 540) == b
def test_face_gate_loss_clears():
gate = FaceGate(need=2, max_jump=0.18)
box = (400, 200, 80, 100)
gate.update(box, 960, 540)
assert gate.update(box, 960, 540) == box
assert gate.update(None, 960, 540) is None
assert gate.update(box, 960, 540) is None
def test_profile_face_accepted():
"""Head turned: eyes cluster, nose not between them — still a face."""
row = _face(
x=400, y=200, w=80, h=100, score=0.90,
re=(418, 238), le=(426, 237),
nose=(410, 255),
rm=(416, 278), lm=(428, 277),
)
assert accept_yunet_face(row, FW, FH) is True
def test_head_hold_keeps_box_on_roi_motion():
from rally_follow import HeadHold
hold = HeadHold(hold_s=1.0)
box = (400, 200, 80, 100)
t = 10.0
assert hold.update(box, moving=False, now=t) == box
assert hold.update(None, moving=True, now=t + 0.3) == box
assert hold.update(None, moving=False, now=t + 0.4) == box # coast
assert hold.update(None, moving=False, now=t + 2.0) is None
def test_roi_motion_ignores_outside_last_box():
from rally_follow import roi_motion
prev = np.zeros((540, 960), dtype=np.uint8)
now = prev.copy()
now[10:40, 10:40] = 200 # motion far from the face
assert roi_motion(prev, now, (400, 200, 80, 100)) is False
now2 = prev.copy()
now2[210:260, 420:460] = 200
assert roi_motion(prev, now2, (400, 200, 80, 100)) is True
def test_stale_hold_freezes_does_not_keep_panning():
"""Last image-space box is not a pan target — that derails as the camera moves."""
from rally_follow import lock_action, steer_speeds
left = (80, 400, 160, 200)
pan, tilt = steer_speeds(left, 1920, 1080, deadband=0.14)
assert pan == -1
assert lock_action(confirmed=left, held=left) == "steer"
assert lock_action(confirmed=None, held=left) == "freeze"
assert lock_action(confirmed=None, held=None) == "lost"
cx = 1920 / 2 - 40
mid = (int(cx - 80), 440, 160, 200)
pan, tilt = steer_speeds(mid, 1920, 1080, deadband=0.14)
assert pan == 0 and tilt == 0
+11
View File
@@ -0,0 +1,11 @@
from rally_follow import video_cmd
def test_video_cmd_without_preview_has_no_kmssink():
cmd = video_cmd("/dev/rally", 1920, 1080, 30, 8, preview=None)
s = " ".join(cmd)
assert "kmssink" not in s
assert "tee" not in cmd
assert "fdsink" in cmd
assert "fd=8" in cmd
assert "device=/dev/rally" in s
+103
View File
@@ -0,0 +1,103 @@
from config import Config
from discovery import Camera
from run import worker_args_for
import json
import jwt
def _cfg(**kw) -> Config:
return Config(url="ws://127.0.0.1:7880", api_key="k", api_secret="s", **kw)
def _cam(identity: str = "cam-07") -> Camera:
return Camera(index=0, identity=identity, video_device="/dev/cam07", audio_card=2)
def test_worker_args_legacy_omits_optional_latency_flags():
args = worker_args_for(_cfg(), _cam())
assert "--audio-queue-ms" not in args
assert "--video-hold-s" not in args
assert "--split-executor" not in args
assert args[args.index("--enhance-mode") + 1] == "auto"
def test_worker_args_latency_flags_and_non_speaker_enhance_off():
cfg = _cfg(
audio_queue_ms=60,
video_hold_s=0.0,
worker_split_executor=True,
enhance_speaker_only=True,
display_speaker_camera="cam-01",
enhance_mode="auto",
)
args = worker_args_for(cfg, _cam("cam-07"))
assert args[args.index("--audio-queue-ms") + 1] == "60"
assert args[args.index("--video-hold-s") + 1] == "0.0"
assert "--split-executor" in args
assert args[args.index("--enhance-mode") + 1] == "off"
assert args[args.index("--beamform-mode") + 1] == "off"
def test_worker_args_speaker_keeps_enhance_mode():
cfg = _cfg(
enhance_mode="force",
enhance_speaker_only=True,
display_speaker_camera="cam-07",
)
args = worker_args_for(cfg, _cam("cam-07"))
assert args[args.index("--enhance-mode") + 1] == "force"
assert args[args.index("--beamform-mode") + 1] == "auto"
def test_worker_token_carries_uwh_tag():
args = worker_args_for(_cfg(), _cam("cam-07"))
token = args[args.index("--token") + 1]
claims = jwt.decode(token, "s", algorithms=["HS256"])
assert claims["attributes"]["tag"] == "uwh"
assert claims["attributes"]["tags"] == "uwh"
def test_worker_args_passes_enhance_socket():
args = worker_args_for(_cfg(enhance_socket="/tmp/e.sock"), _cam())
assert args[args.index("--enhance-socket") + 1] == "/tmp/e.sock"
def test_worker_args_omits_enhance_socket_when_empty():
args = worker_args_for(_cfg(enhance_socket=""), _cam())
assert "--enhance-socket" not in args
def test_worker_args_passes_video_shm():
args = worker_args_for(_cfg(), _cam("cam-07"))
assert args[args.index("--video-shm") + 1] == "/run/livekit-cameras/raw/cam-07.i420"
def test_worker_args_omits_video_shm_when_capture_daemon_off():
args = worker_args_for(_cfg(capture_daemon=False), _cam())
assert "--video-shm" not in args
def test_publisher_args_single_process_and_speaker_only():
from run import publisher_args_for
cfg = _cfg(enhance_speaker_only=True, display_speaker_camera="cam-01")
args = publisher_args_for(cfg, [_cam("cam-07"), _cam("cam-01")])
assert "--enhance-speaker-only" in args
assert "--audio-gate" not in args
payload = json.loads(args[args.index("--cameras-json") + 1])
assert {p["identity"] for p in payload} == {"cam-07", "cam-01"}
assert all("token" in p for p in payload)
assert args[args.index("--video-shm-dir") + 1] == "/run/livekit-cameras/raw"
assert args[args.index("--audio-shm-dir") + 1] == "/run/livekit-cameras/pcm"
def test_publisher_args_rally_keeps_1080p_dims():
from run import publisher_args_for
rally = Camera(index=20, identity="rally", video_device="/dev/rally",
audio_card=0, width=1920, height=1080)
args = publisher_args_for(_cfg(), [_cam("cam-01"), rally])
payload = json.loads(args[args.index("--cameras-json") + 1])
by_id = {p["identity"]: p for p in payload}
assert by_id["rally"]["width"] == 1920
assert by_id["rally"]["height"] == 1080
assert by_id["cam-01"]["width"] is None
+199
View File
@@ -0,0 +1,199 @@
"""Green speaking chrome on the KMS grid (LiveKit active-speaker)."""
import numpy as np
from display_grid import FRAME_RAISE, FRAME_SPEAK, CameraGrid, bgra_to_i420, bgra_to_yuv_pixel
def test_set_speakers_paints_green_i420_border():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
src = np.zeros((360, 640, 4), dtype=np.uint8)
src[:] = (40, 40, 40, 255)
g.set_frame_i420("cam-07", bgra_to_i420(src), 640, 360)
before = np.frombuffer(g.render_i420(), dtype=np.uint8).copy()
g.set_speakers(["cam-07"])
assert g.speaking("cam-07") is True
after = np.frombuffer(g.render_i420(), dtype=np.uint8)
assert not np.array_equal(before, after)
idx = g.identities.index("cam-07")
ox, oy = g.tile_origin(idx)
yplane = after[: g.width * g.height].reshape(g.height, g.width)
yv, _, _ = bgra_to_yuv_pixel(FRAME_SPEAK)
assert int(yplane[oy, ox + g.tile_w // 2]) == yv
# Extra thickness lives in the gutter, not on the feed.
assert int(yplane[oy - 2, ox + g.tile_w // 2]) == yv
ix, iy, iw, _ih = g.inner_rect(idx)
assert int(yplane[iy, ix + iw // 2]) != yv
def test_speaking_overrides_yellow_then_yellow_returns():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
src = np.zeros((360, 640, 4), dtype=np.uint8)
g.set_frame_i420("cam-07", bgra_to_i420(src), 640, 360)
g.set_highlight("cam-07", True)
g.set_speakers(["cam-07"])
idx = g.identities.index("cam-07")
ox, oy = g.tile_origin(idx)
yplane = np.frombuffer(g.render_i420(), dtype=np.uint8)[: g.width * g.height].reshape(
g.height, g.width)
y_speak, _, _ = bgra_to_yuv_pixel(FRAME_SPEAK)
y_raise, _, _ = bgra_to_yuv_pixel(FRAME_RAISE)
assert int(yplane[oy, ox + g.tile_w // 2]) == y_speak
g.set_speakers([])
yplane = np.frombuffer(g.render_i420(), dtype=np.uint8)[: g.width * g.height].reshape(
g.height, g.width)
assert g.speaking("cam-07") is False
assert g.highlighted("cam-07") is True
assert int(yplane[oy, ox + g.tile_w // 2]) == y_raise
def test_clear_drops_speaking():
g = CameraGrid(width=1920, height=1080, cols=5, rows=4)
src = np.zeros((360, 640, 4), dtype=np.uint8)
g.set_frame_i420("cam-01", bgra_to_i420(src), 640, 360)
g.set_speakers(["cam-01"])
g.clear("cam-01")
assert g.speaking("cam-01") is False
class _P:
def __init__(self, identity, keep=True):
self.identity = identity
self.keep = keep
def test_active_speaker_ids_keeps_order_and_filter():
from display_grid import active_speaker_ids, primary_grid_speaker
speakers = [_P("cam-07"), _P("rally", False), _P("cam-03"), _P("")]
assert active_speaker_ids(speakers, want=lambda p: p.keep) == ["cam-07", "cam-03"]
ids = ["rally", "cam-03", "cam-07"]
assert primary_grid_speaker(ids, ["cam-01", "cam-03", "cam-07"]) == ["cam-03"]
assert primary_grid_speaker(["rally"], ["cam-01"]) == []
def test_select_grid_speakers_drops_floor_noise():
from display_grid import select_grid_speakers
assert select_grid_speakers(
[("cam-01", -34.0), ("cam-02", -36.0)], min_db=-24.0, margin_db=6.0,
) == []
def test_select_grid_speakers_bleed_keeps_louder_only():
from display_grid import select_grid_speakers
assert select_grid_speakers(
[("cam-07", -12.0), ("cam-08", -22.0)], min_db=-24.0, margin_db=6.0,
) == ["cam-07"]
def test_select_grid_speakers_two_talkers_both_kept():
from display_grid import select_grid_speakers
assert select_grid_speakers(
[("cam-07", -12.0), ("cam-08", -14.0)], min_db=-24.0, margin_db=6.0,
) == ["cam-07", "cam-08"]
def test_select_grid_speakers_normal_speech_above_mic_floor():
"""Conversational C920 speech is often ~-24 dBFS; absolute -20 missed it."""
from display_grid import select_grid_speakers
floors = {"cam-07": -34.0, "cam-08": -34.0}
assert select_grid_speakers(
[("cam-07", -24.0), ("cam-08", -33.0)],
min_db=-40.0, margin_db=6.0, floors=floors, rise_db=6.0,
) == ["cam-07"]
def test_select_grid_speakers_two_talkers_each_above_own_floor():
from display_grid import select_grid_speakers
floors = {"cam-07": -34.0, "cam-08": -36.0}
assert select_grid_speakers(
[("cam-07", -24.0), ("cam-08", -26.0)],
min_db=-40.0, margin_db=6.0, floors=floors, rise_db=6.0,
) == ["cam-07", "cam-08"]
def test_select_quiet_mic_speech_not_cut_by_abs_min():
"""Quiet C920 idle is ~-45; +3 dB speech is still below -40 dBFS."""
from display_grid import select_grid_speakers
floors = {"cam-10": -45.0, "cam-01": -37.0}
assert select_grid_speakers(
[("cam-10", -41.5), ("cam-01", -36.5)],
min_db=-40.0, margin_db=6.0, floors=floors, rise_db=3.0,
) == ["cam-10"]
def test_update_noise_floor_tracks_idle_not_speech():
from display_grid import update_noise_floor
fl = update_noise_floor(-34.0, -33.5, speaking=False, rise_db=4.0)
assert -34.0 < fl < -33.5
stuck = update_noise_floor(-34.0, -20.0, speaking=True, rise_db=4.0)
assert stuck == -34.0
def test_confirm_speakers_needs_two_hops_new_talker():
from display_grid import confirm_speakers
first, counts = confirm_speakers({}, ["cam-07"], need=2)
assert first == []
second, counts = confirm_speakers(counts, ["cam-07"], need=2)
assert second == ["cam-07"]
# already on: one hop of continued speech keeps chrome
stay, _ = confirm_speakers(counts, ["cam-07"], need=2, already=["cam-07"])
assert stay == ["cam-07"]
# a one-hop idle spike on another seat does not light
spike, _ = confirm_speakers({}, ["cam-01"], need=2, already=["cam-07"])
assert spike == []
def test_waveform_similarity_high_for_delayed_copy():
from display_grid import waveform_similarity
t = np.linspace(0, 1, 1600, endpoint=False)
a = np.sin(2 * np.pi * 220 * t).astype(np.float32)
b = np.roll(a * 0.4, 80)
assert waveform_similarity(a, b) > 0.85
def test_waveform_similarity_low_for_independent_signals():
from display_grid import waveform_similarity
rng = np.random.default_rng(0)
a = rng.normal(size=1600).astype(np.float32)
b = rng.normal(size=1600).astype(np.float32)
assert waveform_similarity(a, b) < 0.35
def test_collapse_bleed_drops_similar_quieter_mic():
from display_grid import collapse_bleed
t = np.linspace(0, 1, 1600, endpoint=False)
src = np.sin(2 * np.pi * 180 * t).astype(np.float32)
waves = {"cam-07": src, "cam-08": np.roll(src * 0.3, 40)}
levels = {"cam-07": -12.0, "cam-08": -18.0}
assert collapse_bleed(["cam-07", "cam-08"], waves, levels, corr_min=0.4) == ["cam-07"]
def test_collapse_bleed_keeps_two_unlike_talkers():
from display_grid import collapse_bleed
t = np.linspace(0, 1, 1600, endpoint=False)
a = np.sin(2 * np.pi * 180 * t).astype(np.float32)
b = np.sin(2 * np.pi * 440 * t + 1.3).astype(np.float32)
waves = {"cam-07": a, "cam-08": b}
levels = {"cam-07": -12.0, "cam-08": -13.0}
assert collapse_bleed(["cam-07", "cam-08"], waves, levels, corr_min=0.6) == [
"cam-07", "cam-08",
]
def test_hold_speakers_adds_second_talker_immediately():
from display_grid import hold_speakers
cur, until = hold_speakers(
["cam-07"], ["cam-07", "cam-08"], prev_peak=-12.0, new_peak=-12.0,
now=10.0, hold_until=10.5, hold_s=0.6, switch_db=3.0)
assert cur == ["cam-07", "cam-08"]
def test_hold_speakers_ignores_similar_bleed_flicker():
from display_grid import hold_speakers
cur, until = hold_speakers(
["cam-07"], ["cam-08"], prev_peak=-12.0, new_peak=-12.5,
now=10.2, hold_until=10.8, hold_s=0.6, switch_db=3.0)
assert cur == ["cam-07"]
cur, _ = hold_speakers(
["cam-07"], ["cam-08"], prev_peak=-12.0, new_peak=-8.0,
now=10.2, hold_until=10.8, hold_s=0.6, switch_db=3.0)
assert cur == ["cam-08"]
+24
View File
@@ -0,0 +1,24 @@
import jwt
from tokens import make_token
def test_make_token_includes_uwh_attributes():
token = make_token(
"ws://127.0.0.1:7880", "devkey", "secret", "cameras", "cam-01",
attributes={"tag": "uwh", "tags": "uwh"},
)
claims = jwt.decode(token, "secret", algorithms=["HS256"])
assert claims["sub"] == "cam-01"
video = claims.get("video") or {}
assert video.get("canPublish") is True
assert video.get("canSubscribe") is False
assert claims["attributes"]["tag"] == "uwh"
assert claims["attributes"]["tags"] == "uwh"
def test_make_token_omits_attributes_when_empty():
token = make_token(
"ws://127.0.0.1:7880", "devkey", "secret", "cameras", "cam-01")
claims = jwt.decode(token, "secret", algorithms=["HS256"])
assert "attributes" not in claims or not claims.get("attributes")
+15
View File
@@ -0,0 +1,15 @@
from usb_ids import (
HUDDLY_VID,
LOGITECH_VID,
is_c920_pid,
is_fleet_video,
is_rally_pid,
)
def test_c920_is_fleet_huddly_and_rally_are_not():
assert is_c920_pid(0x08E5)
assert is_fleet_video(LOGITECH_VID, 0x08E5)
assert not is_fleet_video(HUDDLY_VID, 0x0021)
assert not is_fleet_video(LOGITECH_VID, 0x0881)
assert is_rally_pid(0x0881)
+16
View File
@@ -0,0 +1,16 @@
from uvc_exposure import pin_cmd
def test_pin_cmd_order_manual_then_time_then_dynfps():
cmd = pin_cmd("/dev/cam07")
assert cmd[:3] == ["v4l2-ctl", "-d", "/dev/cam07"]
assert cmd[3] == "--set-ctrl=auto_exposure=1"
assert cmd[4] == "--set-ctrl=exposure_time_absolute=333"
assert cmd[5] == "--set-ctrl=exposure_dynamic_framerate=0"
def test_pin_cmd_auto_skips_inactive_time():
cmd = pin_cmd("/dev/cam07", auto_exposure=3, dynamic_framerate=1)
assert "--set-ctrl=auto_exposure=3" in cmd
assert "--set-ctrl=exposure_dynamic_framerate=1" in cmd
assert not any(c.startswith("--set-ctrl=exposure_time_absolute=") for c in cmd)
+38
View File
@@ -0,0 +1,38 @@
from vaapi_pin import (
classify_render_nodes,
igpu_render,
pin_encode_env,
should_pin_vaapi,
)
def test_classify_by_pci_even_if_card_numbers_swap():
def pci_id_of(node: str) -> str:
return {
"/dev/dri/renderD128": "0xe20b",
"/dev/dri/renderD129": "0xa780",
}[node]
c = classify_render_nodes(
["/dev/dri/renderD128", "/dev/dri/renderD129"],
pci_id_of=pci_id_of,
)
assert c["arc"] == "/dev/dri/renderD128"
assert c["igpu"] == "/dev/dri/renderD129"
def test_pin_encode_env_points_at_igpu_not_arc():
env = pin_encode_env({}, igpu="/dev/dri/renderD129")
assert env["LIBVA_DRIVER_NAME"] == "iHD"
assert env["LIVEKIT_ENCODE_RENDER"] == "/dev/dri/renderD129"
assert env.get("LIBVA_DRM_DEVICE") != "/dev/dri/renderD128"
def test_should_not_pin_vaapi_when_preencoded():
assert should_pin_vaapi(preencoded=True) is False
assert should_pin_vaapi(preencoded=False) is True
def test_igpu_render_matches_live_a780():
node = igpu_render()
assert node.startswith("/dev/dri/renderD")
+69
View File
@@ -0,0 +1,69 @@
"""VideoSource in-flight cap + VAAPI stale-frame drop (encoder behind)."""
from latency import (
should_drop_encoder_queue_depth,
should_drop_stale_vaapi_frame,
video_capture_gate_acquire,
video_capture_gate_release,
)
def test_vaapi_keeps_fresh_delta_frame():
# 30 fps, 33 ms old — still inside the 3-frame budget.
assert should_drop_stale_vaapi_frame(
now_us=1_000_000, capture_us=967_000, fps=30, max_frames_behind=3,
is_keyframe=False,
) is False
def test_vaapi_drops_delta_older_than_three_frame_periods():
# 30 fps × 3 = 100 ms. 150 ms on EncoderQueue → drop before ToI420.
assert should_drop_stale_vaapi_frame(
now_us=1_000_000, capture_us=850_000, fps=30, max_frames_behind=3,
is_keyframe=False,
) is True
def test_vaapi_never_drops_keyframe():
assert should_drop_stale_vaapi_frame(
now_us=1_000_000, capture_us=1, fps=30, max_frames_behind=3,
is_keyframe=True,
) is False
def test_vaapi_missing_timestamp_is_not_dropped():
assert should_drop_stale_vaapi_frame(
now_us=1_000_000, capture_us=0, fps=30, max_frames_behind=3,
is_keyframe=False,
) is False
def test_gate_admits_until_max_in_flight():
gate = {"in_flight": 0, "dropped": 0, "max_in_flight": 3}
assert video_capture_gate_acquire(gate) is True
assert video_capture_gate_acquire(gate) is True
assert video_capture_gate_acquire(gate) is True
assert gate["in_flight"] == 3
assert video_capture_gate_acquire(gate) is False
assert gate["dropped"] == 1
assert gate["in_flight"] == 3
def test_gate_release_allows_another_capture():
gate = {"in_flight": 3, "dropped": 0, "max_in_flight": 3}
video_capture_gate_release(gate)
assert gate["in_flight"] == 2
assert video_capture_gate_acquire(gate) is True
assert gate["in_flight"] == 3
def test_queue_depth_keeps_slot_when_empty():
assert should_drop_encoder_queue_depth(queued=0, max_queued=1) is False
def test_queue_depth_drops_when_at_max():
# Latest-frame cap: one in-flight OnFrame/Encode, overwrite don't push.
assert should_drop_encoder_queue_depth(queued=1, max_queued=1) is True
def test_queue_depth_drops_when_over_max():
assert should_drop_encoder_queue_depth(queued=3, max_queued=1) is True
+52
View File
@@ -0,0 +1,52 @@
"""Publisher must not catch up frames and must recycle native encoders on RSS."""
from latency import (
next_video_capture,
should_recycle_encoders,
)
def test_next_video_capture_sleeps_until_due():
capture, due = next_video_capture(now=10.0, due=10.05, period=1 / 30)
assert capture is False
assert due == 10.05
def test_next_video_capture_fires_on_due_and_advances_one_period():
capture, due = next_video_capture(now=10.0, due=10.0, period=0.05)
assert capture is True
assert due == 10.05
def test_next_video_capture_skips_catchup_when_behind():
# 80 ms late at 30 fps would be two extra ticks if we kept adding period.
capture, due = next_video_capture(now=10.08, due=10.0, period=1 / 30)
assert capture is True
assert due == 10.08 + (1 / 30)
def test_should_recycle_when_anon_rss_exceeds_limit_and_interval_elapsed():
assert should_recycle_encoders(
rss_anon_kb=4_000_000, limit_kb=3_000_000,
now=100.0, last_recycle_at=0.0, min_interval_s=60.0,
) is True
def test_should_not_recycle_below_limit():
assert should_recycle_encoders(
rss_anon_kb=1_000_000, limit_kb=3_000_000,
now=100.0, last_recycle_at=0.0, min_interval_s=60.0,
) is False
def test_should_not_recycle_inside_min_interval():
assert should_recycle_encoders(
rss_anon_kb=5_000_000, limit_kb=3_000_000,
now=100.0, last_recycle_at=80.0, min_interval_s=60.0,
) is False
def test_should_not_recycle_when_limit_disabled():
assert should_recycle_encoders(
rss_anon_kb=9_000_000, limit_kb=0,
now=100.0, last_recycle_at=0.0, min_interval_s=60.0,
) is False
+25
View File
@@ -0,0 +1,25 @@
from visca_xu_bridge import parse_visca, visca_frames
def test_visca_split_frames():
frames, rest = visca_frames(bytes([0x81, 0x01, 0x06, 0x04, 0xFF, 0x81]))
assert frames == [bytes([0x81, 0x01, 0x06, 0x04, 0xFF])]
assert rest == bytes([0x81])
def test_visca_stop_and_move():
stop = parse_visca(bytes([0x81, 0x01, 0x06, 0x01, 0x15, 0x15, 0x03, 0x03, 0xFF]))
assert stop["action"] == "stop"
left = parse_visca(bytes([0x81, 0x01, 0x06, 0x01, 0x08, 0x08, 0x01, 0x03, 0xFF]))
assert left == {"action": "move", "pan": -1.0, "tilt": 0.0, "zoom": 0.0}
up = parse_visca(bytes([0x81, 0x01, 0x06, 0x01, 0x08, 0x08, 0x03, 0x01, 0xFF]))
assert up["tilt"] == 1.0
def test_visca_zoom_home_preset():
assert parse_visca(bytes([0x81, 0x01, 0x04, 0x07, 0x00, 0xFF]))["action"] == "zoom_stop"
tele = parse_visca(bytes([0x81, 0x01, 0x04, 0x07, 0x27, 0xFF]))
assert tele == {"action": "zoom", "zoom": 1.0}
assert parse_visca(bytes([0x81, 0x01, 0x06, 0x04, 0xFF]))["action"] == "home"
rec = parse_visca(bytes([0x81, 0x01, 0x04, 0x3F, 0x02, 0x01, 0xFF]))
assert rec == {"action": "preset_recall", "index": 1}