90 lines
3.4 KiB
Python

from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Dict, Any, List
from tornado.httpclient import AsyncHTTPClient, HTTPRequest, HTTPError
from urllib.parse import quote
if TYPE_CHECKING:
from ..confighelper import ConfigHelper
API_WEBRTC_URL = "http://localhost:1984/api/webrtc"
class WebRTCBridge:
def __init__(self, config: ConfigHelper):
default_cameras = config.getlist("camera_name", ["Camera"])
self.default_cameras = []
for camera in default_cameras:
self.default_cameras.extend(
[cam.strip() for cam in camera.split(",") if cam.strip()]
)
logging.info(f"WebRTC Bridge initialized with cameras: {self.default_cameras}")
def _parse_cameras(self, cameras) -> List[str]:
if isinstance(cameras, str):
return [cam.strip() for cam in cameras.split(",") if cam.strip()]
elif isinstance(cameras, list):
result = []
for camera in cameras:
if isinstance(camera, str):
result.extend(
[cam.strip() for cam in camera.split(",") if cam.strip()]
)
else:
result.append(str(camera).strip())
return result
else:
return self.default_cameras
def _build_url(self, cameras: List[str]) -> str:
params = "&".join(f"src={quote(cam)}" for cam in cameras if cam)
return f"{API_WEBRTC_URL}?{params}"
async def handle_sdp(self, data: Dict[str, Any], topic: str) -> Dict[str, Any]:
try:
sdp = data.get("sdp", "")
if not sdp:
return {"type": "error", "message": "Missing SDP in offer"}
cameras = self._parse_cameras(data.get("cameras"))
logging.info(f"Received SDP offer for cameras: {cameras}")
if not cameras:
return {"type": "error", "message": "No cameras specified"}
url = self._build_url(cameras)
http_client = AsyncHTTPClient()
try:
request = HTTPRequest(
url=url,
method="POST",
body=sdp,
headers={
"Content-Type": "application/sdp",
"Accept": "application/sdp",
},
request_timeout=10,
)
logging.debug(f"Sending SDP offer to: {url}")
response = await http_client.fetch(request)
if response.code in (200, 201):
logging.info(f"Received SDP answer for cameras: {cameras}")
return {"type": "answer", "sdp": response.body.decode("utf-8")}
else:
error_msg = response.body.decode("utf-8")
logging.error(f"go2rtc API error {response.code}: {error_msg}")
return {"type": "error", "message": error_msg}
except HTTPError as e:
logging.error(f"HTTP error: {e}")
return {"type": "error", "message": str(e)}
finally:
http_client.close()
except Exception as e:
logging.error(f"SDP handling error: {e}")
return {"type": "error", "message": str(e)}
def load_component(config: ConfigHelper) -> WebRTCBridge:
return WebRTCBridge(config)