diff options
author | Daniel Calviño Sánchez <danxuliu@gmail.com> | 2022-03-31 09:08:26 +0300 |
---|---|---|
committer | Daniel Calviño Sánchez <danxuliu@gmail.com> | 2022-03-31 18:09:57 +0300 |
commit | 0cc75c5b0973976f6ba1827c085f8d43d91b6b59 (patch) | |
tree | 08b832164911ef73d347c5eaccf5e6bb0ff0a0ea /src/utils | |
parent | a7a9e8368a7ac5795a46ab873a55206998dd3c6a (diff) |
Fix reconnections on single media permission changes
Until now the audio and video publishing permissions were handled as a
whole; either the local participant was able to publish both audio and
video or not. However, the permissions API is actually finer grained,
and it is possible to have one without the other. Now the allowed state
of local media is updated based on the publishing permissions, which
automatically starts and stops the tracks as needed. Nevertheless, in
some cases forced reconnections need to be explicitly triggered to
remove tracks from the senders, as well as to start and stop the local
media.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/webrtc/webrtc.js | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/src/utils/webrtc/webrtc.js b/src/utils/webrtc/webrtc.js index bf56c57f6..babd0b519 100644 --- a/src/utils/webrtc/webrtc.js +++ b/src/utils/webrtc/webrtc.js @@ -982,20 +982,41 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local return } - if ((currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) - && (currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO) - && webrtc.webrtc.isLocalMediaActive()) { + if (webrtc.webrtc.isAudioAllowed() === !!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) + && webrtc.webrtc.isVideoAllowed() === !!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO)) { return } - if (!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) - && !(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO) - && !webrtc.webrtc.isLocalMediaActive()) { - return + let hasAudioSenders = false + let hasVideoSenders = false + + webrtc.webrtc.getPeers(null, 'video').forEach(peer => { + // Look for any sender of each kind, even if the sender no longer + // has a track attached to it. + const audioSender = peer.pc.getSenders().find((sender) => sender.kind === 'audio' || (sender.track && sender.track.kind === 'audio') || (sender.trackDisabled && sender.trackDisabled.kind === 'audio')) + const videoSender = peer.pc.getSenders().find((sender) => sender.kind === 'video' || (sender.track && sender.track.kind === 'video') || (sender.trackDisabled && sender.trackDisabled.kind === 'video')) + + hasAudioSenders ||= !!audioSender + hasVideoSenders ||= !!videoSender + }) + + const removeSender = (hasAudioSenders && !(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO)) + || (hasVideoSenders && !(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO)) + + if (currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) { + webrtc.webrtc.allowAudio() + } else { + webrtc.webrtc.disallowAudio() } - // FIXME handle case where only one of the permissions is given - if (!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) + if (currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO) { + webrtc.webrtc.allowVideo() + } else { + webrtc.webrtc.disallowVideo() + } + + if (webrtc.webrtc.isLocalMediaActive() + && !(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) && !(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO)) { startedWithMedia = undefined @@ -1011,6 +1032,46 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local return } + // If a sender kind is no longer allowed a forced reconnection needs to + // be explicitly triggered. Otherwise "removing" the no longer allowed + // track will just set it to null in the sender, which does not trigger + // a "negotiationneeded" event and thus an automatic forced + // reconnection. + if (webrtc.webrtc.isLocalMediaActive() && removeSender) { + let flags = signaling.getCurrentCallFlags() + if (!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO)) { + flags &= ~PARTICIPANT.CALL_FLAG.WITH_AUDIO + } + if (!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO)) { + flags &= ~PARTICIPANT.CALL_FLAG.WITH_VIDEO + } + + // The flags may be updated later if, besides removing a sender, a + // track is also added (for example, when there are both a + // microphone and a camera and audio permissions are removed at the + // same time that video permissions are added). However, at this + // point it is not possible to know if that will happen (getting the + // new track is an async operation and it could fail), so the flags + // are updated only with the known values. + forceReconnect(signaling, flags) + + return + } + + // If media is already active and a track is added "negotiationneeded" + // will be triggered, which in turn will automatically force a + // reconnection. + if (webrtc.webrtc.isLocalMediaActive()) { + return + } + + // If media is not active but the participant does not have publishing + // permissions there is no need to start the media nor reconnect. + if (!(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO) + && !(currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO)) { + return + } + const forceReconnectOnceLocalMediaStarted = (constraints) => { webrtc.off('localMediaStarted', forceReconnectOnceLocalMediaStarted) webrtc.off('localMediaError', forceReconnectOnceLocalMediaError) @@ -1045,7 +1106,11 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local startedWithMedia = undefined - webrtc.startLocalVideo() + const constraints = { + audio: currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_AUDIO, + video: currentParticipant.participantPermissions & PARTICIPANT.PERMISSIONS.PUBLISH_VIDEO, + } + webrtc.startLocalVideo(constraints) } signaling.on('usersInRoom', function(users) { |