Send state also through signaling messages

The speaking state is still sent only through data channels, as it is
not currently handled by other clients when sent through signaling
messages.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
Daniel Calviño Sánchez 2024-12-19 12:41:07 +01:00 committed by Marcel Hibbe
parent 73105515bd
commit 512b320015
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
6 changed files with 426 additions and 5 deletions

View File

@ -7,6 +7,8 @@
package com.nextcloud.talk.call;
import com.nextcloud.talk.models.json.signaling.DataChannelMessage;
import com.nextcloud.talk.models.json.signaling.NCMessagePayload;
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage;
import java.util.Objects;
@ -48,6 +50,7 @@ public abstract class LocalStateBroadcaster {
audioEnabled = localCallParticipantModel.isAudioEnabled();
messageSender.sendToAll(getDataChannelMessageForAudioState());
messageSender.sendToAll(getSignalingMessageForAudioState());
}
if (!Objects.equals(speaking, localCallParticipantModel.isSpeaking())) {
@ -60,6 +63,7 @@ public abstract class LocalStateBroadcaster {
videoEnabled = localCallParticipantModel.isVideoEnabled();
messageSender.sendToAll(getDataChannelMessageForVideoState());
messageSender.sendToAll(getSignalingMessageForVideoState());
}
}
}
@ -106,4 +110,61 @@ public abstract class LocalStateBroadcaster {
return new DataChannelMessage(type);
}
/**
* Returns a signaling message with the common fields set (type and room type).
*
* @param type the type of the signaling message
* @return the signaling message
*/
private NCSignalingMessage createBaseSignalingMessage(String type) {
NCSignalingMessage ncSignalingMessage = new NCSignalingMessage();
// "roomType" is not really relevant without a peer or when referring to the whole participant, but it is
// nevertheless expected in the message. As most of the signaling messages currently sent to all participants
// are related to audio/video state "video" is used as the room type.
ncSignalingMessage.setRoomType("video");
ncSignalingMessage.setType(type);
return ncSignalingMessage;
}
/**
* Returns a signaling message to notify current audio state.
*
* @return the signaling message
*/
protected NCSignalingMessage getSignalingMessageForAudioState() {
String type = "mute";
if (localCallParticipantModel.isAudioEnabled() != null && localCallParticipantModel.isAudioEnabled()) {
type = "unmute";
}
NCSignalingMessage ncSignalingMessage = createBaseSignalingMessage(type);
NCMessagePayload ncMessagePayload = new NCMessagePayload();
ncMessagePayload.setName("audio");
ncSignalingMessage.setPayload(ncMessagePayload);
return ncSignalingMessage;
}
/**
* Returns a signaling message to notify current video state.
*
* @return the signaling message
*/
protected NCSignalingMessage getSignalingMessageForVideoState() {
String type = "mute";
if (localCallParticipantModel.isVideoEnabled() != null && localCallParticipantModel.isVideoEnabled()) {
type = "unmute";
}
NCSignalingMessage ncSignalingMessage = createBaseSignalingMessage(type);
NCMessagePayload ncMessagePayload = new NCMessagePayload();
ncMessagePayload.setName("video");
ncSignalingMessage.setPayload(ncMessagePayload);
return ncSignalingMessage;
}
}

View File

