diff --git a/src/components/ha-web-rtc-player.ts b/src/components/ha-web-rtc-player.ts index 5573bc599c..e6276aa5f8 100644 --- a/src/components/ha-web-rtc-player.ts +++ b/src/components/ha-web-rtc-player.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { css, CSSResultGroup, @@ -6,12 +7,13 @@ import { PropertyValues, TemplateResult, } from "lit"; -import { customElement, property, state, query } from "lit/decorators"; +import { customElement, property, query, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import { fireEvent } from "../common/dom/fire_event"; import { + fetchWebRtcClientConfiguration, handleWebRtcOffer, WebRtcAnswer, - fetchWebRtcClientConfiguration, } from "../data/camera"; import type { HomeAssistant } from "../types"; import "./ha-alert"; @@ -39,12 +41,11 @@ class HaWebRtcPlayer extends LitElement { @property({ type: Boolean, attribute: "playsinline" }) public playsInline = false; - @property() public posterUrl!: string; + @property({ attribute: "poster-url" }) public posterUrl?: string; @state() private _error?: string; - // don't cache this, as we remove it on disconnects - @query("#remote-stream") private _videoEl!: HTMLVideoElement; + @query("#remote-stream", true) private _videoEl!: HTMLVideoElement; private _peerConnection?: RTCPeerConnection; @@ -61,7 +62,7 @@ class HaWebRtcPlayer extends LitElement { .muted=${this.muted} ?playsinline=${this.playsInline} ?controls=${this.controls} - .poster=${this.posterUrl} + poster=${ifDefined(this.posterUrl)} @loadeddata=${this._loadedData} > `; @@ -83,20 +84,23 @@ class HaWebRtcPlayer extends LitElement { if (!changedProperties.has("entityid")) { return; } - if (!this._videoEl) { - return; - } this._startWebRtc(); } private async _startWebRtc(): Promise { + console.time("WebRTC"); + this._error = undefined; + console.timeLog("WebRTC", "start clientConfig"); + const clientConfig = await fetchWebRtcClientConfiguration( this.hass, this.entityid ); + console.timeLog("WebRTC", "end clientConfig", clientConfig); + const peerConnection = new RTCPeerConnection(clientConfig.configuration); if (clientConfig.dataChannel) { @@ -111,30 +115,48 @@ class HaWebRtcPlayer extends LitElement { offerToReceiveAudio: true, offerToReceiveVideo: true, }; + + console.timeLog("WebRTC", "start createOffer", offerOptions); + const offer: RTCSessionDescriptionInit = await peerConnection.createOffer(offerOptions); + + console.timeLog("WebRTC", "end createOffer", offer); + + console.timeLog("WebRTC", "start setLocalDescription"); + await peerConnection.setLocalDescription(offer); + console.timeLog("WebRTC", "end setLocalDescription"); + + console.timeLog("WebRTC", "start iceResolver"); + let candidates = ""; // Build an Offer SDP string with ice candidates const iceResolver = new Promise((resolve) => { - peerConnection.addEventListener("icecandidate", async (event) => { + peerConnection.addEventListener("icecandidate", (event) => { if (!event.candidate?.candidate) { resolve(); // Gathering complete return; } + console.timeLog("WebRTC", "iceResolver candidate", event.candidate); candidates += `a=${event.candidate.candidate}\r\n`; }); }); await iceResolver; + + console.timeLog("WebRTC", "end iceResolver", candidates); + const offer_sdp = offer.sdp! + candidates; let webRtcAnswer: WebRtcAnswer; try { + console.timeLog("WebRTC", "start WebRTCOffer", offer_sdp); webRtcAnswer = await handleWebRtcOffer( this.hass, this.entityid, offer_sdp ); + console.timeLog("WebRTC", "end webRtcOffer", webRtcAnswer); } catch (err: any) { this._error = "Failed to start WebRTC stream: " + err.message; peerConnection.close(); @@ -144,6 +166,7 @@ class HaWebRtcPlayer extends LitElement { // Setup callbacks to render remote stream once media tracks are discovered. const remoteStream = new MediaStream(); peerConnection.addEventListener("track", (event) => { + console.timeLog("WebRTC", "track", event); remoteStream.addTrack(event.track); this._videoEl.srcObject = remoteStream; }); @@ -155,7 +178,9 @@ class HaWebRtcPlayer extends LitElement { sdp: webRtcAnswer.answer, }); try { + console.timeLog("WebRTC", "start setRemoteDescription", remoteDesc); await peerConnection.setRemoteDescription(remoteDesc); + console.timeLog("WebRTC", "end setRemoteDescription"); } catch (err: any) { this._error = "Failed to connect WebRTC stream: " + err.message; peerConnection.close(); @@ -182,6 +207,8 @@ class HaWebRtcPlayer extends LitElement { } private _loadedData() { + console.timeLog("WebRTC", "loadedData"); + console.timeEnd("WebRTC"); // @ts-ignore fireEvent(this, "load"); }