mobile: prevent WebRTC call failure/hanging when webview "failed" state happens before 30 sec timeout (#1866)

* mobile: do not end calls

* better way of continue connection and end with timeout

* making data classes instead of classes for making logs informative

* refactor

* update webrtc package version

* refactor

* fix

* clear conneciton timeout on disconnection

* refactor

* v0.2.1

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
Stanislav Dmitrenko 2023-02-01 19:23:28 +00:00 committed by GitHub
parent 4a58ca60ac
commit f22ee1a6cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 25 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@simplex-chat/webrtc",
"version": "0.1.1",
"version": "0.2.1",
"description": "WebRTC call in browser and webview for SimpleX Chat clients",
"main": "dist/call.js",
"types": "dist/call.d.ts",

View file

@ -191,6 +191,7 @@ interface Call {
}
let activeCall: Call | undefined
let answerTimeout = 30_000
const processCommand = (function () {
type RTCRtpSenderWithEncryption = RTCRtpSender & {
@ -294,10 +295,17 @@ const processCommand = (function () {
const iceCandidates = getIceCandidates(pc, config)
const call = {connection: pc, iceCandidates, localMedia: mediaType, localCamera, localStream, remoteStream, aesKey, useWorker}
await setupMediaStreams(call)
let connectionTimeout: number | undefined = setTimeout(connectionHandler, answerTimeout)
pc.addEventListener("connectionstatechange", connectionStateChange)
return call
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)
if (pc.connectionState !== "failed") connectionHandler()
}
async function connectionHandler() {
sendMessageToNative({
resp: {
type: "connection",
@ -310,12 +318,14 @@ const processCommand = (function () {
},
})
if (pc.connectionState == "disconnected" || pc.connectionState == "failed") {
clearConnectionTimeout()
pc.removeEventListener("connectionstatechange", connectionStateChange)
if (activeCall) {
setTimeout(() => sendMessageToNative({resp: {type: "ended"}}), 0)
}
endCall()
} else if (pc.connectionState == "connected") {
clearConnectionTimeout()
const stats = (await pc.getStats()) as Map<string, any>
for (const stat of stats.values()) {
const {type, state} = stat
@ -335,6 +345,13 @@ const processCommand = (function () {
}
}
}
function clearConnectionTimeout() {
if (connectionTimeout) {
clearTimeout(connectionTimeout)
connectionTimeout = undefined
}
}
}
function serialize<T>(x: T): string {