@ -6,6 +6,8 @@
*/
package com.nextcloud.talk.call;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
@ -26,11 +28,30 @@ import io.reactivex.schedulers.Schedulers;
* initial state when the local participant joins the call, as all the remote participants joined from the point of
* view of the local participant). If the state was already being sent the sending is restarted with each new
* participant that joins.
* <p>
* Similarly, in the case of signaling messages it is not possible either to know when the remote participants have
* "seen" the local participant and thus are ready to handle signaling messages about the state. However, in the case
* of signaling messages it is possible to send them to a specific participant, so the initial state is sent several
* times with an increasing delay directly to the participant that was added. Moreover, if the participant is removed
* the state is no longer directly sent.
* <p>
* In any case, note that the state is sent only when the remote participant joins the call. Even in case of
* temporary disconnections the normal state updates sent when the state changes are expected to be received by the
* other participant, as signaling messages are sent through a WebSocket and are therefore reliable. Moreover, even
* if the WebSocket is restarted and the connection resumed (rather than joining with a new session ID) the messages
* would be also received, as in that case they would be queued until the WebSocket is connected again.
* <p>
* Data channel messages, on the other hand, could be lost if the remote participant restarts the peer receiver
* connection (although they would be received in case of temporary disconnections, as data channels use a reliable
* transport by default). Therefore, as the speaking state is sent only through data channels, updates of the speaking
* state could be not received by remote participants.
*/
public class LocalStateBroadcasterMcu extends LocalStateBroadcaster {
private final MessageSender messageSender;
private final Map<String, Disposable> sendStateWithRepetitionByParticipant = new HashMap<>();
private Disposable sendStateWithRepetition;
public LocalStateBroadcasterMcu(LocalCallParticipantModel localCallParticipantModel,
@ -46,6 +67,10 @@ public class LocalStateBroadcasterMcu extends LocalStateBroadcaster {
if (sendStateWithRepetition != null) {
sendStateWithRepetition.dispose();
}
for (Disposable sendStateWithRepetitionForParticipant: sendStateWithRepetitionByParticipant.values()) {
sendStateWithRepetitionForParticipant.dispose();
}
}
@Override
@ -58,10 +83,26 @@ public class LocalStateBroadcasterMcu extends LocalStateBroadcaster {
.fromArray(new Integer[]{0, 1, 2, 4, 8, 16})
.concatMap(i -> Observable.just(i).delay(i, TimeUnit.SECONDS, Schedulers.io()))
.subscribe(value -> sendState());
String sessionId = callParticipantModel.getSessionId();
Disposable sendStateWithRepetitionForParticipant = sendStateWithRepetitionByParticipant.get(sessionId);
if (sendStateWithRepetitionForParticipant != null) {
sendStateWithRepetitionForParticipant.dispose();
}
sendStateWithRepetitionByParticipant.put(sessionId, Observable
.fromArray(new Integer[]{0, 1, 2, 4, 8, 16})
.concatMap(i -> Observable.just(i).delay(i, TimeUnit.SECONDS, Schedulers.io()))
.subscribe(value -> sendState(sessionId)));
}
@Override
public void handleCallParticipantRemoved(CallParticipantModel callParticipantModel) {
String sessionId = callParticipantModel.getSessionId();
Disposable sendStateWithRepetitionForParticipant = sendStateWithRepetitionByParticipant.get(sessionId);
if (sendStateWithRepetitionForParticipant != null) {
sendStateWithRepetitionForParticipant.dispose();
}
}
private void sendState() {
@ -69,4 +110,9 @@ public class LocalStateBroadcasterMcu extends LocalStateBroadcaster {
messageSender.sendToAll(getDataChannelMessageForSpeakingState());
messageSender.sendToAll(getDataChannelMessageForVideoState());
}
private void sendState(String sessionId) {
messageSender.send(getSignalingMessageForAudioState(), sessionId);
messageSender.send(getSignalingMessageForVideoState(), sessionId);
}
}

View File

@ -26,6 +26,12 @@ import java.util.Objects;
* after a temporary disconnection; data channels use a reliable transport by default, so even if the state changes
* while the connection is temporarily interrupted the normal state update messages should be received by the other
* participant once the connection is restored.
* <p>
* Nevertheless, in case of a failed connection and an ICE restart it is unclear whether the data channel messages
* would be received or not (as the data channel transport may be the one that failed and needs to be restarted).
* However, the state (except the speaking state) is also sent through signaling messages, which need to be
* explicitly fetched from the internal signaling server, so even in case of a failed connection they will be
* eventually received once the remote participant connects again.
*/
public class LocalStateBroadcasterNoMcu extends LocalStateBroadcaster {
@ -115,5 +121,8 @@ public class LocalStateBroadcasterNoMcu extends LocalStateBroadcaster {
messageSender.send(getDataChannelMessageForAudioState(), sessionId);
messageSender.send(getDataChannelMessageForSpeakingState(), sessionId);
messageSender.send(getDataChannelMessageForVideoState(), sessionId);
messageSender.send(getSignalingMessageForAudioState(), sessionId);
messageSender.send(getSignalingMessageForVideoState(), sessionId);
}
}

View File

@ -7,6 +7,8 @@
package com.nextcloud.talk.call
import com.nextcloud.talk.models.json.signaling.DataChannelMessage
import com.nextcloud.talk.models.json.signaling.NCMessagePayload
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage
import io.reactivex.plugins.RxJavaPlugins
import io.reactivex.schedulers.TestScheduler
import org.junit.Before
@ -32,6 +34,54 @@ class LocalStateBroadcasterMcuTest {
mockedMessageSender = Mockito.mock(MessageSender::class.java)
}
private fun getExpectedUnmuteAudio(): NCSignalingMessage {
val expectedUnmuteAudio = NCSignalingMessage()
expectedUnmuteAudio.roomType = "video"
expectedUnmuteAudio.type = "unmute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedUnmuteAudio.payload = payload
return expectedUnmuteAudio
}
private fun getExpectedMuteAudio(): NCSignalingMessage {
val expectedMuteAudio = NCSignalingMessage()
expectedMuteAudio.roomType = "video"
expectedMuteAudio.type = "mute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedMuteAudio.payload = payload
return expectedMuteAudio
}
private fun getExpectedUnmuteVideo(): NCSignalingMessage {
val expectedUnmuteVideo = NCSignalingMessage()
expectedUnmuteVideo.roomType = "video"
expectedUnmuteVideo.type = "unmute"
val payload = NCMessagePayload()
payload.name = "video"
expectedUnmuteVideo.payload = payload
return expectedUnmuteVideo
}
private fun getExpectedMuteVideo(): NCSignalingMessage {
val expectedMuteVideo = NCSignalingMessage()
expectedMuteVideo.roomType = "video"
expectedMuteVideo.type = "mute"
val payload = NCMessagePayload()
payload.name = "video"
expectedMuteVideo.payload = payload
return expectedMuteVideo
}
@Test
fun testStateSentWithExponentialBackoffWhenParticipantAdded() {
val testScheduler = TestScheduler()
@ -54,12 +104,17 @@ class LocalStateBroadcasterMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
testScheduler.advanceTimeBy(0, TimeUnit.SECONDS)
var messageCount = 1
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
@ -68,6 +123,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
@ -76,6 +133,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(4, TimeUnit.SECONDS)
@ -84,6 +143,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(8, TimeUnit.SECONDS)
@ -92,6 +153,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(16, TimeUnit.SECONDS)
@ -100,6 +163,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(100, TimeUnit.SECONDS)
@ -132,11 +197,16 @@ class LocalStateBroadcasterMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
testScheduler.advanceTimeBy(0, TimeUnit.SECONDS)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
localCallParticipantModel!!.isSpeaking = false
@ -151,51 +221,73 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(2)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(2)).sendToAll(expectedStoppedSpeaking)
Mockito.verify(mockedMessageSender!!, times(2)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(2)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(2)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
localCallParticipantModel!!.isAudioEnabled = false
val expectedAudioOff = DataChannelMessage("audioOff")
val expectedMuteAudio = getExpectedMuteAudio()
// Changing the state causes the normal state update to be sent, independently of the initial state
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedAudioOff)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteAudio)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
Mockito.verify(mockedMessageSender!!, times(2)).sendToAll(expectedAudioOff)
Mockito.verify(mockedMessageSender!!, times(3)).sendToAll(expectedStoppedSpeaking)
Mockito.verify(mockedMessageSender!!, times(3)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteAudio)
Mockito.verify(mockedMessageSender!!, times(1)).send(expectedMuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(3)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
localCallParticipantModel!!.isVideoEnabled = false
val expectedVideoOff = DataChannelMessage("videoOff")
val expectedMuteVideo = getExpectedMuteVideo()
// Changing the state causes the normal state update to be sent, independently of the initial state
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedVideoOff)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteVideo)
testScheduler.advanceTimeBy(4, TimeUnit.SECONDS)
Mockito.verify(mockedMessageSender!!, times(3)).sendToAll(expectedAudioOff)
Mockito.verify(mockedMessageSender!!, times(4)).sendToAll(expectedStoppedSpeaking)
Mockito.verify(mockedMessageSender!!, times(2)).sendToAll(expectedVideoOff)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteAudio)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteVideo)
Mockito.verify(mockedMessageSender!!, times(2)).send(expectedMuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(1)).send(expectedMuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
localCallParticipantModel!!.isVideoEnabled = true
// Changing the state causes the normal state update to be sent, independently of the initial state
Mockito.verify(mockedMessageSender!!, times(4)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedUnmuteVideo)
testScheduler.advanceTimeBy(8, TimeUnit.SECONDS)
Mockito.verify(mockedMessageSender!!, times(4)).sendToAll(expectedAudioOff)
Mockito.verify(mockedMessageSender!!, times(5)).sendToAll(expectedStoppedSpeaking)
Mockito.verify(mockedMessageSender!!, times(5)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteAudio)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedMuteVideo)
Mockito.verify(mockedMessageSender!!, times(1)).sendToAll(expectedUnmuteVideo)
Mockito.verify(mockedMessageSender!!, times(3)).send(expectedMuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(4)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}
@Test
fun testStateSentWithExponentialBackoffRestartedWhenAnotherParticipantAdded() {
fun testStateSentWithExponentialBackoffWhenAnotherParticipantAdded() {
// The state sent through data channels should be restarted, although the state sent through signaling
// messages should be independent for each participant.
val testScheduler = TestScheduler()
RxJavaPlugins.setIoSchedulerHandler { testScheduler }
@ -216,36 +308,51 @@ class LocalStateBroadcasterMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
testScheduler.advanceTimeBy(0, TimeUnit.SECONDS)
var dataChannelMessageCount = 1
var signalingMessageCount1 = 1
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
dataChannelMessageCount = 2
signalingMessageCount1 = 2
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
dataChannelMessageCount = 3
signalingMessageCount1 = 3
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(4, TimeUnit.SECONDS)
dataChannelMessageCount = 4
signalingMessageCount1 = 4
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
val callParticipantModel2 = MutableCallParticipantModel("theSessionId2")
@ -255,49 +362,107 @@ class LocalStateBroadcasterMcuTest {
testScheduler.advanceTimeBy(0, TimeUnit.SECONDS)
dataChannelMessageCount = 5
var signalingMessageCount2 = 1
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
dataChannelMessageCount = 6
signalingMessageCount2 = 2
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
dataChannelMessageCount = 7
signalingMessageCount2 = 3
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(4, TimeUnit.SECONDS)
dataChannelMessageCount = 8
signalingMessageCount2 = 4
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(8, TimeUnit.SECONDS)
// 0+1+2+4+1=8 seconds since last signaling messages for participant 1
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
signalingMessageCount1 = 5
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
// 1+7=8 seconds since last data channel messages and signaling messages for participant 2
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS)
dataChannelMessageCount = 9
signalingMessageCount2 = 5
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(16, TimeUnit.SECONDS)
// 7+9=16 seconds since last signaling messages for participant 1
testScheduler.advanceTimeBy(9, TimeUnit.SECONDS)
dataChannelMessageCount = 10
signalingMessageCount1 = 6
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
// 9+7=16 seconds since last data channel messages and signaling messages for participant 2
testScheduler.advanceTimeBy(7, TimeUnit.SECONDS)
dataChannelMessageCount = 10
signalingMessageCount2 = 6
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount1)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount2)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(100, TimeUnit.SECONDS)
@ -306,8 +471,9 @@ class LocalStateBroadcasterMcuTest {
}
@Test
fun testStateStillSentWithExponentialBackoffWhenParticipantRemoved() {
fun testStateSentWithExponentialBackoffWhenParticipantRemoved() {
// For simplicity the exponential backoff is not aborted when the participant that triggered it is removed.
// However, the signaling messages are stopped when the participant is removed.
val testScheduler = TestScheduler()
RxJavaPlugins.setIoSchedulerHandler { testScheduler }
@ -329,36 +495,51 @@ class LocalStateBroadcasterMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
testScheduler.advanceTimeBy(0, TimeUnit.SECONDS)
var dataChannelMessageCount = 1
var signalingMessageCount = 1
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
dataChannelMessageCount = 2
signalingMessageCount = 2
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
dataChannelMessageCount = 3
signalingMessageCount = 3
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(4, TimeUnit.SECONDS)
dataChannelMessageCount = 4
signalingMessageCount = 4
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
localStateBroadcasterMcu!!.handleCallParticipantRemoved(callParticipantModel)
@ -369,6 +550,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(16, TimeUnit.SECONDS)
@ -377,6 +560,8 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(dataChannelMessageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(signalingMessageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(100, TimeUnit.SECONDS)
@ -395,8 +580,10 @@ class LocalStateBroadcasterMcuTest {
)
val callParticipantModel = MutableCallParticipantModel("theSessionId")
val callParticipantModel2 = MutableCallParticipantModel("theSessionId2")
localStateBroadcasterMcu!!.handleCallParticipantAdded(callParticipantModel)
localStateBroadcasterMcu!!.handleCallParticipantAdded(callParticipantModel2)
// Sending will be done in another thread, so just adding the participant does not send anything until that
// other thread could run.
@ -406,12 +593,19 @@ class LocalStateBroadcasterMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
testScheduler.advanceTimeBy(0, TimeUnit.SECONDS)
var messageCount = 1
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
@ -420,6 +614,10 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
@ -428,6 +626,10 @@ class LocalStateBroadcasterMcuTest {
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!, times(messageCount)).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSender!!, times(messageCount)).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSender)
localStateBroadcasterMcu!!.destroy()

View File

@ -7,6 +7,8 @@
package com.nextcloud.talk.call
import com.nextcloud.talk.models.json.signaling.DataChannelMessage
import com.nextcloud.talk.models.json.signaling.NCMessagePayload
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
@ -28,6 +30,30 @@ class LocalStateBroadcasterNoMcuTest {
mockedMessageSenderNoMcu = Mockito.mock(MessageSenderNoMcu::class.java)
}
private fun getExpectedUnmuteAudio(): NCSignalingMessage {
val expectedUnmuteAudio = NCSignalingMessage()
expectedUnmuteAudio.roomType = "video"
expectedUnmuteAudio.type = "unmute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedUnmuteAudio.payload = payload
return expectedUnmuteAudio
}
private fun getExpectedUnmuteVideo(): NCSignalingMessage {
val expectedUnmuteVideo = NCSignalingMessage()
expectedUnmuteVideo.roomType = "video"
expectedUnmuteVideo.type = "unmute"
val payload = NCMessagePayload()
payload.name = "video"
expectedUnmuteVideo.payload = payload
return expectedUnmuteVideo
}
@Test
fun testStateSentWhenIceConnected() {
localStateBroadcasterNoMcu = LocalStateBroadcasterNoMcu(
@ -49,9 +75,14 @@ class LocalStateBroadcasterNoMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedAudioOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedSpeaking, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedVideoOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSenderNoMcu)
}
@ -76,9 +107,14 @@ class LocalStateBroadcasterNoMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedAudioOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedSpeaking, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedVideoOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSenderNoMcu)
}
@ -103,9 +139,14 @@ class LocalStateBroadcasterNoMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedAudioOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedSpeaking, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedVideoOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSenderNoMcu)
callParticipantModel.setIceConnectionState(PeerConnection.IceConnectionState.COMPLETED)
@ -134,9 +175,14 @@ class LocalStateBroadcasterNoMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedAudioOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedSpeaking, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedVideoOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSenderNoMcu)
callParticipantModel.setIceConnectionState(PeerConnection.IceConnectionState.COMPLETED)
@ -191,9 +237,14 @@ class LocalStateBroadcasterNoMcuTest {
val expectedSpeaking = DataChannelMessage("speaking")
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteAudio = getExpectedUnmuteAudio()
val expectedUnmuteVideo = getExpectedUnmuteVideo()
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedAudioOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedSpeaking, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedVideoOn, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteAudio, "theSessionId")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteVideo, "theSessionId")
Mockito.verifyNoMoreInteractions(mockedMessageSenderNoMcu)
callParticipantModel2.setIceConnectionState(PeerConnection.IceConnectionState.CONNECTED)
@ -201,6 +252,8 @@ class LocalStateBroadcasterNoMcuTest {
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedAudioOn, "theSessionId2")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedSpeaking, "theSessionId2")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedVideoOn, "theSessionId2")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteAudio, "theSessionId2")
Mockito.verify(mockedMessageSenderNoMcu!!).send(expectedUnmuteVideo, "theSessionId2")
Mockito.verifyNoMoreInteractions(mockedMessageSenderNoMcu)
}

