4485cbf702
Split monolithic files into focused modules: - app/core: settings, logging, lifecycle - app/signaling: websocket server, ICE parser, message models - app/webrtc: peer session, video receiver, frame source - app/vision: pose landmarker wrapper, model config, pose types - app/exercises/dead_bug: detector, metrics, rules, state machine, types - app/rendering: skeleton renderer, status overlay, window display - app/audio: rep announcer - app/diagnostics: perf timer, crash handler - configs: environment-based settings - tests: unit tests for rules, state machine, ICE parser - run.py: entry point
31 lines
774 B
Python
31 lines
774 B
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from typing import Any
|
|
|
|
from aiortc import RTCIceCandidate
|
|
|
|
|
|
def parse_ice(data: dict[str, Any]) -> RTCIceCandidate | None:
|
|
match = re.match(
|
|
r'candidate:(\S+) (\d) (\S+) (\d+) (\S+) (\d+) typ (\S+)(?: raddr (\S+) rport (\d+))?',
|
|
data["candidate"],
|
|
)
|
|
if not match:
|
|
return None
|
|
g = match.groups()
|
|
cand = RTCIceCandidate(
|
|
foundation=g[0],
|
|
component=int(g[1]),
|
|
protocol=g[2].lower(),
|
|
priority=int(g[3]),
|
|
ip=g[4],
|
|
port=int(g[5]),
|
|
type=g[6],
|
|
relatedAddress=g[7],
|
|
relatedPort=int(g[8]) if g[8] else None,
|
|
)
|
|
cand.sdpMid = data.get("sdpMid")
|
|
cand.sdpMLineIndex = data.get("sdpMLineIndex", 0)
|
|
return cand
|