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
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2021-11-11 18:19:06 +0300
committerGitHub <noreply@github.com>2021-11-11 18:19:06 +0300
commitf8f6758987a737e72f24b285404c10467c263033 (patch)
treec1f5812477d108d1b8fe5a30bacf5107dbf0594e
parent197208e4543dd331e7e300888e819c32c6dae67b (diff)
parent1a1f7765896416c05bbc3f7cd725063530f4b6aa (diff)
Merge pull request #6475 from nextcloud/backport/6466/stable23
[stable23] Show message about problems in the connection with another participant
-rw-r--r--src/components/CallView/shared/Video.vue84
-rw-r--r--src/utils/webrtc/models/CallParticipantModel.js34
-rw-r--r--src/utils/webrtc/webrtc.js10
3 files changed, 128 insertions, 0 deletions
diff --git a/src/components/CallView/shared/Video.vue b/src/components/CallView/shared/Video.vue
index 8f0d1d2fe..87539b12d 100644
--- a/src/components/CallView/shared/Video.vue
+++ b/src/components/CallView/shared/Video.vue
@@ -83,6 +83,11 @@
:size="36" />
</div>
</transition-group>
+ <div v-if="connectionMessage"
+ :class="connectionMessageClass"
+ class="connection-message">
+ {{ connectionMessage }}
+ </div>
<VideoBottomBar v-bind="$props"
:has-shadow="hasVideo"
:participant-name="participantName" />
@@ -172,6 +177,10 @@ export default {
}
},
+ wasConnectedAtLeastOnce() {
+ return this.model.attributes.connectedAtLeastOnce
+ },
+
isNotConnected() {
return this.model.attributes.connectionState !== ConnectionState.CONNECTED && this.model.attributes.connectionState !== ConnectionState.COMPLETED
},
@@ -180,6 +189,57 @@ export default {
return this.isNotConnected && this.model.attributes.connectionState !== ConnectionState.FAILED_NO_RESTART
},
+ isDisconnected() {
+ return this.model.attributes.connectionState !== ConnectionState.NEW && this.model.attributes.connectionState !== ConnectionState.CHECKING
+ && this.model.attributes.connectionState !== ConnectionState.CONNECTED && this.model.attributes.connectionState !== ConnectionState.COMPLETED
+ },
+
+ /**
+ * Whether the connection to the participant is being tried again.
+ *
+ * The initial connection to the participant is excluded.
+ *
+ * A "failed" connection state will trigger a reconnection, but that may
+ * not immediately change the "negotiating" or "connecting" attributes
+ * (for example, while the new offer requested to the HPB was not
+ * received yet). Similarly both "negotiating" and "connecting" need to
+ * be checked, as the negotiation will start before the connection
+ * attempt is started.
+ */
+ isReconnecting() {
+ return this.model.attributes.connectionState === ConnectionState.FAILED
+ || (!this.model.attributes.initialConnection
+ && (this.model.attributes.negotiating || this.model.attributes.connecting))
+ },
+
+ isNoLongerTryingToReconnect() {
+ return this.model.attributes.connectionState === ConnectionState.FAILED_NO_RESTART
+ },
+
+ connectionMessage() {
+ if (!this.wasConnectedAtLeastOnce && this.isNoLongerTryingToReconnect) {
+ return t('spreed', 'Connection could not be established …')
+ }
+
+ if (this.isNoLongerTryingToReconnect) {
+ return t('spreed', 'Connection was lost and could not be re-established …')
+ }
+
+ if (!this.wasConnectedAtLeastOnce && this.isReconnecting) {
+ return t('spreed', 'Connection could not be established. Trying again …')
+ }
+
+ if (this.isReconnecting) {
+ return t('spreed', 'Connection lost. Trying to reconnect …')
+ }
+
+ if (this.isDisconnected) {
+ return t('spreed', 'Connection problems …')
+ }
+
+ return null
+ },
+
containerClass() {
return {
'videoContainer-dummy': this.placeholderForPromoted,
@@ -214,6 +274,12 @@ export default {
})
},
+ connectionMessageClass() {
+ return {
+ 'below-avatar': this.showBackgroundAndAvatar,
+ }
+ },
+
firstLetterOfGuestName() {
const customName = this.participantName && this.participantName !== t('spreed', 'Guest') ? this.participantName : '?'
return customName.charAt(0)
@@ -514,6 +580,24 @@ export default {
object-fit: cover;
}
+.connection-message {
+ width: 100%;
+
+ position: absolute;
+ top: calc(50% + 50px);
+
+ text-align: center;
+
+ z-index: 1;
+
+ color: white;
+ filter: drop-shadow(1px 1px 4px var(--color-box-shadow));
+}
+
+.connection-message.below-avatar {
+ top: calc(50% + 80px);
+}
+
.speaking-shadow {
position: absolute;
height: 100%;
diff --git a/src/utils/webrtc/models/CallParticipantModel.js b/src/utils/webrtc/models/CallParticipantModel.js
index f10c47aa7..5c260f12c 100644
--- a/src/utils/webrtc/models/CallParticipantModel.js
+++ b/src/utils/webrtc/models/CallParticipantModel.js
@@ -55,6 +55,10 @@ export default function CallParticipantModel(options) {
name: undefined,
internal: undefined,
connectionState: ConnectionState.NEW,
+ negotiating: false,
+ connecting: false,
+ initialConnection: true,
+ connectedAtLeastOnce: false,
stream: null,
// The audio element is part of the model to ensure that it can be
// played if needed even if there is no view for it.
@@ -79,6 +83,7 @@ export default function CallParticipantModel(options) {
this._handleMuteBound = this._handleMute.bind(this)
this._handleUnmuteBound = this._handleUnmute.bind(this)
this._handleExtendedIceConnectionStateChangeBound = this._handleExtendedIceConnectionStateChange.bind(this)
+ this._handleSignalingStateChangeBound = this._handleSignalingStateChange.bind(this)
this._handleChannelMessageBound = this._handleChannelMessage.bind(this)
this._handleRaisedHandBound = this._handleRaisedHand.bind(this)
@@ -96,6 +101,7 @@ CallParticipantModel.prototype = {
destroy() {
if (this.get('peer')) {
this.get('peer').off('extendedIceConnectionStateChange', this._handleExtendedIceConnectionStateChangeBound)
+ this.get('peer').off('signalingStateChange', this._handleSignalingStateChangeBound)
}
this._webRtc.off('peerStreamAdded', this._handlePeerStreamAddedBound)
@@ -232,6 +238,7 @@ CallParticipantModel.prototype = {
if (this.get('peer')) {
this.get('peer').off('extendedIceConnectionStateChange', this._handleExtendedIceConnectionStateChangeBound)
+ this.get('peer').off('signalingStateChange', this._handleSignalingStateChangeBound)
}
this.set('peer', peer)
@@ -239,6 +246,8 @@ CallParticipantModel.prototype = {
// Special case when the participant has no streams.
if (!this.get('peer')) {
this.set('connectionState', ConnectionState.COMPLETED)
+ this.set('negotiating', false)
+ this.set('connecting', false)
this.set('audioAvailable', false)
this.set('speaking', false)
this.set('videoAvailable', false)
@@ -254,9 +263,11 @@ CallParticipantModel.prototype = {
} else {
this._handleExtendedIceConnectionStateChange(this.get('peer').pc.iceConnectionState)
}
+ this._handleSignalingStateChange(this.get('peer').pc.signalingState)
this._handlePeerStreamAdded(this.get('peer'))
this.get('peer').on('extendedIceConnectionStateChange', this._handleExtendedIceConnectionStateChangeBound)
+ this.get('peer').on('signalingStateChange', this._handleSignalingStateChangeBound)
},
_handleExtendedIceConnectionStateChange(extendedIceConnectionState) {
@@ -269,25 +280,38 @@ CallParticipantModel.prototype = {
}
}.bind(this)
+ // "connecting" state is not changed when entering the "disconnected"
+ // state, as it can be entered while still connecting (if done from
+ // "checking") or once already connected (from "connected" or
+ // "completed").
+
switch (extendedIceConnectionState) {
case 'new':
this.set('connectionState', ConnectionState.NEW)
+ this.set('connecting', true)
this.set('audioAvailable', undefined)
this.set('speaking', undefined)
this.set('videoAvailable', undefined)
break
case 'checking':
this.set('connectionState', ConnectionState.CHECKING)
+ this.set('connecting', true)
this.set('audioAvailable', undefined)
this.set('speaking', undefined)
this.set('videoAvailable', undefined)
break
case 'connected':
this.set('connectionState', ConnectionState.CONNECTED)
+ this.set('connecting', false)
+ this.set('initialConnection', false)
+ this.set('connectedAtLeastOnce', true)
setNameForUserFromPeerNick()
break
case 'completed':
this.set('connectionState', ConnectionState.COMPLETED)
+ this.set('connecting', false)
+ this.set('initialConnection', false)
+ this.set('connectedAtLeastOnce', true)
setNameForUserFromPeerNick()
break
case 'disconnected':
@@ -298,18 +322,28 @@ CallParticipantModel.prototype = {
break
case 'failed':
this.set('connectionState', ConnectionState.FAILED)
+ this.set('connecting', false)
+ this.set('initialConnection', false)
break
case 'failed-no-restart':
this.set('connectionState', ConnectionState.FAILED_NO_RESTART)
+ this.set('connecting', false)
+ this.set('initialConnection', false)
break
case 'closed':
this.set('connectionState', ConnectionState.CLOSED)
+ this.set('connecting', false)
+ this.set('initialConnection', false)
break
default:
console.error('Unexpected (extended) ICE connection state: ', extendedIceConnectionState)
}
},
+ _handleSignalingStateChange(signalingState) {
+ this.set('negotiating', signalingState !== 'stable' && signalingState !== 'closed')
+ },
+
setScreenPeer(screenPeer) {
if (screenPeer && this.get('peerId') !== screenPeer.id) {
console.warn('Mismatch between stored peer ID and ID of given screen peer: ', this.get('peerId'), screenPeer.id)
diff --git a/src/utils/webrtc/webrtc.js b/src/utils/webrtc/webrtc.js
index e06bba446..4820ec176 100644
--- a/src/utils/webrtc/webrtc.js
+++ b/src/utils/webrtc/webrtc.js
@@ -849,6 +849,15 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
/**
* @param {object} peer The peer connection to handle the state on
*/
+ function setHandlerForSignalingStateChange(peer) {
+ peer.pc.addEventListener('signalingstatechange', function() {
+ peer.emit('signalingStateChange', peer.pc.signalingState)
+ })
+ }
+
+ /**
+ * @param {object} peer The peer connection to handle the state on
+ */
function setHandlerForOwnIceConnectionStateChange(peer) {
peer.pc.addEventListener('iceconnectionstatechange', function() {
peer.emit('extendedIceConnectionStateChange', peer.pc.iceConnectionState)
@@ -1067,6 +1076,7 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
} else {
setHandlerForIceConnectionStateChange(peer)
setHandlerForConnectionStateChange(peer)
+ setHandlerForSignalingStateChange(peer)
}
setHandlerForNegotiationNeeded(peer)