mirror of
https://github.com/nextcloud/talk-android
synced 2025-01-18 21:18:15 +00:00
Add support for sending signaling messages in the MessageSender
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
parent
8644d05636
commit
ea2bebe3b0
@ -1590,6 +1590,8 @@ class CallActivity : CallBaseActivity() {
|
||||
hasMCU = false
|
||||
|
||||
messageSender = MessageSenderNoMcu(
|
||||
signalingMessageSender,
|
||||
callParticipants.keys,
|
||||
peerConnectionWrapperList
|
||||
)
|
||||
|
||||
@ -1895,11 +1897,15 @@ class CallActivity : CallBaseActivity() {
|
||||
|
||||
if (hasMCU) {
|
||||
messageSender = MessageSenderMcu(
|
||||
signalingMessageSender,
|
||||
callParticipants.keys,
|
||||
peerConnectionWrapperList,
|
||||
webSocketClient!!.sessionId
|
||||
)
|
||||
} else {
|
||||
messageSender = MessageSenderNoMcu(
|
||||
signalingMessageSender,
|
||||
callParticipants.keys,
|
||||
peerConnectionWrapperList
|
||||
)
|
||||
}
|
||||
@ -1934,11 +1940,15 @@ class CallActivity : CallBaseActivity() {
|
||||
|
||||
if (hasMCU) {
|
||||
messageSender = MessageSenderMcu(
|
||||
signalingMessageSender,
|
||||
callParticipants.keys,
|
||||
peerConnectionWrapperList,
|
||||
webSocketClient!!.sessionId
|
||||
)
|
||||
} else {
|
||||
messageSender = MessageSenderNoMcu(
|
||||
signalingMessageSender,
|
||||
callParticipants.keys,
|
||||
peerConnectionWrapperList
|
||||
)
|
||||
}
|
||||
|
@ -7,16 +7,22 @@
|
||||
package com.nextcloud.talk.call;
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.DataChannelMessage;
|
||||
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage;
|
||||
import com.nextcloud.talk.signaling.SignalingMessageSender;
|
||||
import com.nextcloud.talk.webrtc.PeerConnectionWrapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class to send messages to participants in a call.
|
||||
* <p>
|
||||
* A specific subclass has to be created depending on whether an MCU is being used or not.
|
||||
* <p>
|
||||
* Note that, unlike signaling messages, data channel messages require a peer connection. Therefore data channel
|
||||
* Note that recipients of signaling messages are not validated, so no error will be triggered if trying to send a
|
||||
* message to a participant with a session ID that does not exist or is not in the call.
|
||||
* <p>
|
||||
* Also note that, unlike signaling messages, data channel messages require a peer connection. Therefore data channel
|
||||
* messages may not be received by a participant if there is no peer connection with that participant (for example, if
|
||||
* neither the local and remote participants have publishing rights). Moreover, data channel messages are expected to
|
||||
* be received only on peer connections with type "video", so data channel messages will not be sent on other peer
|
||||
@ -24,9 +30,17 @@ import java.util.List;
|
||||
*/
|
||||
public abstract class MessageSender {
|
||||
|
||||
private final SignalingMessageSender signalingMessageSender;
|
||||
|
||||
private final Set<String> callParticipantSessionIds;
|
||||
|
||||
protected final List<PeerConnectionWrapper> peerConnectionWrappers;
|
||||
|
||||
public MessageSender(List<PeerConnectionWrapper> peerConnectionWrappers) {
|
||||
public MessageSender(SignalingMessageSender signalingMessageSender,
|
||||
Set<String> callParticipantSessionIds,
|
||||
List<PeerConnectionWrapper> peerConnectionWrappers) {
|
||||
this.signalingMessageSender = signalingMessageSender;
|
||||
this.callParticipantSessionIds = callParticipantSessionIds;
|
||||
this.peerConnectionWrappers = peerConnectionWrappers;
|
||||
}
|
||||
|
||||
@ -37,6 +51,35 @@ public abstract class MessageSender {
|
||||
*/
|
||||
public abstract void sendToAll(DataChannelMessage dataChannelMessage);
|
||||
|
||||
/**
|
||||
* Sends the given signaling message to the given session ID.
|
||||
* <p>
|
||||
* Note that the signaling message will be modified to set the recipient in the "to" field.
|
||||
*
|
||||
* @param ncSignalingMessage the message to send
|
||||
* @param sessionId the signaling session ID of the participant to send the message to
|
||||
*/
|
||||
public void send(NCSignalingMessage ncSignalingMessage, String sessionId) {
|
||||
ncSignalingMessage.setTo(sessionId);
|
||||
|
||||
signalingMessageSender.send(ncSignalingMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the given signaling message to all the participants in the call.
|
||||
* <p>
|
||||
* Note that the signaling message will be modified to set each of the recipients in the "to" field.
|
||||
*
|
||||
* @param ncSignalingMessage the message to send
|
||||
*/
|
||||
public void sendToAll(NCSignalingMessage ncSignalingMessage) {
|
||||
for (String sessionId: callParticipantSessionIds) {
|
||||
ncSignalingMessage.setTo(sessionId);
|
||||
|
||||
signalingMessageSender.send(ncSignalingMessage);
|
||||
}
|
||||
}
|
||||
|
||||
protected PeerConnectionWrapper getPeerConnectionWrapper(String sessionId) {
|
||||
for (PeerConnectionWrapper peerConnectionWrapper: peerConnectionWrappers) {
|
||||
if (peerConnectionWrapper.getSessionId().equals(sessionId)
|
||||
|
@ -7,9 +7,11 @@
|
||||
package com.nextcloud.talk.call;
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.DataChannelMessage;
|
||||
import com.nextcloud.talk.signaling.SignalingMessageSender;
|
||||
import com.nextcloud.talk.webrtc.PeerConnectionWrapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class to send messages to participants in a call when an MCU is used.
|
||||
@ -21,9 +23,11 @@ public class MessageSenderMcu extends MessageSender {
|
||||
|
||||
private final String ownSessionId;
|
||||
|
||||
public MessageSenderMcu(List<PeerConnectionWrapper> peerConnectionWrappers,
|
||||
public MessageSenderMcu(SignalingMessageSender signalingMessageSender,
|
||||
Set<String> callParticipantSessionIds,
|
||||
List<PeerConnectionWrapper> peerConnectionWrappers,
|
||||
String ownSessionId) {
|
||||
super(peerConnectionWrappers);
|
||||
super(signalingMessageSender, callParticipantSessionIds, peerConnectionWrappers);
|
||||
|
||||
this.ownSessionId = ownSessionId;
|
||||
}
|
||||
|
@ -7,17 +7,21 @@
|
||||
package com.nextcloud.talk.call;
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.DataChannelMessage;
|
||||
import com.nextcloud.talk.signaling.SignalingMessageSender;
|
||||
import com.nextcloud.talk.webrtc.PeerConnectionWrapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Helper class to send messages to participants in a call when an MCU is not used.
|
||||
*/
|
||||
public class MessageSenderNoMcu extends MessageSender {
|
||||
|
||||
public MessageSenderNoMcu(List<PeerConnectionWrapper> peerConnectionWrappers) {
|
||||
super(peerConnectionWrappers);
|
||||
public MessageSenderNoMcu(SignalingMessageSender signalingMessageSender,
|
||||
Set<String> callParticipantSessionIds,
|
||||
List<PeerConnectionWrapper> peerConnectionWrappers) {
|
||||
super(signalingMessageSender, callParticipantSessionIds, peerConnectionWrappers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@
|
||||
package com.nextcloud.talk.call
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.DataChannelMessage
|
||||
import com.nextcloud.talk.signaling.SignalingMessageSender
|
||||
import com.nextcloud.talk.webrtc.PeerConnectionWrapper
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -27,6 +28,10 @@ class MessageSenderMcuTest {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val signalingMessageSender = Mockito.mock(SignalingMessageSender::class.java)
|
||||
|
||||
val callParticipants = HashMap<String, CallParticipant>()
|
||||
|
||||
peerConnectionWrappers = ArrayList()
|
||||
|
||||
peerConnectionWrapper1 = Mockito.mock(PeerConnectionWrapper::class.java)
|
||||
@ -59,7 +64,12 @@ class MessageSenderMcuTest {
|
||||
Mockito.`when`(ownPeerConnectionWrapperScreen!!.videoStreamType).thenReturn("screen")
|
||||
peerConnectionWrappers!!.add(ownPeerConnectionWrapperScreen)
|
||||
|
||||
messageSender = MessageSenderMcu(peerConnectionWrappers, "ownSessionId")
|
||||
messageSender = MessageSenderMcu(
|
||||
signalingMessageSender,
|
||||
callParticipants.keys,
|
||||
peerConnectionWrappers,
|
||||
"ownSessionId"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -7,6 +7,7 @@
|
||||
package com.nextcloud.talk.call
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.DataChannelMessage
|
||||
import com.nextcloud.talk.signaling.SignalingMessageSender
|
||||
import com.nextcloud.talk.webrtc.PeerConnectionWrapper
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
@ -25,6 +26,10 @@ class MessageSenderNoMcuTest {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val signalingMessageSender = Mockito.mock(SignalingMessageSender::class.java)
|
||||
|
||||
val callParticipants = HashMap<String, CallParticipant>()
|
||||
|
||||
peerConnectionWrappers = ArrayList()
|
||||
|
||||
peerConnectionWrapper1 = Mockito.mock(PeerConnectionWrapper::class.java)
|
||||
@ -47,7 +52,7 @@ class MessageSenderNoMcuTest {
|
||||
Mockito.`when`(peerConnectionWrapper4Screen!!.videoStreamType).thenReturn("screen")
|
||||
peerConnectionWrappers!!.add(peerConnectionWrapper4Screen)
|
||||
|
||||
messageSender = MessageSenderNoMcu(peerConnectionWrappers)
|
||||
messageSender = MessageSenderNoMcu(signalingMessageSender, callParticipants.keys, peerConnectionWrappers)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
134
app/src/test/java/com/nextcloud/talk/call/MessageSenderTest.kt
Normal file
134
app/src/test/java/com/nextcloud/talk/call/MessageSenderTest.kt
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Daniel Calviño Sánchez <danxuliu@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package com.nextcloud.talk.call
|
||||
|
||||
import com.nextcloud.talk.models.json.signaling.DataChannelMessage
|
||||
import com.nextcloud.talk.models.json.signaling.NCSignalingMessage
|
||||
import com.nextcloud.talk.signaling.SignalingMessageSender
|
||||
import com.nextcloud.talk.webrtc.PeerConnectionWrapper
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.doAnswer
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.invocation.InvocationOnMock
|
||||
|
||||
class MessageSenderTest {
|
||||
|
||||
private class MessageSender(
|
||||
signalingMessageSender: SignalingMessageSender?,
|
||||
callParticipantSessionIds: Set<String>?,
|
||||
peerConnectionWrappers: List<PeerConnectionWrapper>?
|
||||
) : com.nextcloud.talk.call.MessageSender(
|
||||
signalingMessageSender,
|
||||
callParticipantSessionIds,
|
||||
peerConnectionWrappers
|
||||
) {
|
||||
|
||||
override fun sendToAll(dataChannelMessage: DataChannelMessage?) {
|
||||
// Not used in base class tests
|
||||
}
|
||||
}
|
||||
|
||||
private var signalingMessageSender: SignalingMessageSender? = null
|
||||
|
||||
private var callParticipants: MutableMap<String, CallParticipant>? = null
|
||||
|
||||
private var messageSender: MessageSender? = null
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
signalingMessageSender = Mockito.mock(SignalingMessageSender::class.java)
|
||||
|
||||
callParticipants = HashMap()
|
||||
|
||||
val callParticipant1: CallParticipant = Mockito.mock(CallParticipant::class.java)
|
||||
callParticipants!!["theSessionId1"] = callParticipant1
|
||||
|
||||
val callParticipant2: CallParticipant = Mockito.mock(CallParticipant::class.java)
|
||||
callParticipants!!["theSessionId2"] = callParticipant2
|
||||
|
||||
val callParticipant3: CallParticipant = Mockito.mock(CallParticipant::class.java)
|
||||
callParticipants!!["theSessionId3"] = callParticipant3
|
||||
|
||||
val callParticipant4: CallParticipant = Mockito.mock(CallParticipant::class.java)
|
||||
callParticipants!!["theSessionId4"] = callParticipant4
|
||||
|
||||
val peerConnectionWrappers = ArrayList<PeerConnectionWrapper>()
|
||||
|
||||
messageSender = MessageSender(signalingMessageSender, callParticipants!!.keys, peerConnectionWrappers)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSendSignalingMessage() {
|
||||
val message: NCSignalingMessage = Mockito.mock(NCSignalingMessage::class.java)
|
||||
messageSender!!.send(message, "theSessionId2")
|
||||
|
||||
Mockito.verify(message).to = "theSessionId2"
|
||||
Mockito.verify(signalingMessageSender!!).send(message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSendSignalingMessageIfUnknownSessionId() {
|
||||
val message: NCSignalingMessage = Mockito.mock(NCSignalingMessage::class.java)
|
||||
messageSender!!.send(message, "unknownSessionId")
|
||||
|
||||
Mockito.verify(message).to = "unknownSessionId"
|
||||
Mockito.verify(signalingMessageSender!!).send(message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSendSignalingMessageToAll() {
|
||||
val sentTo: MutableList<String?> = ArrayList()
|
||||
doAnswer { invocation: InvocationOnMock ->
|
||||
val arguments = invocation.arguments
|
||||
val message = (arguments[0] as NCSignalingMessage)
|
||||
|
||||
sentTo.add(message.to)
|
||||
null
|
||||
}.`when`(signalingMessageSender!!).send(any())
|
||||
|
||||
val message = NCSignalingMessage()
|
||||
messageSender!!.sendToAll(message)
|
||||
|
||||
assertTrue(sentTo.contains("theSessionId1"))
|
||||
assertTrue(sentTo.contains("theSessionId2"))
|
||||
assertTrue(sentTo.contains("theSessionId3"))
|
||||
assertTrue(sentTo.contains("theSessionId4"))
|
||||
Mockito.verify(signalingMessageSender!!, times(4)).send(message)
|
||||
Mockito.verifyNoMoreInteractions(signalingMessageSender)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSendSignalingMessageToAllWhenParticipantsWereUpdated() {
|
||||
val callParticipant5: CallParticipant = Mockito.mock(CallParticipant::class.java)
|
||||
callParticipants!!["theSessionId5"] = callParticipant5
|
||||
|
||||
callParticipants!!.remove("theSessionId2")
|
||||
callParticipants!!.remove("theSessionId3")
|
||||
|
||||
val sentTo: MutableList<String?> = ArrayList()
|
||||
doAnswer { invocation: InvocationOnMock ->
|
||||
val arguments = invocation.arguments
|
||||
val message = (arguments[0] as NCSignalingMessage)
|
||||
|
||||
sentTo.add(message.to)
|
||||
null
|
||||
}.`when`(signalingMessageSender!!).send(any())
|
||||
|
||||
val message = NCSignalingMessage()
|
||||
messageSender!!.sendToAll(message)
|
||||
|
||||
assertTrue(sentTo.contains("theSessionId1"))
|
||||
assertTrue(sentTo.contains("theSessionId4"))
|
||||
assertTrue(sentTo.contains("theSessionId5"))
|
||||
Mockito.verify(signalingMessageSender!!, times(3)).send(message)
|
||||
Mockito.verifyNoMoreInteractions(signalingMessageSender)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user