From 6940782024676a60979e177dea10a1ff28345e11 Mon Sep 17 00:00:00 2001 From: Fritz Heiden Date: Mon, 14 Apr 2025 13:59:59 +0200 Subject: [PATCH] feat: add data channel to webrtc connection --- www/src/services/webrtc-service.js | 31 ++++++++++++++++++++-- www/src/views/devices/integration-view.jsx | 9 ++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/www/src/services/webrtc-service.js b/www/src/services/webrtc-service.js index ad0c82a..e347051 100644 --- a/www/src/services/webrtc-service.js +++ b/www/src/services/webrtc-service.js @@ -8,10 +8,12 @@ function WebRTCService() { const STATE_CLOSED = "closed"; const STATE_FAILED = "failed"; const ICE_CONNECTION_STATE_CHANGE_EVENT = "iceconnectionstatechange"; + const DATA_CHANNEL_OPEN_EVENT = "datachannelopen"; let videoElement; let peerConnection; let peerId; + let dataChannel; let eventEmitter = new EventEmitter(); @@ -57,12 +59,19 @@ function WebRTCService() { console.log("Negotiation needed"); negotiate(targetId); }; + dataChannel = peerConnection.createDataChannel("data"); + dataChannel.addEventListener("open", () => { + eventEmitter.dispatchEvent(DATA_CHANNEL_OPEN_EVENT); + }); negotiate(targetId); } - + function disconnect() { peerConnection.close(); - eventEmitter.dispatchEvent(ICE_CONNECTION_STATE_CHANGE_EVENT, peerConnection.iceConnectionState); + eventEmitter.dispatchEvent( + ICE_CONNECTION_STATE_CHANGE_EVENT, + peerConnection.iceConnectionState + ); } async function negotiate(targetId) { @@ -125,12 +134,27 @@ function WebRTCService() { peerConnection.addIceCandidate(iceCandidate); } + function sendDataString(data) { + if (!dataChannel) return; + if (dataChannel.readyState !== "open") return; + dataChannel.send(data); + } + + function sendDataJson(data) { + let dataJson = JSON.stringify(data); + sendDataString(dataJson); + } + function onStateChanged(callback) { eventEmitter.on(ICE_CONNECTION_STATE_CHANGE_EVENT, () => { callback(peerConnection.iceConnectionState); }); } + function onDataChannelOpen(callback) { + eventEmitter.on(DATA_CHANNEL_OPEN_EVENT, callback); + } + function getConfiguration() { return { iceServers: [{ urls: "stun:stun.l.google.com:19302" }], @@ -155,7 +179,10 @@ function WebRTCService() { disconnect, setVideoElement, getVideoElement, + sendDataString, + sendDataJson, onStateChanged, + onDataChannelOpen, }; } diff --git a/www/src/views/devices/integration-view.jsx b/www/src/views/devices/integration-view.jsx index 8aafcad..e10ff32 100644 --- a/www/src/views/devices/integration-view.jsx +++ b/www/src/views/devices/integration-view.jsx @@ -22,6 +22,7 @@ function IntegrationView(props) { connectionState() === WebRTCService.STATE_CLOSED ); WebRTCService.onStateChanged(handleConnectionStateChanged); + WebRTCService.onDataChannelOpen(handleDataChannelOpen); let videoElement = null; createEffect(() => { @@ -40,7 +41,7 @@ function IntegrationView(props) { async function setIntegrationFromUrl() { let integrationId = UrlUtils.getQueryParameter("id"); if (!integrationId) return; - let integration = await DeviceService.getIntegration(integrationId) + let integration = await DeviceService.getIntegration(integrationId); setIntegration(integration); } @@ -58,6 +59,12 @@ function IntegrationView(props) { setConnectionState(state); } + function handleDataChannelOpen() { + setInterval(() => { + WebRTCService.sendDataJson({ message: "ping" }); + }, 1000); + } + return (