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 43ea0265f0..637403ec81 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js @@ -54,7 +54,6 @@ let inactiveCallMediaSources = { let activeCall; let notConnectedCall; let answerTimeout = 30000; -// How long a call is allowed to stay disconnected before it is ended let reconnectTimeout = 30000; var useWorker = false; var isDesktop = false; @@ -208,8 +207,7 @@ const processCommand = (function () { localOrPeerMediaSourcesChanged(call); await setupMediaStreams(call); let connectionTimeout = setTimeout(connectionHandler, answerTimeout); - // disconnect call if it does not reconnect in time - let disconnectedTimeout; + let reconnectingTimeout; let wasConnected = false; if (pc.connectionState) { pc.addEventListener("connectionstatechange", connectionStateChange); @@ -221,44 +219,65 @@ const processCommand = (function () { async function connectionStateChange() { // "failed" means the second party did not answer in time (15 sec timeout in Chrome WebView) // See https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/p2p/base/p2p_constants.cc;l=70) - // Once the call is connected failed needs to work otherwise the call would go on forever if (pc.connectionState !== "failed" || wasConnected) connectionHandler(); } - async function connectionHandler() { - if (reconnecting()) { - // The call was connected and lost connection should be reconnected without any action as long as connection issue is fixed - // call only ends if it doesn't reconnect within reconnectTimeout timeframe. - // "reconnecting" is reported instead of "disconnected"/"failed" - if (disconnectedTimeout === undefined) { - sendConnectionState("reconnecting"); - disconnectedTimeout = setTimeout(() => { - disconnectedTimeout = undefined; - if (activeCall === call && !connected()) { - // call ends because call did not reconnect - // makes sure to set call to disconnected - sendConnectionState("disconnected"); - terminateCall(); - } - }, reconnectTimeout); + async function connectionHandler(reconnectTimedOut = false) { + var _a; + let state = (_a = pc.connectionState) !== null && _a !== void 0 ? _a : (pc.iceConnectionState != "completed" && pc.iceConnectionState != "checking" + ? pc.iceConnectionState + : pc.iceConnectionState == "completed" + ? "connected" + : "connecting"); /* webView 69-70 doesn't have connectionState yet */ + if (wasConnected) { + if (reconnectTimedOut) { + reconnectingTimeout = undefined; + if (activeCall !== call || state == "connected") + return; + state = "disconnected"; } - return; - } - if (wasConnected && connecting()) { - return; - } - if (connected()) { - const restored = wasConnected; - wasConnected = true; - clearDisconnectedTimeout(); - clearConnectionTimeout(); - // reconnecting turns back to connected - // client keeps original call duration - if (restored) { - sendConnectionState(); + else if (state == "disconnected" || state == "failed") { + if (reconnectingTimeout !== undefined) + return; + reconnectingTimeout = setTimeout(() => connectionHandler(true), reconnectTimeout); + state = "reconnecting"; + } + else if (state == "connecting" || state == "new") { return; } - sendConnectionState(); + } + sendMessageToNative({ + resp: { + type: "connection", + state: { + connectionState: state, + iceConnectionState: pc.iceConnectionState, + iceGatheringState: pc.iceGatheringState, + signalingState: pc.signalingState, + }, + }, + }); + if (state == "disconnected" || state == "failed") { + clearConnectionTimeout(); + clearTimeout(reconnectingTimeout); + if (pc.connectionState) { + pc.removeEventListener("connectionstatechange", connectionStateChange); + } + else { + pc.removeEventListener("iceconnectionstatechange", connectionStateChange); + } + if (activeCall) { + setTimeout(() => sendMessageToNative({ resp: { type: "ended" } }), 0); + } + endCall(); + } + else if (state == "connected") { + clearConnectionTimeout(); + clearTimeout(reconnectingTimeout); + reconnectingTimeout = undefined; + if (wasConnected) + return; + wasConnected = true; const stats = (await pc.getStats()); for (const stat of stats.values()) { const { type, state } = stat; @@ -276,65 +295,7 @@ const processCommand = (function () { break; } } - return; } - sendConnectionState(); - if (disconnected() || failed()) { - // the call was not connected - terminateCall(); - } - } - function sendConnectionState(state) { - var _a; - sendMessageToNative({ - resp: { - type: "connection", - state: { - connectionState: (_a = state !== null && state !== void 0 ? state : pc.connectionState) !== null && _a !== void 0 ? _a : (pc.iceConnectionState != "completed" && pc.iceConnectionState != "checking" - ? pc.iceConnectionState - : pc.iceConnectionState == "completed" - ? "connected" - : "connecting") /* webView 69-70 doesn't have connectionState yet */, - iceConnectionState: pc.iceConnectionState, - iceGatheringState: pc.iceGatheringState, - signalingState: pc.signalingState, - }, - }, - }); - } - // webView 69-70 has no connectionState, and it reports a connected call as "completed" as well - function connected() { - return (pc.connectionState == "connected" || - (!pc.connectionState && (pc.iceConnectionState == "connected" || pc.iceConnectionState == "completed"))); - } - function connecting() { - return (pc.connectionState == "connecting" || - pc.connectionState == "new" || - (!pc.connectionState && (pc.iceConnectionState == "checking" || pc.iceConnectionState == "new"))); - } - function disconnected() { - return pc.connectionState == "disconnected" || (!pc.connectionState && pc.iceConnectionState == "disconnected"); - } - function failed() { - return pc.connectionState == "failed" || (!pc.connectionState && pc.iceConnectionState == "failed"); - } - // the connected call lost connection and could reconnect - function reconnecting() { - return wasConnected && (disconnected() || failed()); - } - function terminateCall() { - clearConnectionTimeout(); - clearDisconnectedTimeout(); - if (pc.connectionState) { - pc.removeEventListener("connectionstatechange", connectionStateChange); - } - else { - pc.removeEventListener("iceconnectionstatechange", connectionStateChange); - } - if (activeCall) { - setTimeout(() => sendMessageToNative({ resp: { type: "ended" } }), 0); - } - endCall(); } function clearConnectionTimeout() { if (connectionTimeout) { @@ -342,12 +303,6 @@ const processCommand = (function () { connectionTimeout = undefined; } } - function clearDisconnectedTimeout() { - if (disconnectedTimeout !== undefined) { - clearTimeout(disconnectedTimeout); - disconnectedTimeout = undefined; - } - } } function serialize(x) { return LZString.compressToBase64(JSON.stringify(x));