mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-08-24 06:33:48 +08:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 68cefe6811 | |||
| 718db8c62e | |||
| 1347801f99 | |||
| ca9c6e1933 | |||
| 3a955ca11a | |||
| 8c7726b8ed | |||
| 22d1cf7fdc | |||
| dc1625d4a1 | |||
| 37e027a0e0 | |||
| c2214d4c32 | |||
| 25375bd157 | |||
| 8e8baf60db | |||
| daa765a016 | |||
| be554e982c | |||
| 400a35ef7f | |||
| e9bafbd353 | |||
| e372046ff1 | |||
| 084747c75d | |||
| df5695ba08 | |||
| 76279f6540 | |||
| 555f48c5d2 | |||
| dcf9d25bf3 | |||
| a8d1a280c6 | |||
| 5b36799eec | |||
| 20fdc3d824 | |||
| 7bd6cad821 |
@@ -188,7 +188,7 @@ jobs:
|
||||
if [ "${{ inputs.target_hardware }}" == "usbgpu" ]; then
|
||||
echo "USBGPU build"
|
||||
export USBGPU=1
|
||||
TG_FLAGS="DEBUG=2 DEV=USB+AMD:LLVM WARP_DEV=QCOM FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2"
|
||||
TG_FLAGS="DEBUG=1 DEV=USB+AMD:LLVM WARP_DEV=QCOM FLOAT16=1 JIT_BATCH_SIZE=0 GMMU=0 TC_OPT=2"
|
||||
OUTPUT_PKL="${{ env.MODELS_DIR }}/big_driving_tinygrad.pkl"
|
||||
else
|
||||
echo "QCOM build"
|
||||
|
||||
+3
-1
@@ -24,7 +24,9 @@ function agnos_init {
|
||||
if $AGNOS_PY --verify $MANIFEST; then
|
||||
sudo reboot
|
||||
fi
|
||||
$DIR/openpilot/common/hardware/comma/updater $AGNOS_PY $MANIFEST
|
||||
while true; do
|
||||
$DIR/openpilot/common/hardware/comma/updater $AGNOS_PY $MANIFEST
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsEngaged", {PERSISTENT, BOOL}},
|
||||
{"IsLdwEnabled", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsLiveStreaming", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
|
||||
{"IsMetric", {PERSISTENT | BACKUP, BOOL}},
|
||||
{"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}},
|
||||
{"IsRhdDetected", {PERSISTENT, BOOL}},
|
||||
|
||||
@@ -149,11 +149,15 @@ class BigButton(Widget):
|
||||
def set_touch_valid_callback(self, touch_callback: Callable[[], bool]) -> None:
|
||||
super().set_touch_valid_callback(lambda: touch_callback() and self._grow_animation_until is None)
|
||||
|
||||
def _width_hint(self) -> int:
|
||||
# A value moves the title to the top, where it shares space with the icon.
|
||||
def _title_width_hint(self) -> int:
|
||||
# A value moves the title to the top, where it shares space with the icon
|
||||
icon_size = self._txt_icon.width if self._txt_icon and self.value else 0
|
||||
return int(self._rect.width - self.LABEL_HORIZONTAL_PADDING * 2 - icon_size)
|
||||
|
||||
def _subtitle_width_hint(self) -> int:
|
||||
# Bottom aligned, so it sits below the icon
|
||||
return int(self._rect.width - self.LABEL_HORIZONTAL_PADDING * 2)
|
||||
|
||||
def _get_label_font_size(self):
|
||||
if len(self.text) <= 18:
|
||||
return 48
|
||||
@@ -228,14 +232,14 @@ class BigButton(Widget):
|
||||
|
||||
label_color = LABEL_COLOR if self.enabled else rl.Color(255, 255, 255, int(255 * 0.35))
|
||||
self._label.set_color(label_color)
|
||||
label_rect = rl.Rectangle(label_x, btn_y + self.LABEL_VERTICAL_PADDING, self._width_hint(),
|
||||
label_rect = rl.Rectangle(label_x, btn_y + self.LABEL_VERTICAL_PADDING, self._title_width_hint(),
|
||||
self._rect.height - self.LABEL_VERTICAL_PADDING * 2)
|
||||
self._label.render(label_rect)
|
||||
|
||||
if self.value:
|
||||
label_y = btn_y + self.LABEL_VERTICAL_PADDING + self._label.get_content_height(self._width_hint())
|
||||
label_y = label_rect.y + self._label.get_content_height(int(label_rect.width))
|
||||
sub_label_height = btn_y + self._rect.height - self.LABEL_VERTICAL_PADDING - label_y
|
||||
sub_label_rect = rl.Rectangle(label_x, label_y, self._width_hint(), sub_label_height)
|
||||
sub_label_rect = rl.Rectangle(label_x, label_y, self._subtitle_width_hint(), sub_label_height)
|
||||
self._sub_label.render(sub_label_rect)
|
||||
|
||||
# ICON -------------------------------------------------------------------
|
||||
@@ -312,9 +316,6 @@ class BigMultiToggle(BigToggle):
|
||||
|
||||
self.set_value(self._options[0])
|
||||
|
||||
def _width_hint(self) -> int:
|
||||
return int(self._rect.width - self.LABEL_HORIZONTAL_PADDING * 2 - self._txt_enabled_toggle.width)
|
||||
|
||||
def _handle_mouse_release(self, mouse_pos: MousePos):
|
||||
super()._handle_mouse_release(mouse_pos)
|
||||
cur_idx = self._options.index(self.value)
|
||||
@@ -363,9 +364,6 @@ class GreyBigButton(BigButton):
|
||||
def LABEL_VERTICAL_PADDING(self):
|
||||
return BigButton.LABEL_VERTICAL_PADDING if self._label.text else 18
|
||||
|
||||
def _width_hint(self) -> int:
|
||||
return int(self._rect.width - self.LABEL_HORIZONTAL_PADDING * 2)
|
||||
|
||||
def _get_label_font_size(self):
|
||||
return 36
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import math
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
@@ -66,14 +67,15 @@ def get_policy_npy_shapes(input_shapes: dict, is_supercombo: bool = False) -> tu
|
||||
if desire_key:
|
||||
shapes['desire'] = (input_shapes[desire_key][2],)
|
||||
|
||||
if is_supercombo and 'features_buffer' in input_shapes:
|
||||
fb = input_shapes['features_buffer']
|
||||
shapes['prev_feat'] = (fb[0], fb[2])
|
||||
|
||||
for key, shape in input_shapes.items():
|
||||
if key not in (desire_key, 'features_buffer') and 'img' not in key:
|
||||
shapes[key] = tuple(shape)
|
||||
|
||||
if is_supercombo and 'features_buffer' in input_shapes:
|
||||
fb = input_shapes['features_buffer']
|
||||
feat_dim = math.prod(fb[2:])
|
||||
shapes['prev_feat'] = (fb[0], feat_dim)
|
||||
|
||||
sizes = [int(np.prod(size)) for size in shapes.values()]
|
||||
return shapes, sizes
|
||||
|
||||
@@ -117,8 +119,9 @@ def generate_queues_and_npy(input_shapes: dict, frame_skip: int, device: str = D
|
||||
}
|
||||
|
||||
if features_buffer:
|
||||
feat_dim = math.prod(features_buffer[2:])
|
||||
feat_q_len = frame_skip * features_buffer[1] if is_supercombo else frame_skip * (features_buffer[1] - 1) + 1
|
||||
queues['feat_q'] = Tensor(np.zeros((feat_q_len, features_buffer[0], features_buffer[2]),
|
||||
queues['feat_q'] = Tensor(np.zeros((feat_q_len, features_buffer[0], feat_dim),
|
||||
dtype=np.float32), device=device).contiguous().realize()
|
||||
|
||||
queues.update({key: Tensor(value, device='NPY').realize() for key, value in npy_arrays.items() if key in ('tfm', 'big_tfm')})
|
||||
@@ -183,14 +186,14 @@ def make_run_policy(vision_runner, policy_runners: list, features_slice: slice,
|
||||
warped_dev = warped.to(Device.DEFAULT)
|
||||
Tensor.realize(packed_npy_inputs_dev, warped_dev)
|
||||
|
||||
img = shift_and_sample(img_q, warped_dev[0:1], sample_skip_fn).realize()
|
||||
big_img = shift_and_sample(big_img_q, warped_dev[1:2], sample_skip_fn).realize()
|
||||
img = shift_and_sample(img_q, warped_dev[0:1], sample_skip_fn)
|
||||
big_img = shift_and_sample(big_img_q, warped_dev[1:2], sample_skip_fn)
|
||||
|
||||
unpacked_tensors = [tensor.reshape(shape) for tensor, shape in zip(packed_npy_inputs_dev.split(npy_sizes), npy_shapes.values(), strict=True)]
|
||||
unpacked_dict = dict(zip(npy_shapes.keys(), unpacked_tensors, strict=True))
|
||||
|
||||
desire_dev = unpacked_dict['desire']
|
||||
desire_buf = shift_and_sample(desire_q, desire_dev.reshape(1, 1, -1), sample_desire_fn).realize()
|
||||
desire_buf = shift_and_sample(desire_q, desire_dev.reshape(1, 1, -1), sample_desire_fn)
|
||||
|
||||
inputs = {desire_key: desire_buf}
|
||||
for key, tensor_val in unpacked_dict.items():
|
||||
@@ -199,7 +202,7 @@ def make_run_policy(vision_runner, policy_runners: list, features_slice: slice,
|
||||
|
||||
if 'prev_feat' in unpacked_dict:
|
||||
prev_feat_dev = unpacked_dict['prev_feat']
|
||||
inputs['features_buffer'] = shift_and_sample(feat_q, prev_feat_dev.reshape(1, 1, -1), sample_skip_fn).realize()
|
||||
inputs['features_buffer'] = shift_and_sample(feat_q, prev_feat_dev.reshape(1, 1, -1), sample_skip_fn).reshape(input_shapes['features_buffer'])
|
||||
|
||||
if vision_runner:
|
||||
vision_out_cast = next(iter(vision_runner({road_key: img, wide_key: big_img}).values())).cast('float32').realize()
|
||||
@@ -211,7 +214,7 @@ def make_run_policy(vision_runner, policy_runners: list, features_slice: slice,
|
||||
|
||||
inputs.update({road_key: img, wide_key: big_img})
|
||||
if 'features_buffer' not in inputs:
|
||||
inputs['features_buffer'] = sample_skip_fn(feat_q)
|
||||
inputs['features_buffer'] = sample_skip_fn(feat_q).reshape(input_shapes['features_buffer'])
|
||||
|
||||
policy_out = next(iter(policy_runners[0](inputs).values())).cast('float32').realize()
|
||||
if 'features_buffer' not in inputs and features_slice is not None:
|
||||
|
||||
@@ -195,3 +195,85 @@ class TestReadFileChunkedToDisk(OpenpilotTestCase):
|
||||
|
||||
assert out.parent == Path(d)
|
||||
assert out.read_bytes() == payload
|
||||
|
||||
|
||||
class Test4DFeaturesBuffer(OpenpilotTestCase):
|
||||
def test_get_policy_npy_shapes_4d(self):
|
||||
from openpilot.sunnypilot.modeld_v2.compile_modeld import get_policy_npy_shapes
|
||||
input_shapes = {
|
||||
'desire_pulse': (1, 25, 8),
|
||||
'features_buffer': (1, 24, 32, 512), # compare 4d to 3d for regression
|
||||
'traffic_convention': (1, 2),
|
||||
'action_t': (1, 2)
|
||||
}
|
||||
shapes, sizes = get_policy_npy_shapes(input_shapes, is_supercombo=True)
|
||||
assert shapes['prev_feat'] == (1, 16384)
|
||||
assert sizes == [8, 2, 2, 16384]
|
||||
|
||||
def test_get_policy_npy_shapes_3d(self):
|
||||
from openpilot.sunnypilot.modeld_v2.compile_modeld import get_policy_npy_shapes
|
||||
input_shapes = {
|
||||
'desire_pulse': (1, 25, 8),
|
||||
'features_buffer': (1, 24, 512),
|
||||
'traffic_convention': (1, 2),
|
||||
'action_t': (1, 2)
|
||||
}
|
||||
shapes, sizes = get_policy_npy_shapes(input_shapes, is_supercombo=True)
|
||||
assert shapes['prev_feat'] == (1, 512)
|
||||
assert sizes == [8, 2, 2, 512]
|
||||
|
||||
|
||||
class TestStockCompileModeldEquivalence(OpenpilotTestCase):
|
||||
def test_get_policy_npy_shapes_matches_stock(self):
|
||||
from openpilot.selfdrive.modeld.compile_modeld import get_policy_npy_shapes as stock_get_policy_npy_shapes
|
||||
from openpilot.sunnypilot.modeld_v2.compile_modeld import get_policy_npy_shapes as sunny_get_policy_npy_shapes
|
||||
|
||||
stock_input_shapes = {
|
||||
'desire_pulse': (1, 25, 8),
|
||||
'features_buffer': (1, 24, 512), # see below comment
|
||||
'traffic_convention': (1, 2),
|
||||
'action_t': (1, 2),
|
||||
}
|
||||
|
||||
stock_shapes, stock_sizes = stock_get_policy_npy_shapes(stock_input_shapes)
|
||||
sunny_shapes, sunny_sizes = sunny_get_policy_npy_shapes(stock_input_shapes, is_supercombo=True)
|
||||
|
||||
assert sunny_shapes == stock_shapes
|
||||
assert sunny_sizes == stock_sizes
|
||||
assert sunny_shapes['prev_feat'] == (1, 512)
|
||||
|
||||
def test_make_input_queues_full_stock_equivalence(self):
|
||||
from openpilot.selfdrive.modeld.compile_modeld import make_input_queues as stock_make_input_queues
|
||||
from openpilot.sunnypilot.modeld_v2.compile_modeld import make_supercombo_input_queues as sunny_make_supercombo_input_queues
|
||||
input_shapes = {
|
||||
'img': (1, 12, 128, 256),
|
||||
'desire_pulse': (1, 25, 8),
|
||||
'features_buffer': (1, 24, 512), # when https://github.com/commaai/openpilot/pull/38681 merges, update to 1,24,32,512
|
||||
'traffic_convention': (1, 2),
|
||||
'action_t': (1, 2),
|
||||
}
|
||||
frame_skip = 4
|
||||
|
||||
stock_queues, stock_npy = stock_make_input_queues(input_shapes, frame_skip, device='NPY')
|
||||
sunny_queues, sunny_npy = sunny_make_supercombo_input_queues(input_shapes, frame_skip, device='NPY')
|
||||
assert set(sunny_queues.keys()) == set(stock_queues.keys())
|
||||
for key in stock_queues:
|
||||
assert sunny_queues[key].shape == stock_queues[key].shape, \
|
||||
f"Queue shape mismatch for {key}: sunny {sunny_queues[key].shape} != stock {stock_queues[key].shape}"
|
||||
assert set(sunny_npy.keys()) == set(stock_npy.keys())
|
||||
for key in stock_npy:
|
||||
assert sunny_npy[key].shape == stock_npy[key].shape, \
|
||||
f"Numpy array shape mismatch for {key}: sunny {sunny_npy[key].shape} != stock {stock_npy[key].shape}"
|
||||
|
||||
def test_make_warp_queues_stock_equivalence(self):
|
||||
from openpilot.selfdrive.modeld.compile_modeld import make_warp_input_queues as stock_make_warp_queues
|
||||
from openpilot.sunnypilot.modeld_v2.compile_modeld import make_warp_queues as sunny_make_warp_queues
|
||||
stock_vision_shapes = {'img': (1, 12, 128, 256)} # for now?
|
||||
stock_queues, stock_npy = stock_make_warp_queues(stock_vision_shapes, frame_skip=4, device='NPY')
|
||||
sunny_queues, sunny_npy = sunny_make_warp_queues(device='NPY')
|
||||
|
||||
assert set(sunny_npy.keys()) == set(stock_npy.keys()) == {'tfm', 'big_tfm'}
|
||||
for key in sunny_npy:
|
||||
assert sunny_npy[key].shape == stock_npy[key].shape == (3, 3)
|
||||
|
||||
|
||||
|
||||
@@ -140,8 +140,8 @@ class ModelCache:
|
||||
|
||||
class ModelFetcher:
|
||||
"""Handles fetching and caching of model data from remote source"""
|
||||
MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_v20.json"
|
||||
MODEL_URL_USBGPU = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_usbgpu_v21.json"
|
||||
MODEL_URL = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_v21.json"
|
||||
MODEL_URL_USBGPU = "https://raw.githubusercontent.com/sunnypilot/sunnypilot-models/refs/heads/gh-pages/docs/driving_models_usbgpu_v22.json"
|
||||
|
||||
def __init__(self, params: Params):
|
||||
self.params = params
|
||||
|
||||
@@ -18,7 +18,7 @@ from openpilot.sunnypilot.models.constants import Meta, MetaSimPose, MetaTombRai
|
||||
from openpilot.common.hardware.hw import Paths
|
||||
|
||||
# SET ME TO THE EXACT JSON VERSION WE SET IN SUNNYPILOT_MODELS REPO
|
||||
REQUIRED_JSON_VERSION = 17
|
||||
REQUIRED_JSON_VERSION = 18
|
||||
|
||||
CUSTOM_MODEL_PATH = Paths.model_root()
|
||||
METADATA_PATH = Path(__file__).parent / '../models/supercombo_metadata.pkl'
|
||||
|
||||
@@ -828,20 +828,22 @@ def startStream(sdp: str, enabled: bool) -> dict:
|
||||
bridge_services_in = []
|
||||
|
||||
# stale car params case taken care of by webrtcd being shut off on ignition
|
||||
cp_bytes = Params().get("CarParamsPersistent")
|
||||
cp_bytes = params.get("CarParamsPersistent")
|
||||
if cp_bytes is not None:
|
||||
with car.CarParams.from_bytes(cp_bytes) as CP:
|
||||
if CP.notCar:
|
||||
bridge_services_in.append("testJoystick")
|
||||
else:
|
||||
raise Exception("failed to get CarParamsPersistent")
|
||||
|
||||
if params.get_bool("IsOffroad"):
|
||||
# manager owns camerad/stream_encoderd/webrtcd; flip the param and let it bring them up.
|
||||
# webrtcd clears IsLiveStreaming when the session ends
|
||||
params.put_bool("IsLiveStreaming", True)
|
||||
# wait for webrtcd end points to wake up
|
||||
wait_for_webrtcd()
|
||||
try:
|
||||
wait_for_webrtcd()
|
||||
except TimeoutError:
|
||||
cloudlog.event("athena.startStream.webrtcd_offroad_start_timeout", error=True)
|
||||
raise
|
||||
|
||||
return post_stream_request(StreamRequestBody(sdp, ["wideRoad"], enabled, bridge_services_in, ["carState", "deviceState"]))
|
||||
|
||||
|
||||
@@ -106,15 +106,12 @@ def or_(*fns):
|
||||
def and_(*fns):
|
||||
return lambda *args: operator.and_(*(fn(*args) for fn in fns))
|
||||
|
||||
def not_(*fns):
|
||||
return lambda *args: operator.not_(*(fn(*args) for fn in fns))
|
||||
|
||||
procs = [
|
||||
DaemonProcess("manage_athenad", "openpilot.system.athena.manage_athenad", "AthenadPid"),
|
||||
|
||||
NativeProcess("loggerd", "openpilot/system/loggerd", ["./loggerd"], logging),
|
||||
NativeProcess("encoderd", "openpilot/system/loggerd", ["./encoderd"], only_onroad),
|
||||
NativeProcess("stream_encoderd", "openpilot/system/loggerd", ["./encoderd", "--stream"], or_(and_(livestream, not_(iscar)), notcar)),
|
||||
NativeProcess("stream_encoderd", "openpilot/system/loggerd", ["./encoderd", "--stream"], or_(livestream, notcar)),
|
||||
PythonProcess("logmessaged", "openpilot.system.logmessaged", always_run),
|
||||
|
||||
NativeProcess("camerad", "openpilot/system/camerad", ["./camerad"], or_(driverview, livestream), enabled=not WEBCAM),
|
||||
@@ -159,7 +156,7 @@ procs = [
|
||||
|
||||
# debug procs
|
||||
NativeProcess("bridge", "openpilot/cereal/messaging", ["./bridge"], notcar),
|
||||
PythonProcess("webrtcd", "openpilot.system.webrtc.webrtcd", or_(and_(livestream, not_(iscar)), notcar)),
|
||||
PythonProcess("webrtcd", "openpilot.system.webrtc.webrtcd", or_(livestream, notcar)),
|
||||
PythonProcess("joystick", "openpilot.tools.joystick.joystick_control", and_(joystick, iscar)),
|
||||
|
||||
# sunnylink <3
|
||||
|
||||
@@ -23,9 +23,9 @@ def post_stream_request(body: StreamRequestBody) -> dict:
|
||||
ret["time"] = (t_end - t_start) * 1000
|
||||
return ret
|
||||
except requests.ConnectTimeout as e:
|
||||
raise Exception("webrtc took too long to respond.") from e
|
||||
raise Exception("device took too long to respond.") from e
|
||||
except requests.ConnectionError as e:
|
||||
raise Exception("webrtc server on device is not running.") from e
|
||||
raise Exception("turn car ignition off to use livestreaming.") from e
|
||||
|
||||
|
||||
def wait_for_webrtcd(max_retries: float = 10) -> None:
|
||||
@@ -37,4 +37,4 @@ def wait_for_webrtcd(max_retries: float = 10) -> None:
|
||||
except requests.ConnectionError:
|
||||
attempts += 1
|
||||
time.sleep(0.5)
|
||||
raise TimeoutError("webrtcd did not initialize in time.")
|
||||
raise TimeoutError("livestreaming service did not initialize in time.")
|
||||
|
||||
@@ -21,10 +21,16 @@ from typing import Any
|
||||
from openpilot.system.webrtc.helpers import StreamRequestBody
|
||||
from openpilot.system.webrtc.schema import generate_field
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.cereal import messaging, log
|
||||
|
||||
SESSION_TIMEOUT_SECONDS = 300
|
||||
|
||||
|
||||
# ice candidate parser for logging
|
||||
def _ice_candidates(sdp: str) -> list[str]:
|
||||
return [line.removeprefix("a=") for line in sdp.splitlines() if line.startswith("a=candidate:")]
|
||||
|
||||
# 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
|
||||
def _default_route_ip() -> str | None:
|
||||
@@ -253,7 +259,7 @@ class StreamSession:
|
||||
self._cleanup_lock = asyncio.Lock()
|
||||
self._cleanup_done = False
|
||||
self.logger = logging.getLogger("webrtcd")
|
||||
self.logger.info(
|
||||
cloudlog.warning(
|
||||
"New stream session (%s), video cameras %s, video enabled %s, incoming services %s, outgoing services %s",
|
||||
self.identifier, [t.id for t in self.video_tracks], body.enabled, body.bridge_services_in, body.bridge_services_out,
|
||||
)
|
||||
@@ -329,9 +335,12 @@ class StreamSession:
|
||||
async def run(self):
|
||||
try:
|
||||
self.params.put("LivestreamRequestKeyframe", True)
|
||||
|
||||
# avoid datachannel race by adding messange_handler immediately
|
||||
self.stream.set_message_handler(self.message_handler)
|
||||
|
||||
await asyncio.wait_for(self.stream.wait_for_connection(), timeout=15)
|
||||
if self.stream.has_messaging_channel():
|
||||
self.stream.set_message_handler(self.message_handler)
|
||||
if self.incoming_bridge is not None:
|
||||
await self.shared_pub_master.add_services_if_needed(self.incoming_bridge_services)
|
||||
if self.outgoing_bridge is not None:
|
||||
@@ -341,14 +350,18 @@ class StreamSession:
|
||||
if self.bitrate_controller is not None:
|
||||
self.bitrate_controller.start()
|
||||
|
||||
self.logger.info("Stream session (%s) connected", self.identifier)
|
||||
with cloudlog.ctx(session_id=self.identifier):
|
||||
cloudlog.warning("webrtcd.session.connected")
|
||||
if self.is_body:
|
||||
await self.run_body_session()
|
||||
else:
|
||||
await self.run_normal_session()
|
||||
self.logger.info("Stream session (%s) ended", self.identifier)
|
||||
with cloudlog.ctx(session_id=self.identifier):
|
||||
cloudlog.warning("webrtcd.session.ended")
|
||||
except Exception:
|
||||
self.logger.exception("Stream session failure")
|
||||
with cloudlog.ctx(session_id=self.identifier):
|
||||
cloudlog.exception("webrtcd.session.exception")
|
||||
finally:
|
||||
await self.post_run_cleanup()
|
||||
|
||||
@@ -422,15 +435,25 @@ async def handle_get_stream(state: ServerState, raw_body: bytes, content_type: s
|
||||
stream_dict[session.identifier] = session
|
||||
try:
|
||||
answer = await asyncio.wait_for(session.get_answer(), timeout=30)
|
||||
cloudlog.event(
|
||||
"webrtcd.session.ice_candidates",
|
||||
session_id=session.identifier,
|
||||
offer_candidates=_ice_candidates(body.sdp),
|
||||
answer_candidates=_ice_candidates(answer.sdp),
|
||||
)
|
||||
except TimeoutError:
|
||||
await session.stop()
|
||||
stream_dict.pop(session.identifier, None)
|
||||
logging.getLogger("webrtcd").exception("Timed out creating stream answer")
|
||||
with cloudlog.ctx(session_id=session.identifier):
|
||||
cloudlog.warning("webrtcd.session.answer_timeout")
|
||||
raise
|
||||
except Exception:
|
||||
await session.stop()
|
||||
stream_dict.pop(session.identifier, None)
|
||||
logging.getLogger("webrtcd").exception("Failed to create stream answer")
|
||||
with cloudlog.ctx(session_id=session.identifier):
|
||||
cloudlog.exception("webrtcd.session.answer_exception")
|
||||
raise
|
||||
session.start()
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ def generate_chunked_model(driving_pkl: Path) -> dict:
|
||||
|
||||
|
||||
def create_metadata_json(models: list, output_dir: Path, custom_name=None, short_name=None, is_20hz=False, upstream_branch="unknown",
|
||||
onnx_sha256=None) -> None:
|
||||
onnx_sha256=None, is_big=False) -> None:
|
||||
bundle_json = {
|
||||
"short_name": short_name,
|
||||
"display_name": custom_name or upstream_branch,
|
||||
@@ -149,6 +149,7 @@ def create_metadata_json(models: list, output_dir: Path, custom_name=None, short
|
||||
"generation": "-1",
|
||||
"build_time": datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"overrides": {},
|
||||
"is_big": is_big,
|
||||
"models": models,
|
||||
}
|
||||
|
||||
@@ -186,6 +187,8 @@ if __name__ == "__main__":
|
||||
print(f"No driving_tinygrad.pkl found in {_output_dir}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
is_big = _driving_pkl.name.startswith('big_')
|
||||
|
||||
if _pkl:
|
||||
new_pkl = _output_dir / f"driving_{_pkl}_tinygrad.pkl"
|
||||
if not new_pkl.exists():
|
||||
@@ -196,4 +199,4 @@ if __name__ == "__main__":
|
||||
_model_metadata = generate_chunked_model(_driving_pkl)
|
||||
_onnx_sha256 = _hash_onnx_files(Path(args.model_dir))
|
||||
create_metadata_json([_model_metadata], _output_dir, args.custom_name, _short_name, args.is_20hz, args.upstream_branch,
|
||||
onnx_sha256=_onnx_sha256)
|
||||
onnx_sha256=_onnx_sha256, is_big=is_big)
|
||||
|
||||
Reference in New Issue
Block a user