View File

@ -7,6 +7,8 @@
package com.nextcloud.talk.call
import com.nextcloud.talk.models.json.signaling.DataChannelMessage
import com.nextcloud.talk.models.json.signaling.NCMessagePayload
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
@ -49,7 +51,15 @@ class LocalStateBroadcasterTest {
val expectedAudioOn = DataChannelMessage("audioOn")
val expectedUnmuteAudio = NCSignalingMessage()
expectedUnmuteAudio.roomType = "video"
expectedUnmuteAudio.type = "unmute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedUnmuteAudio.payload = payload
Mockito.verify(mockedMessageSender!!).sendToAll(expectedAudioOn)
Mockito.verify(mockedMessageSender!!).sendToAll(expectedUnmuteAudio)
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}
@ -74,7 +84,15 @@ class LocalStateBroadcasterTest {
val expectedAudioOff = DataChannelMessage("audioOff")
val expectedMuteAudio = NCSignalingMessage()
expectedMuteAudio.roomType = "video"
expectedMuteAudio.type = "mute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedMuteAudio.payload = payload
Mockito.verify(mockedMessageSender!!).sendToAll(expectedAudioOff)
Mockito.verify(mockedMessageSender!!).sendToAll(expectedMuteAudio)
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}
@ -141,10 +159,18 @@ class LocalStateBroadcasterTest {
val expectedAudioOn = DataChannelMessage("audioOn")
val expectedSpeaking = DataChannelMessage("speaking")
val expectedUnmuteAudio = NCSignalingMessage()
expectedUnmuteAudio.roomType = "video"
expectedUnmuteAudio.type = "unmute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedUnmuteAudio.payload = payload
val inOrder = Mockito.inOrder(mockedMessageSender)
inOrder.verify(mockedMessageSender!!).sendToAll(expectedAudioOn)
inOrder.verify(mockedMessageSender!!).sendToAll(expectedSpeaking)
Mockito.verify(mockedMessageSender!!).sendToAll(expectedUnmuteAudio)
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}
@ -187,10 +213,18 @@ class LocalStateBroadcasterTest {
val expectedStoppedSpeaking = DataChannelMessage("stoppedSpeaking")
val expectedAudioOff = DataChannelMessage("audioOff")
val expectedMuteAudio = NCSignalingMessage()
expectedMuteAudio.roomType = "video"
expectedMuteAudio.type = "mute"
val payload = NCMessagePayload()
payload.name = "audio"
expectedMuteAudio.payload = payload
val inOrder = Mockito.inOrder(mockedMessageSender)
inOrder.verify(mockedMessageSender!!).sendToAll(expectedStoppedSpeaking)
inOrder.verify(mockedMessageSender!!).sendToAll(expectedAudioOff)
Mockito.verify(mockedMessageSender!!).sendToAll(expectedMuteAudio)
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}
@ -216,7 +250,15 @@ class LocalStateBroadcasterTest {
val expectedVideoOn = DataChannelMessage("videoOn")
val expectedUnmuteVideo = NCSignalingMessage()
expectedUnmuteVideo.roomType = "video"
expectedUnmuteVideo.type = "unmute"
val payload = NCMessagePayload()
payload.name = "video"
expectedUnmuteVideo.payload = payload
Mockito.verify(mockedMessageSender!!).sendToAll(expectedVideoOn)
Mockito.verify(mockedMessageSender!!).sendToAll(expectedUnmuteVideo)
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}
@ -241,7 +283,15 @@ class LocalStateBroadcasterTest {
val expectedVideoOff = DataChannelMessage("videoOff")
val expectedMuteVideo = NCSignalingMessage()
expectedMuteVideo.roomType = "video"
expectedMuteVideo.type = "mute"
val payload = NCMessagePayload()
payload.name = "video"
expectedMuteVideo.payload = payload
Mockito.verify(mockedMessageSender!!).sendToAll(expectedVideoOff)
Mockito.verify(mockedMessageSender!!).sendToAll(expectedMuteVideo)
Mockito.verifyNoMoreInteractions(mockedMessageSender)
}