From 25fb099c4484601dc788012db49296d1e7ed462d Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:00:08 +0000 Subject: [PATCH] android, desktop: fix always connecting state in call (#4911) --- .../src/commonMain/resources/assets/www/call.js | 14 ++++++++++++-- packages/simplex-chat-webrtc/src/call.ts | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js index 571c494c7c..68b2f1bf54 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js @@ -34,6 +34,9 @@ var useWorker = false; var isDesktop = false; var localizedState = ""; var localizedDescription = ""; +// When one side of a call sends candidates tot fast (until local & remote descriptions are set), that candidates +// will be stored here and then set when the call will be ready to process them +let afterCallInitializedCandidates = []; const processCommand = (function () { const defaultIceServers = [ { urls: ["stuns:stun.simplex.im:443"] }, @@ -234,6 +237,8 @@ const processCommand = (function () { const pc = activeCall.connection; const offer = await pc.createOffer(); await pc.setLocalDescription(offer); + addIceCandidates(pc, afterCallInitializedCandidates); + afterCallInitializedCandidates = []; // for debugging, returning the command for callee to use // resp = { // type: "offer", @@ -272,6 +277,8 @@ const processCommand = (function () { const answer = await pc.createAnswer(); await pc.setLocalDescription(answer); addIceCandidates(pc, remoteIceCandidates); + addIceCandidates(pc, afterCallInitializedCandidates); + afterCallInitializedCandidates = []; // same as command for caller to use resp = { type: "answer", @@ -297,17 +304,20 @@ const processCommand = (function () { // console.log("answer remoteIceCandidates", JSON.stringify(remoteIceCandidates)) await pc.setRemoteDescription(new RTCSessionDescription(answer)); addIceCandidates(pc, remoteIceCandidates); + addIceCandidates(pc, afterCallInitializedCandidates); + afterCallInitializedCandidates = []; resp = { type: "ok" }; } break; case "ice": + const remoteIceCandidates = parse(command.iceCandidates); if (pc) { - const remoteIceCandidates = parse(command.iceCandidates); addIceCandidates(pc, remoteIceCandidates); resp = { type: "ok" }; } else { - resp = { type: "error", message: "ice: call not started" }; + afterCallInitializedCandidates.push(...remoteIceCandidates); + resp = { type: "error", message: "ice: call not started yet, will add candidates later" }; } break; case "media": diff --git a/packages/simplex-chat-webrtc/src/call.ts b/packages/simplex-chat-webrtc/src/call.ts index 19682249e9..2e9a58750c 100644 --- a/packages/simplex-chat-webrtc/src/call.ts +++ b/packages/simplex-chat-webrtc/src/call.ts @@ -219,6 +219,9 @@ var useWorker = false var isDesktop = false var localizedState = "" var localizedDescription = "" +// When one side of a call sends candidates tot fast (until local & remote descriptions are set), that candidates +// will be stored here and then set when the call will be ready to process them +let afterCallInitializedCandidates: RTCIceCandidateInit[] = [] const processCommand = (function () { type RTCRtpSenderWithEncryption = RTCRtpSender & { @@ -445,6 +448,8 @@ const processCommand = (function () { const pc = activeCall.connection const offer = await pc.createOffer() await pc.setLocalDescription(offer) + addIceCandidates(pc, afterCallInitializedCandidates) + afterCallInitializedCandidates = [] // for debugging, returning the command for callee to use // resp = { // type: "offer", @@ -481,6 +486,8 @@ const processCommand = (function () { const answer = await pc.createAnswer() await pc.setLocalDescription(answer) addIceCandidates(pc, remoteIceCandidates) + addIceCandidates(pc, afterCallInitializedCandidates) + afterCallInitializedCandidates = [] // same as command for caller to use resp = { type: "answer", @@ -503,16 +510,19 @@ const processCommand = (function () { // console.log("answer remoteIceCandidates", JSON.stringify(remoteIceCandidates)) await pc.setRemoteDescription(new RTCSessionDescription(answer)) addIceCandidates(pc, remoteIceCandidates) + addIceCandidates(pc, afterCallInitializedCandidates) + afterCallInitializedCandidates = [] resp = {type: "ok"} } break case "ice": + const remoteIceCandidates: RTCIceCandidateInit[] = parse(command.iceCandidates) if (pc) { - const remoteIceCandidates: RTCIceCandidateInit[] = parse(command.iceCandidates) addIceCandidates(pc, remoteIceCandidates) resp = {type: "ok"} } else { - resp = {type: "error", message: "ice: call not started"} + afterCallInitializedCandidates.push(...remoteIceCandidates) + resp = {type: "error", message: "ice: call not started yet, will add candidates later"} } break case "media":