Share the K1 live scene template and preserve idle media channels
This commit is contained in:
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user