Share the K1 live scene template and preserve idle media channels

This commit is contained in:
DCCONSTRUCTIONS
2026-09-07 16:38:39 +03:00
parent 309bdf759e
commit fa8ac760a1
49 changed files with 2813 additions and 2126 deletions
+92
View File
@@ -59,6 +59,9 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
except queue.Empty:
return b""
def snapshot(self):
return {"type": "lidar-state", "sequence": 1, "age_ms": 0, "points": 5000}
def close(self):
pass
@@ -90,6 +93,8 @@ def test_native_webrtc_roundtrip_and_missing_camera_preserve_rrd(monkeypatch):
@channel.on("message")
def message(data):
if isinstance(data, str):
return
payloads.append(data)
if len(payloads) > 1 and sum(map(len, payloads[1:])) == len(payload):
received.set()
@@ -153,3 +158,90 @@ def test_installed_camera_uses_declared_os_ffmpeg():
unit = (root / "plugins/xgrids-k1/packaging/mission-core-k1.service").read_text()
assert "Environment=MISSIONCORE_FFMPEG_BINARY=/usr/bin/ffmpeg" in unit
assert "iproute2, ffmpeg" in (root / "plugins/xgrids-k1/packaging/build_deb.py").read_text()
def test_native_rrd_idle_does_not_close_camera_or_peer(monkeypatch):
"""Regression: the real binary sink, two media channels, idle then resume."""
import json
import time
from types import SimpleNamespace
from k1link.data_plane import ConsumerFrameContext, DecodedPointCloudView
from k1link.viewer.node_rerun import NodeRerunBridge
class Segments:
def __init__(self):
self.queue = queue.Queue()
def get(self, timeout):
return self.queue.get(timeout=timeout)
class Camera:
def __init__(self):
self.lease = SimpleNamespace(segments=Segments())
self.released = []
def snapshot(self):
return {"generation": 1, "delivery": {"media_type": "video/mp4"}}
def open_delivery(self, generation):
assert generation == 1
return self.lease
def release_delivery(self, lease, **_):
self.released.append(lease)
def mark_streaming(self, _):
pass
async def run():
import aioice.ice
monkeypatch.setattr(aioice.ice, "get_host_addresses", lambda **_: ["127.0.0.1"])
hub, camera = NodeRerunBridge(), Camera()
peers = NodeMediaPeers(hub, camera)
client = RTCPeerConnection(RTCConfiguration(iceServers=[]))
rrd = client.createDataChannel("rrd", ordered=True)
video = client.createDataChannel("camera", ordered=True)
ready, resumed, camera_frame = asyncio.Event(), asyncio.Event(), asyncio.Event()
@rrd.on("message")
def rrd_message(data):
if isinstance(data, str):
value = json.loads(data)
if value["sequence"] == 1:
resumed.set()
else:
ready.set()
@video.on("message")
def camera_message(data):
if data == b"synthetic-camera-fragment":
camera_frame.set()
try:
await client.setLocalDescription(await client.createOffer())
answer = await peers.offer({"sdp": client.localDescription.sdp})
await client.setRemoteDescription(
RTCSessionDescription(sdp=answer["sdp"], type="answer")
)
await asyncio.wait_for(ready.wait(), 8)
await asyncio.sleep(1.5)
assert answer["peer_id"] in peers.items
assert rrd.readyState == video.readyState == "open"
assert not camera.released
now = time.monotonic_ns()
hub.process(DecodedPointCloudView(
ConsumerFrameContext(1, time.time_ns(), now, now, 1, True),
"world", ((1.0, 2.0, 3.0),), b"\x01",
))
camera.lease.segments.queue.put(("media", b"synthetic-camera-fragment"))
await asyncio.wait_for(resumed.wait(), 5)
await asyncio.wait_for(camera_frame.wait(), 5)
assert rrd.readyState == video.readyState == "open"
finally:
await client.close()
await peers.close_all()
hub.close()
assert not peers.items
asyncio.run(run())