From f3b1f97afacc13d68d1fb3543c19b6ec9708a870 Mon Sep 17 00:00:00 2001 From: stef <19478336+stefpi@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:48:16 -0400 Subject: [PATCH] webrtc/athena: speed up first time stream connection (#38184) * move streamrequest to models file, prewarm in webrtcd * cleanup * debug * change print to logger.info --- system/athena/athenad.py | 2 +- system/webrtc/device/video.py | 5 ++--- system/webrtc/models.py | 9 +++++++++ system/webrtc/webrtcd.py | 33 +++++++++++++++++++-------------- 4 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 system/webrtc/models.py diff --git a/system/athena/athenad.py b/system/athena/athenad.py index c31f1ef281..4c9b536219 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -581,7 +581,7 @@ def getNetworks(): @dispatcher.add_method def startStream(sdp: str, video_enabled: bool | None = None) -> dict: - from openpilot.system.webrtc.webrtcd import StreamRequestBody + from openpilot.system.webrtc.models import StreamRequestBody bridge_services_in = [] # get live car params to avoid stale notCar edge case diff --git a/system/webrtc/device/video.py b/system/webrtc/device/video.py index af492c829e..69f628cb11 100644 --- a/system/webrtc/device/video.py +++ b/system/webrtc/device/video.py @@ -7,7 +7,7 @@ from teleoprtc.tracks import TiciVideoStreamTrack from aiortc import MediaStreamError from cereal import messaging -from openpilot.common.realtime import DT_MDL, DT_DMON +from openpilot.common.realtime import DT_MDL from openpilot.common.params import Params @@ -30,8 +30,7 @@ class LiveStreamVideoStreamTrack(TiciVideoStreamTrack): } def __init__(self, camera_type: str, video_enabled: bool = True): - dt = DT_DMON if camera_type == "driver" else DT_MDL - super().__init__(camera_type, dt) + super().__init__(camera_type, DT_MDL) self._sock = self._make_sock(camera_type) self._pts = 0 diff --git a/system/webrtc/models.py b/system/webrtc/models.py new file mode 100644 index 0000000000..fd74113049 --- /dev/null +++ b/system/webrtc/models.py @@ -0,0 +1,9 @@ +from dataclasses import dataclass, field + +@dataclass +class StreamRequestBody: + sdp: str + initCamera: str + video_enabled: bool = True + bridge_services_in: list[str] = field(default_factory=list) + bridge_services_out: list[str] = field(default_factory=list) diff --git a/system/webrtc/webrtcd.py b/system/webrtc/webrtcd.py index 8d29dafdd3..48b868de21 100755 --- a/system/webrtc/webrtcd.py +++ b/system/webrtc/webrtcd.py @@ -10,7 +10,6 @@ import contextlib import json import uuid import logging -from dataclasses import dataclass, field from typing import Any, TYPE_CHECKING # aiortc and its dependencies have lots of internal warnings :( @@ -22,13 +21,13 @@ import capnp from aiohttp import web if TYPE_CHECKING: from aiortc.rtcdatachannel import RTCDataChannel +import aioice.ice +from openpilot.system.webrtc.models import StreamRequestBody from openpilot.system.webrtc.schema import generate_field from openpilot.common.params import Params from cereal import messaging, log -import aioice.ice - # socket trick: route lookup for 8.8.8.8 (nothing is sent or actually connected to) # return the source interfaces IP which is the default interface of the device @@ -254,9 +253,10 @@ class StreamSession: enabled: bool | None = None, debug_mode: bool = False ): - from aiortc.mediastreams import VideoStreamTrack + if debug_mode: + from aiortc.mediastreams import VideoStreamTrack from openpilot.system.webrtc.device.video import LiveStreamVideoStreamTrack - from teleoprtc import WebRTCAnswerBuilder + from teleoprtc.builder import WebRTCAnswerBuilder self.identifier = str(uuid.uuid4()) self.params = Params() @@ -370,15 +370,6 @@ class StreamSession: await self.stream.stop() -@dataclass -class StreamRequestBody: - sdp: str - initCamera: str - video_enabled: bool = True - bridge_services_in: list[str] = field(default_factory=list) - bridge_services_out: list[str] = field(default_factory=list) - - async def get_stream(request: 'web.Request'): stream_dict, debug_mode = request.app['streams'], request.app['debug'] raw_body = await request.json() @@ -455,11 +446,25 @@ async def error_middleware(request: 'web.Request', handler): return web.json_response({"error": "exception", "message": f"{type(e).__name__}: {e}"}, status=500) +def prewarm_stream_session_imports(debug_mode: bool = False) -> None: + if debug_mode: + from aiortc.mediastreams import VideoStreamTrack + assert VideoStreamTrack + from openpilot.system.webrtc.device.video import LiveStreamVideoStreamTrack + from teleoprtc.builder import WebRTCAnswerBuilder + assert LiveStreamVideoStreamTrack + assert WebRTCAnswerBuilder + + def webrtcd_thread(host: str, port: int, debug: bool): logging.basicConfig(level=logging.CRITICAL, handlers=[logging.StreamHandler()]) logging_level = logging.DEBUG if debug else logging.INFO logging.getLogger("WebRTCStream").setLevel(logging_level) logging.getLogger("webrtcd").setLevel(logging_level) + prewarm_start = time.monotonic() + prewarm_stream_session_imports(debug) + prewarm_end = time.monotonic() + logging.getLogger("webrtcd").info(f"webrtc prewarm finished in {(prewarm_end - prewarm_start) * 1000} ms") app = web.Application(middlewares=[error_middleware])