Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Calviño Sánchez <danxuliu@gmail.com>2021-08-30 14:13:47 +0300
committerDaniel Calviño Sánchez <danxuliu@gmail.com>2021-08-30 16:59:12 +0300
commitfcd82c1d8cd9f4d11dec70dc68ef8cd7dc46226a (patch)
tree673127487ab163f1c6b7884236b10ed83e378010 /src
parent501fb5294dfee1d8a923846c7d92cf074c8486e6 (diff)
Work around Chromium bug of iceConnectionState stuck as "disconnected"
Due to a bug in Chromium the "iceConnectionState" of a RTCPeerConnection may get stuck as "disconnected" even if the connection has already failed. However, in that case "connectionState" does change to "failed", so now its listened too to changes in "connectionState" to handle that case. Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js34
-rw-r--r--src/utils/webrtc/models/CallParticipantModel.js8
-rw-r--r--src/utils/webrtc/models/LocalCallParticipantModel.js8
-rw-r--r--src/utils/webrtc/simplewebrtc/peer.js19
-rw-r--r--src/utils/webrtc/webrtc.js25
5 files changed, 90 insertions, 4 deletions
diff --git a/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js b/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js
index d18774cd8..6d89c63d2 100644
--- a/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js
+++ b/src/utils/webrtc/analyzers/PeerConnectionAnalyzer.js
@@ -136,6 +136,7 @@ function PeerConnectionAnalyzer() {
this._getStatsInterval = null
this._handleIceConnectionStateChangedBound = this._handleIceConnectionStateChanged.bind(this)
+ this._handleConnectionStateChangedBound = this._handleConnectionStateChanged.bind(this)
this._processStatsBound = this._processStats.bind(this)
this._connectionQuality = {
@@ -209,6 +210,7 @@ PeerConnectionAnalyzer.prototype = {
setPeerConnection(peerConnection, peerDirection = null) {
if (this._peerConnection) {
this._peerConnection.removeEventListener('iceconnectionstatechange', this._handleIceConnectionStateChangedBound)
+ this._peerConnection.removeEventListener('connectionstatechange', this._handleConnectionStateChangedBound)
this._stopGetStatsInterval()
}
@@ -220,6 +222,7 @@ PeerConnectionAnalyzer.prototype = {
if (this._peerConnection) {
this._peerConnection.addEventListener('iceconnectionstatechange', this._handleIceConnectionStateChangedBound)
+ this._peerConnection.addEventListener('connectionstatechange', this._handleConnectionStateChangedBound)
this._handleIceConnectionStateChangedBound()
}
},
@@ -265,7 +268,10 @@ PeerConnectionAnalyzer.prototype = {
// Note that even if the ICE connection state is "disconnected" the
// connection is actually active, media is still transmitted, and the
// stats are properly updated.
- if (!this._peerConnection || (this._peerConnection.iceConnectionState !== 'connected' && this._peerConnection.iceConnectionState !== 'completed' && this._peerConnection.iceConnectionState !== 'disconnected')) {
+ // "connectionState === failed" needs to be checked due to a Chromium
+ // bug in which "iceConnectionState" can get stuck as "disconnected"
+ // even if the connection has already failed.
+ if (!this._peerConnection || (this._peerConnection.iceConnectionState !== 'connected' && this._peerConnection.iceConnectionState !== 'completed' && this._peerConnection.iceConnectionState !== 'disconnected') || this._peerConnection.connectionState === 'failed') {
this._setConnectionQualityAudio(CONNECTION_QUALITY.UNKNOWN)
this._setConnectionQualityVideo(CONNECTION_QUALITY.UNKNOWN)
@@ -295,13 +301,37 @@ PeerConnectionAnalyzer.prototype = {
}, 1000)
},
+ _handleConnectionStateChanged() {
+ if (!this._peerConnection) {
+ return
+ }
+
+ if (this._peerConnection.connectionState !== 'failed') {
+ return
+ }
+
+ if (this._peerConnection.iceConnectionState === 'failed') {
+ return
+ }
+
+ // Work around Chromium bug where "iceConnectionState" never changes
+ // to "failed" (it stays as "disconnected"). When that happens
+ // "connectionState" actually does change to "failed", so the normal
+ // handling of "iceConnectionState === failed" is triggered here.
+
+ this._handleIceConnectionStateChanged()
+ },
+
_stopGetStatsInterval() {
window.clearInterval(this._getStatsInterval)
this._getStatsInterval = null
},
_processStats(stats) {
- if (!this._peerConnection || (this._peerConnection.iceConnectionState !== 'connected' && this._peerConnection.iceConnectionState !== 'completed' && this._peerConnection.iceConnectionState !== 'disconnected')) {
+ // "connectionState === failed" needs to be checked due to a Chromium
+ // bug in which "iceConnectionState" can get stuck as "disconnected"
+ // even if the connection has already failed.
+ if (!this._peerConnection || (this._peerConnection.iceConnectionState !== 'connected' && this._peerConnection.iceConnectionState !== 'completed' && this._peerConnection.iceConnectionState !== 'disconnected') || this._peerConnection.connectionState === 'failed') {
return
}
diff --git a/src/utils/webrtc/models/CallParticipantModel.js b/src/utils/webrtc/models/CallParticipantModel.js
index 3237bdb9c..2e40ccbd8 100644
--- a/src/utils/webrtc/models/CallParticipantModel.js
+++ b/src/utils/webrtc/models/CallParticipantModel.js
@@ -282,7 +282,13 @@ CallParticipantModel.prototype = {
}
// Reset state that depends on the Peer object.
- this._handleExtendedIceConnectionStateChange(this.get('peer').pc.iceConnectionState)
+ if (this.get('peer').pc.connectionState === 'failed' && this.get('peer').pc.iceConnectionState === 'disconnected') {
+ // Work around Chromium bug where "iceConnectionState" gets stuck as
+ // "disconnected" even if the connection already failed.
+ this._handleExtendedIceConnectionStateChange(this.get('peer').pc.connectionState)
+ } else {
+ this._handleExtendedIceConnectionStateChange(this.get('peer').pc.iceConnectionState)
+ }
this._handlePeerStreamAdded(this.get('peer'))
this.get('peer').on('extendedIceConnectionStateChange', this._handleExtendedIceConnectionStateChangeBound)
diff --git a/src/utils/webrtc/models/LocalCallParticipantModel.js b/src/utils/webrtc/models/LocalCallParticipantModel.js
index efabab337..f678da597 100644
--- a/src/utils/webrtc/models/LocalCallParticipantModel.js
+++ b/src/utils/webrtc/models/LocalCallParticipantModel.js
@@ -127,7 +127,13 @@ LocalCallParticipantModel.prototype = {
}
// Reset state that depends on the Peer object.
- this._handleExtendedIceConnectionStateChange(this.get('peer').pc.iceConnectionState)
+ if (this.get('peer').pc.connectionState === 'failed' && this.get('peer').pc.iceConnectionState === 'disconnected') {
+ // Work around Chromium bug where "iceConnectionState" gets stuck as
+ // "disconnected" even if the connection already failed.
+ this._handleExtendedIceConnectionStateChange(this.get('peer').pc.connectionState)
+ } else {
+ this._handleExtendedIceConnectionStateChange(this.get('peer').pc.iceConnectionState)
+ }
this.get('peer').on('extendedIceConnectionStateChange', this._handleExtendedIceConnectionStateChangeBound)
},
diff --git a/src/utils/webrtc/simplewebrtc/peer.js b/src/utils/webrtc/simplewebrtc/peer.js
index 5e40e6d9b..efd9e89be 100644
--- a/src/utils/webrtc/simplewebrtc/peer.js
+++ b/src/utils/webrtc/simplewebrtc/peer.js
@@ -92,6 +92,25 @@ function Peer(options) {
break
}
})
+ this.pc.addEventListener('connectionstatechange', function() {
+ if (self.pc.connectionState !== 'failed') {
+ return
+ }
+
+ if (self.pc.iceConnectionState === 'failed') {
+ return
+ }
+
+ // Work around Chromium bug where "iceConnectionState" never changes to
+ // "failed" (it stays as "disconnected"). When that happens
+ // "connectionState" actually does change to "failed", so the normal
+ // handling of "iceConnectionState === failed" is triggered here.
+
+ if (self.pc.localDescription.type === 'offer') {
+ self.parent.emit('iceFailed', self)
+ self.send('connectivityError')
+ }
+ })
this.pc.addEventListener('signalingstatechange', this.emit.bind(this, 'signalingStateChange'))
this.logger = this.parent.logger
diff --git a/src/utils/webrtc/webrtc.js b/src/utils/webrtc/webrtc.js
index 88af1971b..01850d72d 100644
--- a/src/utils/webrtc/webrtc.js
+++ b/src/utils/webrtc/webrtc.js
@@ -789,6 +789,30 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
/**
* @param peer
*/
+ function setHandlerForConnectionStateChange(peer) {
+ peer.pc.addEventListener('connectionstatechange', function() {
+ if (peer.pc.connectionState !== 'failed') {
+ return
+ }
+
+ if (peer.pc.iceConnectionState === 'failed') {
+ return
+ }
+
+ // Work around Chromium bug where "iceConnectionState" never changes
+ // to "failed" (it stays as "disconnected"). When that happens
+ // "connectionState" actually does change to "failed", so the normal
+ // handling of "iceConnectionState === failed" is triggered here.
+
+ peer.emit('extendedIceConnectionStateChange', peer.pc.connectionState)
+
+ handleIceConnectionStateFailed(peer)
+ })
+ }
+
+ /**
+ * @param peer
+ */
function setHandlerForOwnIceConnectionStateChange(peer) {
peer.pc.addEventListener('iceconnectionstatechange', function() {
peer.emit('extendedIceConnectionStateChange', peer.pc.iceConnectionState)
@@ -1000,6 +1024,7 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
setHandlerForOwnIceConnectionStateChange(peer)
} else {
setHandlerForIceConnectionStateChange(peer)
+ setHandlerForConnectionStateChange(peer)
}
setHandlerForNegotiationNeeded(peer)