From 272b16ee1c0540cb52f08182dbde8b098527cc91 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 13 Jun 2023 20:34:45 +0200 Subject: [PATCH] webrtc: accept `iceServers: []` provided in `POST /webrtc`, support trickle ICE Thanks https://github.com/ayufan/camera-streamer/pull/65 --- RELEASE.md | 1 + cmd/camera-streamer/opts.c | 1 + html/control.html | 43 +++++----- html/webrtc.html | 98 ++++++++++----------- output/webrtc/webrtc.cc | 172 ++++++++++++++++++++++++++++++------- output/webrtc/webrtc.h | 1 + util/http/json.hh | 27 ++++++ 7 files changed, 239 insertions(+), 104 deletions(-) create mode 100644 util/http/json.hh diff --git a/RELEASE.md b/RELEASE.md index a2b56fb..b8b20d2 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -9,6 +9,7 @@ - http: change `/option` to accept `device=`, `key=`, and `value=` - device: show stddev estimates to measure frame pacing - webrtc: allow to specify `--webrtc-ice_servers=` on command line +- webrtc: accept `iceServers:[{urls:[],username:,password:}]` provided in `POST /webrtc` ## Variants diff --git a/cmd/camera-streamer/opts.c b/cmd/camera-streamer/opts.c index b0c48c7..756dd29 100644 --- a/cmd/camera-streamer/opts.c +++ b/cmd/camera-streamer/opts.c @@ -132,6 +132,7 @@ option_t all_options[] = { DEFINE_OPTION_DEFAULT(rtsp, port, uint, "8554", "Set the RTSP server port (default: 8854)."), DEFINE_OPTION_PTR(webrtc, ice_servers, list, "Specify ICE servers: [(stun|turn|turns)(:|://)][username:password@]hostname[:port][?transport=udp|tcp|tls)]."), + DEFINE_OPTION_DEFAULT(webrtc, disable_client_ice, bool, "1", "Ignore ICE servers provided in '/webrtc' request."), DEFINE_OPTION_DEFAULT(log, debug, bool, "1", "Enable debug logging."), DEFINE_OPTION_DEFAULT(log, verbose, bool, "1", "Enable verbose logging."), diff --git a/html/control.html b/html/control.html index 98705e9..18f4fc0 100644 --- a/html/control.html +++ b/html/control.html @@ -759,8 +759,11 @@ method: 'POST' }).then(function(response) { return response.json(); - }).then(function(answer) { - rtcPeerConnection = new RTCPeerConnection(rtcPeerConfig); + }).then(function(request) { + rtcPeerConnection = new RTCPeerConnection({ + sdpSemantics: 'unified-plan', + iceServers: request.iceServers + }); rtcPeerConnection.addTransceiver('video', { direction: 'recvonly' }); //pc.addTransceiver('audio', {direction: 'recvonly'}); rtcPeerConnection.addEventListener('track', function(evt) { @@ -771,27 +774,27 @@ view.scrollIntoView(false); } }); - rtcPeerConnection.remote_pc_id = answer.id; - return rtcPeerConnection.setRemoteDescription(answer); + rtcPeerConnection.addEventListener("icecandidate", function(e) { + if (e.candidate) { + return fetch(webrtcURL, { + body: JSON.stringify({ + type: 'remote_candidate', + id: rtcPeerConnection.remote_pc_id, + candidates: [e.candidate] + }), + headers: { 'Content-Type': 'application/json' }, + method: 'POST' + }).catch(function(e) { + console.log("Failed to send ICE WebRTC: "+e); + }); + } + }); + rtcPeerConnection.remote_pc_id = request.id; + return rtcPeerConnection.setRemoteDescription(request); }).then(function() { return rtcPeerConnection.createAnswer(); }).then(function(answer) { return rtcPeerConnection.setLocalDescription(answer); - }).then(function() { - // wait for ICE gathering to complete - return new Promise(function(resolve) { - if (rtcPeerConnection.iceGatheringState === 'complete') { - resolve(); - } else { - function checkState() { - if (rtcPeerConnection.iceGatheringState === 'complete') { - rtcPeerConnection.removeEventListener('icegatheringstatechange', checkState); - resolve(); - } - } - rtcPeerConnection.addEventListener('icegatheringstatechange', checkState); - } - }); }).then(function(answer) { var offer = rtcPeerConnection.localDescription; @@ -807,7 +810,7 @@ }).then(function(response) { return response.json(); }).catch(function(e) { - alert(e); + console.log(e); }); } }) diff --git a/html/webrtc.html b/html/webrtc.html index 226a2f1..d643a3b 100644 --- a/html/webrtc.html +++ b/html/webrtc.html @@ -47,28 +47,13 @@