diff --git a/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ColibriSessionManager.kt b/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ColibriSessionManager.kt index ebd96598bc..802d2ec3b0 100644 --- a/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ColibriSessionManager.kt +++ b/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ColibriSessionManager.kt @@ -90,7 +90,6 @@ data class ParticipantAllocationParameters( val statsId: String?, val region: String?, val sources: EndpointSourceSet, - val supportsSourceNames: Boolean, val useSsrcRewriting: Boolean, val forceMuteAudio: Boolean, val forceMuteVideo: Boolean, diff --git a/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/Extensions.kt b/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/Extensions.kt index a9bcc67c76..483924c0d3 100644 --- a/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/Extensions.kt +++ b/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/Extensions.kt @@ -104,9 +104,7 @@ internal fun ParticipantInfo.toEndpoint( if (create) { setCreate(true) setStatsId(statsId) - if (supportsSourceNames) { - addCapability(Capability.CAP_SOURCE_NAME_SUPPORT) - } + addCapability(Capability.CAP_SOURCE_NAME_SUPPORT) if (supportsPrivateAddresses) { addCapability(Capability.CAP_PRIVATE_ADDRESS_CONNECTIVITY) } diff --git a/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ParticipantInfo.kt b/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ParticipantInfo.kt index 27d04c9eee..e1f20cddff 100644 --- a/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ParticipantInfo.kt +++ b/jicofo-selector/src/main/kotlin/org/jitsi/jicofo/bridge/colibri/ParticipantInfo.kt @@ -30,7 +30,6 @@ class ParticipantInfo( val statsId = parameters.statsId val useSctp = parameters.useSctp val medias = parameters.medias - val supportsSourceNames = parameters.supportsSourceNames val supportsPrivateAddresses = parameters.supportsPrivateAddresses val useSsrcRewriting = parameters.useSsrcRewriting val visitor = parameters.visitor @@ -46,7 +45,6 @@ class ParticipantInfo( put("bridge", session.bridge.jid.resourceOrNull.toString()) put("audio_muted", audioMuted) put("video_muted", videoMuted) - put("source_names", supportsSourceNames) put("private_addresses", supportsPrivateAddresses) put("ssrc_rewriting", useSsrcRewriting) put("visitor", visitor) diff --git a/jicofo-selector/src/main/resources/reference.conf b/jicofo-selector/src/main/resources/reference.conf index 1e8a5c4bb2..9e3db5e878 100644 --- a/jicofo-selector/src/main/resources/reference.conf +++ b/jicofo-selector/src/main/resources/reference.conf @@ -236,17 +236,6 @@ jicofo { // session) or ReplaceTransport (send a transport-replace). reinvite-method = "RestartJingle" - // Whether to enable backward compatibility for clients which do not support receiving multiple video streams. - // - // Newer jitsi-meet clients support sending video and screensharing in two separate streams. We want to support - // older clients with no support for receiving multiple streams in conferences with newer clients (for this mode we - // assume they can have at most 1 camera and one screensharing stream), and specifically we want them to receive - // the screensharing stream when there is a choice. To achieve this jicofo filters the set of sources signaled to - // older clients, excluding the camera source if there is a screenshering source. - // - // Note: this feature is indented to be removed once older clients (mobile) are phased out. - enable-multi-stream-backward-compat = false - // Rate limits for a participant requesting an ICE restart. restart-request-rate-limits { // Never accept a request unless at least `min-interval` has passed since the last request diff --git a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java index 0240b0c7a9..b11c5e6a94 100644 --- a/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java +++ b/jicofo/src/main/java/org/jitsi/jicofo/conference/JitsiMeetConferenceImpl.java @@ -806,14 +806,6 @@ private void inviteChatMember(ChatRoomMember chatRoomMember, boolean justJoined) features); ConferenceMetrics.participants.inc(); - if (!participant.supportsReceivingMultipleVideoStreams() && !participant.getChatMember().isJigasi()) - { - ConferenceMetrics.participantsNoMultiStream.inc(); - } - if (!participant.hasSourceNameSupport() && !participant.getChatMember().isJigasi()) - { - ConferenceMetrics.participantsNoSourceName.inc(); - } boolean added = (participants.put(chatRoomMember.getOccupantJid(), participant) == null); if (added) @@ -2100,22 +2092,6 @@ public JibriSipGateway getJibriSipGateway() return jibriSipGateway; } - /** - * Notifies this conference that one of the participants' screensharing source has changed its "mute" status. - */ - void desktopSourceIsMutedChanged(Participant participant, boolean desktopSourceIsMuted) - { - if (!ConferenceConfig.config.getMultiStreamBackwardCompat()) - { - return; - } - - participants.values().stream() - .filter(p -> p != participant) - .filter(p -> !p.supportsReceivingMultipleVideoStreams()) - .forEach(p -> p.remoteDesktopSourceIsMutedChanged(participant.getEndpointId(), desktopSourceIsMuted)); - } - /** * {@inheritDoc} */ @@ -2358,11 +2334,6 @@ public void localRoleChanged(@NotNull MemberRole newRole) @Override public void memberPresenceChanged(@NotNull ChatRoomMember member) { - Participant participant = getParticipant(member.getOccupantJid()); - if (participant != null) - { - participant.presenceChanged(); - } } @Override diff --git a/jicofo/src/main/java/org/jitsi/jicofo/conference/ParticipantInviteRunnable.java b/jicofo/src/main/java/org/jitsi/jicofo/conference/ParticipantInviteRunnable.java index f19cca556b..acb4cf40e8 100644 --- a/jicofo/src/main/java/org/jitsi/jicofo/conference/ParticipantInviteRunnable.java +++ b/jicofo/src/main/java/org/jitsi/jicofo/conference/ParticipantInviteRunnable.java @@ -204,7 +204,6 @@ private void doRun() participant.getStatId(), participant.getChatMember().getRegion(), participant.getSources(), - participant.hasSourceNameSupport(), participant.useSsrcRewriting(), forceMuteAudio, forceMuteVideo, diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt index b60f11a989..b63afabb8a 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/ConferenceConfig.kt @@ -105,10 +105,6 @@ class ConferenceConfig private constructor() { "jicofo.conference.reinvite-method".from(newConfig) } - val multiStreamBackwardCompat: Boolean by config { - "jicofo.conference.enable-multi-stream-backward-compat".from(newConfig) - } - /** * Whether to strip simulcast streams when signaling receivers. This option requires that jitsi-videobridge * uses the first SSRC in the SIM group as the target SSRC when rewriting streams, as this is the only SSRC diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/FocusManager.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/FocusManager.kt index ed711e8e6f..ca9bcccafd 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/FocusManager.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/FocusManager.kt @@ -263,8 +263,6 @@ class FocusManager( // so we'll merge stats from different "child" objects here. val stats = OrderedJsonObject() stats["total_participants"] = ConferenceMetrics.participants.get() - stats["total_participants_no_multi_stream"] = ConferenceMetrics.participantsNoMultiStream.get() - stats["total_participants_no_source_name"] = ConferenceMetrics.participantsNoSourceName.get() stats["total_conferences_created"] = ConferenceMetrics.conferencesCreated.get() stats["conferences"] = ConferenceMetrics.conferenceCount.get() stats["conferences_with_visitors"] = ConferenceMetrics.conferencesWithVisitors.get() diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/ConferenceMetrics.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/ConferenceMetrics.kt index dfb185813f..abee9e4d82 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/ConferenceMetrics.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/ConferenceMetrics.kt @@ -36,18 +36,6 @@ class ConferenceMetrics { "The total number of participants that have connected to this Jicofo since it was started." ) - @JvmField - val participantsNoMultiStream = metricsContainer.registerCounter( - "participants_no_multi_stream", - "Number of participants with no support for receiving multiple streams." - ) - - @JvmField - val participantsNoSourceName = metricsContainer.registerCounter( - "participants_no_source_name", - "Number of participants with no support for source names." - ) - @JvmField val participantsMoved = metricsContainer.registerCounter( "participants_moved", diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/Participant.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/Participant.kt index 11fccc7d4d..4377c59f86 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/Participant.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/Participant.kt @@ -25,7 +25,6 @@ import org.jitsi.jicofo.conference.source.ConferenceSourceMap import org.jitsi.jicofo.conference.source.EndpointSourceSet import org.jitsi.jicofo.conference.source.EndpointSourceSet.Companion.fromJingle import org.jitsi.jicofo.conference.source.ValidationFailedException -import org.jitsi.jicofo.conference.source.VideoType import org.jitsi.jicofo.util.Cancelable import org.jitsi.jicofo.util.RateLimit import org.jitsi.jicofo.xmpp.Features @@ -34,7 +33,6 @@ import org.jitsi.jicofo.xmpp.jingle.JingleRequestHandler import org.jitsi.jicofo.xmpp.jingle.JingleSession import org.jitsi.jicofo.xmpp.muc.ChatRoomMember import org.jitsi.jicofo.xmpp.muc.MemberRole -import org.jitsi.jicofo.xmpp.muc.SourceInfo import org.jitsi.jicofo.xmpp.muc.hasModeratorRights import org.jitsi.utils.OrderedJsonObject import org.jitsi.utils.logging2.Logger @@ -94,8 +92,7 @@ open class Participant @JvmOverloads constructor( private val sourceSignaling = SourceSignaling( audio = hasAudioSupport(), video = hasVideoSupport(), - ConferenceConfig.config.stripSimulcast(), - supportsReceivingMultipleVideoStreams() || !ConferenceConfig.config.multiStreamBackwardCompat + ConferenceConfig.config.stripSimulcast() ) /** @@ -132,13 +129,6 @@ open class Participant @JvmOverloads constructor( */ private val signalQueuedSourcesTaskSyncRoot = Any() - /** - * Whether the screensharing source of this participant (if it exists) is muted. If a screensharing source doesn't - * exists this stays false (though the source and the mute status are communicated separately so they may not - * always be in sync) - */ - private var desktopSourceIsMuted = false - /** * Whether this participant is a "user participant" for the purposes of * [JitsiMeetConferenceImpl.getUserParticipantCount]. @@ -146,47 +136,6 @@ open class Participant @JvmOverloads constructor( */ val isUserParticipant = !chatMember.isJibri && !chatMember.isTranscriber && chatMember.role != MemberRole.VISITOR - init { - updateDesktopSourceIsMuted(chatMember.sourceInfos) - } - - /** - * Notify this [Participant] that the underlying [ChatRoomMember]'s presence changed. - */ - fun presenceChanged() { - if (updateDesktopSourceIsMuted(chatMember.sourceInfos)) { - conference.desktopSourceIsMutedChanged(this, desktopSourceIsMuted) - } - } - - /** - * Update the value of [.desktopSourceIsMuted] based on the advertised [SourceInfo]s. - * @return true if the value of [.desktopSourceIsMuted] changed as a result of this call. - */ - private fun updateDesktopSourceIsMuted(sourceInfos: Set): Boolean { - val newValue = sourceInfos - .any { (_, muted, videoType) -> videoType === VideoType.Desktop && muted } - if (desktopSourceIsMuted != newValue) { - desktopSourceIsMuted = newValue - return true - } - return false - } - - /** - * Notify this participant that another participant's (identified by `owner`) screensharing source was muted - * or unmuted. - */ - fun remoteDesktopSourceIsMutedChanged(owner: String, muted: Boolean) { - // This is only needed for backwards compatibility with clients that don't support receiving multiple streams. - if (supportsReceivingMultipleVideoStreams()) { - return - } - sourceSignaling.remoteDesktopSourceIsMutedChanged(owner, muted) - // Signal updates, if any, immediately. - synchronized(signalQueuedSourcesTaskSyncRoot) { scheduleSignalingOfQueuedSources() } - } - /** * Replaces the channel allocator thread, which is currently allocating channels for this participant (if any) * with the specified channel allocator (if any). @@ -217,9 +166,6 @@ open class Participant @JvmOverloads constructor( } } - /** Return `true` if this participant supports source name signaling. */ - fun hasSourceNameSupport() = supportedFeatures.contains(Features.SOURCE_NAMES) - /** Return `true` if this participant supports SSRC rewriting functionality. */ fun hasSsrcRewritingSupport() = supportedFeatures.contains(Features.SSRC_REWRITING_V1) @@ -228,7 +174,6 @@ open class Participant @JvmOverloads constructor( /** Return `true` if this participant supports receiving Jingle sources encoded in JSON. */ fun supportsJsonEncodedSources() = supportedFeatures.contains(Features.JSON_SOURCES) - fun supportsReceivingMultipleVideoStreams() = supportedFeatures.contains(Features.RECEIVE_MULTIPLE_STREAMS) /** Returns `true` iff this participant supports REMB. */ fun hasRembSupport() = supportedFeatures.contains(Features.REMB) diff --git a/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/SourceSignaling.kt b/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/SourceSignaling.kt index ab160b3399..46179a6427 100644 --- a/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/SourceSignaling.kt +++ b/jicofo/src/main/kotlin/org/jitsi/jicofo/conference/SourceSignaling.kt @@ -20,9 +20,6 @@ package org.jitsi.jicofo.conference import org.jitsi.jicofo.conference.AddOrRemove.Add import org.jitsi.jicofo.conference.AddOrRemove.Remove import org.jitsi.jicofo.conference.source.ConferenceSourceMap -import org.jitsi.jicofo.conference.source.EndpointSourceSet -import org.jitsi.jicofo.conference.source.Source -import org.jitsi.jicofo.conference.source.VideoType import org.jitsi.utils.MediaType import org.json.simple.JSONArray import org.json.simple.JSONObject @@ -30,14 +27,7 @@ import org.json.simple.JSONObject class SourceSignaling( audio: Boolean = true, video: Boolean = true, - private val stripSimulcast: Boolean = true, - /** - * Whether the endpoint supports receiving multiple video streams. If it doesn't, we make sure to only signal the - * screensharing (desktop) source when another endpoint has both camera and screensharing. - * - * We assume at most one desktop source and at most one camera source. - */ - private val supportsReceivingMultipleStreams: Boolean = true + private val stripSimulcast: Boolean = true ) { /** The set of media types supported by the endpoint. */ private val supportedMediaTypes: Set = buildSet { @@ -57,31 +47,12 @@ class SourceSignaling( */ private var updatedSources = ConferenceSourceMap() - /** - * In the case when [supportsReceivingMultipleStreams] is false, stores any screensharing sources which are - * signaled to be muted, so that they can be restored once unmuted. - */ - private val mutedDesktopSources = ConferenceSourceMap() - fun addSources(sourcesToAdd: ConferenceSourceMap) { - sourcesToAdd.copy().entries.forEach { (owner, ess) -> - if (mutedDesktopSources[owner] == NO_SOURCES) { - // owner's desktop source was muted before the source details were signaled. Suppress and save the - // desktop sources. - val desktopSources = ess.getDesktopSources() - if (!desktopSources.isEmpty()) { - mutedDesktopSources.remove(owner) - mutedDesktopSources.add(owner, desktopSources) - sourcesToAdd.remove(ConferenceSourceMap(owner, desktopSources)) - } - } - } updatedSources.add(sourcesToAdd) } fun removeSources(sourcesToRemove: ConferenceSourceMap) { updatedSources.remove(sourcesToRemove) - mutedDesktopSources.remove(sourcesToRemove) } /** @@ -124,68 +95,5 @@ class SourceSignaling( private fun ConferenceSourceMap.filter(): ConferenceSourceMap = copy().apply { stripByMediaType(supportedMediaTypes) if (stripSimulcast) stripSimulcast() - if (!supportsReceivingMultipleStreams) { - filterMultiStream() - } - } - - /** - * Notifies this instance that a remote participant (identified by [owner]) has muted or unmuted their screensharing - * source. - */ - fun remoteDesktopSourceIsMutedChanged(owner: String, muted: Boolean) { - if (muted) { - // so that we can fall back to the video source - val allParticipantSources = updatedSources[owner] ?: EndpointSourceSet() - val desktopSources = allParticipantSources.getDesktopSources() - - // The source was muted. If there was a screensharing source signaled (desktopSources is not empty) - // we remove it from [updatedSources], so that we can signal a source-remove with the next update. - updatedSources.remove(ConferenceSourceMap(owner, desktopSources)) - // If the source was not signaled yet, save NO_SOURCES in the map to remember that it is muted once it - // is signaled. - mutedDesktopSources.add(owner, if (desktopSources.isEmpty()) NO_SOURCES else desktopSources) - } else { - val unmutedDesktopSources = mutedDesktopSources[owner] - - // Remove it from the muted map so future calls to [addSources] are allowed to add it. - mutedDesktopSources.remove(owner) - // If there was a screensharing source previously signaled, and it is not the NO_SOURCES placeholder, add - // it to [updatedSources] so that is signaled with the next update. - if (unmutedDesktopSources != null && unmutedDesktopSources != NO_SOURCES) { - updatedSources.add(owner, unmutedDesktopSources) - } - } - } -} - -/** - * If an endpoint has a screensharing (desktop) source, filter out all other video sources. - */ -private fun ConferenceSourceMap.filterMultiStream() = map { ess -> - val desktopSourceName = ess.sources.find { it.videoType == VideoType.Desktop }?.name - if (desktopSourceName != null) { - val remainingSources = ess.sources.filter { - it.mediaType != MediaType.VIDEO || it.name == desktopSourceName - }.toSet() - val remainingSsrcs = remainingSources.map { it.ssrc }.toSet() - val remainingGroups = ess.ssrcGroups.filter { it.ssrcs.any { it in remainingSsrcs } }.toSet() - EndpointSourceSet(remainingSources, remainingGroups) - } else { - ess - } -} - -private fun EndpointSourceSet.getDesktopSources(): EndpointSourceSet { - val desktopSourceName = sources.find { it.videoType == VideoType.Desktop }?.name - return if (desktopSourceName != null) { - val desktopSources = sources.filter { it.name == desktopSourceName }.toSet() - val desktopSsrcs = desktopSources.map { it.ssrc }.toSet() - val desktopGroups = ssrcGroups.filter { it.ssrcs.any { it in desktopSsrcs } }.toSet() - EndpointSourceSet(desktopSources, desktopGroups) - } else { - EndpointSourceSet() } } - -private val NO_SOURCES = EndpointSourceSet(Source(987654321, MediaType.VIDEO)) diff --git a/jicofo/src/test/kotlin/org/jitsi/jicofo/conference/source/SourceSignalingTest.kt b/jicofo/src/test/kotlin/org/jitsi/jicofo/conference/source/SourceSignalingTest.kt index d71c57071b..54b547e9de 100644 --- a/jicofo/src/test/kotlin/org/jitsi/jicofo/conference/source/SourceSignalingTest.kt +++ b/jicofo/src/test/kotlin/org/jitsi/jicofo/conference/source/SourceSignalingTest.kt @@ -19,7 +19,6 @@ import io.kotest.core.spec.IsolationMode import io.kotest.core.spec.style.ShouldSpec import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.shouldBe -import io.kotest.matchers.shouldNotBe import org.jitsi.jicofo.conference.AddOrRemove.Add import org.jitsi.jicofo.conference.AddOrRemove.Remove import org.jitsi.jicofo.conference.SourceSignaling @@ -49,43 +48,6 @@ class SourceSignalingTest : ShouldSpec() { val e3a = Source(3, MediaType.AUDIO) val s3 = ConferenceSourceMap(e3 to EndpointSourceSet(e3a)).unmodifiable - val e4 = "endpoint4" - val e4a1 = Source(4, MediaType.AUDIO) - val e4v1a = Source(43, MediaType.VIDEO, name = "e4-v1") - val e4v1b = Source(44, MediaType.VIDEO, name = "e4-v1") - val e4v1c = Source(45, MediaType.VIDEO, name = "e4-v1") - val e4v1aR = Source(53, MediaType.VIDEO, name = "e4-v1") - val e4v1bR = Source(54, MediaType.VIDEO, name = "e4-v1") - val e4v1cR = Source(55, MediaType.VIDEO, name = "e4-v1") - val e4vgroups = setOf( - SsrcGroup(SsrcGroupSemantics.Sim, listOf(43, 44, 45)), - SsrcGroup(SsrcGroupSemantics.Fid, listOf(43, 53)), - SsrcGroup(SsrcGroupSemantics.Fid, listOf(44, 54)), - SsrcGroup(SsrcGroupSemantics.Fid, listOf(45, 55)) - ) - val e4ss1a = Source(46, MediaType.VIDEO, name = "e4-ss1", videoType = VideoType.Desktop) - val e4ss1b = Source(47, MediaType.VIDEO, name = "e4-ss1", videoType = VideoType.Desktop) - val e4ss1c = Source(48, MediaType.VIDEO, name = "e4-ss1", videoType = VideoType.Desktop) - val s4audio = ConferenceSourceMap(e4 to EndpointSourceSet(e4a1)) - val s4video = ConferenceSourceMap( - e4 to EndpointSourceSet( - setOf(e4v1a, e4v1b, e4v1c, e4v1aR, e4v1bR, e4v1cR), - e4vgroups - ) - ) - val s4ss = ConferenceSourceMap( - e4 to EndpointSourceSet( - setOf(e4ss1a, e4ss1b, e4ss1c), - setOf() - ) - ) - val e4sources = setOf(e4a1, e4v1a, e4v1b, e4v1c, e4ss1a, e4ss1b, e4ss1c) - val e4groups = setOf( - SsrcGroup(SsrcGroupSemantics.Sim, listOf(43, 44, 45), MediaType.VIDEO), - SsrcGroup(SsrcGroupSemantics.Sim, listOf(46, 47, 48), MediaType.VIDEO) - ) - val s4 = ConferenceSourceMap(e4 to EndpointSourceSet(e4sources, e4groups)) - context("Queueing remote sources") { val sourceSignaling = SourceSignaling() sourceSignaling.update().shouldBeEmpty() @@ -167,109 +129,37 @@ class SourceSignalingTest : ShouldSpec() { sourceSignaling.debugState.shouldBeValidJson() } - listOf(true, false).forEach { supportsReceivingMultipleStreams -> - context("Filtering (supportsReceivingMultipleStreams=$supportsReceivingMultipleStreams)") { - val sourceSignaling = SourceSignaling(audio = true, video = false, stripSimulcast = true) + context("Filtering") { + val sourceSignaling = SourceSignaling(audio = true, video = false, stripSimulcast = true) - sourceSignaling.reset(s1 + s2).shouldBe( - ConferenceSourceMap( - e1 to EndpointSourceSet(e1a), - e2 to EndpointSourceSet(e2a) - ) + sourceSignaling.reset(s1 + s2).shouldBe( + ConferenceSourceMap( + e1 to EndpointSourceSet(e1a), + e2 to EndpointSourceSet(e2a) ) - - sourceSignaling.addSources(s2new) - sourceSignaling.update().let { - it.size shouldBe 1 - it[0].action shouldBe Add - it[0].sources shouldBe ConferenceSourceMap(e2 to EndpointSourceSet(e2a2)) - } - - sourceSignaling.removeSources(s1) - sourceSignaling.update().let { - it.size shouldBe 1 - it[0].action shouldBe Remove - it[0].sources shouldBe ConferenceSourceMap(e1 to EndpointSourceSet(e1a)) - } - - sourceSignaling.addSources(s1) - sourceSignaling.removeSources(s1) - sourceSignaling.update().shouldBeEmpty() - - sourceSignaling.removeSources(s2) - sourceSignaling.addSources(s2) - sourceSignaling.update().shouldBeEmpty() - } - } - context("Filtering with no support for multiple streams") { - val sourceSignaling = SourceSignaling( - audio = true, - video = true, - stripSimulcast = true, - supportsReceivingMultipleStreams = false ) - sourceSignaling.addSources(s1) + sourceSignaling.addSources(s2new) sourceSignaling.update().let { it.size shouldBe 1 it[0].action shouldBe Add - it[0].sources shouldBe s1 + it[0].sources shouldBe ConferenceSourceMap(e2 to EndpointSourceSet(e2a2)) } - // When camera and SS are added together, it should only add SS - sourceSignaling.addSources(s4audio + s4video + s4ss) - sourceSignaling.update().let { - it.size shouldBe 1 - it[0].action shouldBe Add - it[0].sources shouldBe (s4audio + s4ss).stripSimulcast() - } - - // It should only remove the sources that were added (SS) - sourceSignaling.removeSources(s4audio + s4video + s4ss) + sourceSignaling.removeSources(s1) sourceSignaling.update().let { it.size shouldBe 1 it[0].action shouldBe Remove - it[0].sources shouldBe (s4audio + s4ss).stripSimulcast() + it[0].sources shouldBe ConferenceSourceMap(e1 to EndpointSourceSet(e1a)) } - sourceSignaling.addSources(s4audio + s4ss) - sourceSignaling.update().let { - it.size shouldBe 1 - it[0].action shouldBe Add - it[0].sources shouldBe (s4audio + s4ss).stripSimulcast() - } - - // SS exists, camera should not be added. - sourceSignaling.addSources(s4video) + sourceSignaling.addSources(s1) + sourceSignaling.removeSources(s1) sourceSignaling.update().shouldBeEmpty() - // When SS is removed and only camera is left, camera should be added - sourceSignaling.removeSources(s4ss) - sourceSignaling.update().let { sourceUpdates -> - sourceUpdates.size shouldBe 2 - - val remove = sourceUpdates.find { it.action == Remove } - remove shouldNotBe null - remove!!.sources shouldBe s4ss.stripSimulcast() - - val add = sourceUpdates.find { it.action == Add } - add shouldNotBe null - add!!.sources shouldBe s4video.stripSimulcast() - } - - // When SS is added and camera exists, it should be replaced. - sourceSignaling.addSources(s4ss) - sourceSignaling.update().let { sourceUpdates -> - sourceUpdates.size shouldBe 2 - - val remove = sourceUpdates.find { it.action == Remove } - remove shouldNotBe null - remove!!.sources shouldBe s4video.stripSimulcast() - - val add = sourceUpdates.find { it.action == Add } - add shouldNotBe null - add!!.sources shouldBe s4ss.stripSimulcast() - } + sourceSignaling.removeSources(s2) + sourceSignaling.addSources(s2) + sourceSignaling.update().shouldBeEmpty() } } }