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.
64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
"""Pin Logitech C920 exposure so 360p stays 30 fps.
|
|
|
|
Aperture-priority + exposure_dynamic_framerate=1 lets the sensor sit at
|
|
~66 ms / gain 255 and drop to 15 fps. Manual 333 (0.1 ms units = 1/30 s)
|
|
with dyn-fps off holds the gst 30 fps request.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
|
|
log = logging.getLogger("cameras.uvc-exposure")
|
|
|
|
# UVC: 1 = Manual Mode, 3 = Aperture Priority. Time unit is 0.1 ms.
|
|
AUTO_EXPOSURE_MANUAL = 1
|
|
EXPOSURE_TIME_30FPS = 333
|
|
|
|
|
|
def pin_cmd(
|
|
device: str,
|
|
*,
|
|
auto_exposure: int = AUTO_EXPOSURE_MANUAL,
|
|
exposure_time: int = EXPOSURE_TIME_30FPS,
|
|
dynamic_framerate: int = 0,
|
|
) -> list[str]:
|
|
cmd = [
|
|
"v4l2-ctl",
|
|
"-d",
|
|
str(device),
|
|
f"--set-ctrl=auto_exposure={int(auto_exposure)}",
|
|
f"--set-ctrl=exposure_dynamic_framerate={int(dynamic_framerate)}",
|
|
]
|
|
# Time is inactive under aperture-priority (3); setting it fails the whole pin.
|
|
if int(auto_exposure) == AUTO_EXPOSURE_MANUAL:
|
|
cmd.insert(4, f"--set-ctrl=exposure_time_absolute={int(exposure_time)}")
|
|
return cmd
|
|
|
|
|
|
def pin_from_env() -> tuple[int, int, int]:
|
|
ae = int(os.environ.get("VIDEO_AUTO_EXPOSURE", str(AUTO_EXPOSURE_MANUAL)))
|
|
exp = int(os.environ.get("VIDEO_EXPOSURE_TIME", str(EXPOSURE_TIME_30FPS)))
|
|
dyn = int(os.environ.get("VIDEO_EXPOSURE_DYNAMIC", "0"))
|
|
return ae, exp, dyn
|
|
|
|
|
|
def pin_c920_exposure(device: str) -> None:
|
|
ae, exp, dyn = pin_from_env()
|
|
cmd = pin_cmd(device, auto_exposure=ae, exposure_time=exp, dynamic_framerate=dyn)
|
|
try:
|
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
|
|
except OSError as exc:
|
|
log.warning("pin %s failed: %s", device, exc)
|
|
return
|
|
if r.returncode:
|
|
log.warning("pin %s rc=%s %s", device, r.returncode, (r.stderr or "").strip())
|
|
return
|
|
log.info("pinned %s ae=%s time=%s dynfps=%s", device, ae, exp, dyn)
|
|
|
|
|
|
def pin_devices(devices: list[str]) -> None:
|
|
for dev in devices:
|
|
pin_c920_exposure(dev)
|