From 4da0e50a81fce9af93fcbdd827e02e9084bb4d7e Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Tue, 11 Jul 2023 11:05:28 +0300 Subject: [PATCH] Add support HLS mode --- custom_components/webrtc/__init__.py | 36 ++++++++++++++++++- custom_components/webrtc/www/webrtc-camera.js | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/custom_components/webrtc/__init__.py b/custom_components/webrtc/__init__.py index b25d60c..291d01a 100644 --- a/custom_components/webrtc/__init__.py +++ b/custom_components/webrtc/__init__.py @@ -50,6 +50,11 @@ LINKS = {} # 2 3 4 +# DDoS protection against requests to HLS proxy +# streams are additionally protected by a random playlist identifier +HLS_COOKIE = "webrtc-hls-session" +HLS_SESSION = str(uuid.uuid4()) + async def async_setup(hass: HomeAssistantType, config: ConfigType): # 1. Serve lovelace card @@ -68,7 +73,10 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType): # 4. Serve WebSocket API hass.http.register_view(WebSocketView) - # 5. Register webrtc.create_link and webrtc.dash_cast services: + # 5. Serve HLS proxy + hass.http.register_view(HLSView) + + # 6. Register webrtc.create_link and webrtc.dash_cast services: async def create_link(call: ServiceCallType): link_id = call.data["link_id"] @@ -201,6 +209,7 @@ async def get(self, request: web.Request): raise HTTPUnauthorized() ws_server = web.WebSocketResponse(autoclose=False, autoping=False) + ws_server.set_cookie(HLS_COOKIE, HLS_SESSION) await ws_server.prepare(request) try: @@ -235,3 +244,28 @@ async def get(self, request: web.Request): await ws_server.send_json({"type": "error", "value": str(e)}) return ws_server + + +class HLSView(HomeAssistantView): + url = "/api/webrtc/hls/{filename}" + name = "api:webrtc:hls" + requires_auth = False + + async def get(self, request: web.Request, filename: str): + if request.cookies.get(HLS_COOKIE) != HLS_SESSION: + raise HTTPUnauthorized() + + if filename not in ("playlist.m3u8", "init.mp4", "segment.m4s", "segment.ts"): + raise HTTPNotFound() + + hass: HomeAssistantType = request.app["hass"] + entry = hass.data[DOMAIN] + url = "http://localhost:1984/" if isinstance(entry, Server) else entry + url = urljoin(url, "api/hls/" + filename) + "?" + request.query_string + + async with async_get_clientsession(hass).get(url) as r: + if not r.ok: + raise HTTPNotFound() + + body = await r.read() + return web.Response(body=body, content_type=r.content_type) diff --git a/custom_components/webrtc/www/webrtc-camera.js b/custom_components/webrtc/www/webrtc-camera.js index 43ddfe8..3f4a689 100644 --- a/custom_components/webrtc/www/webrtc-camera.js +++ b/custom_components/webrtc/www/webrtc-camera.js @@ -122,6 +122,7 @@ class WebRTCCamera extends VideoRTC { this.setStatus('error', msg.value); break; case 'mse': + case 'hls': case 'mp4': case 'mjpeg': this.setStatus(msg.type.toUpperCase(), this.config.title || '');