mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 19:49:33 +01:00
Fix remote data channels not disposed when removing peer connection
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
This commit is contained in:
parent
c940175453
commit
4d4b8832aa
@ -34,6 +34,7 @@ import java.io.IOException;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -57,7 +58,7 @@ public class PeerConnectionWrapper {
|
|||||||
private PeerConnection peerConnection;
|
private PeerConnection peerConnection;
|
||||||
private String sessionId;
|
private String sessionId;
|
||||||
private final MediaConstraints mediaConstraints;
|
private final MediaConstraints mediaConstraints;
|
||||||
private DataChannel statusDataChannel;
|
private final Map<String, DataChannel> dataChannels = new HashMap<>();
|
||||||
private final SdpObserver sdpObserver;
|
private final SdpObserver sdpObserver;
|
||||||
|
|
||||||
private final boolean hasInitiated;
|
private final boolean hasInitiated;
|
||||||
@ -144,8 +145,11 @@ public class PeerConnectionWrapper {
|
|||||||
if (hasMCU || hasInitiated) {
|
if (hasMCU || hasInitiated) {
|
||||||
DataChannel.Init init = new DataChannel.Init();
|
DataChannel.Init init = new DataChannel.Init();
|
||||||
init.negotiated = false;
|
init.negotiated = false;
|
||||||
statusDataChannel = peerConnection.createDataChannel("status", init);
|
|
||||||
|
DataChannel statusDataChannel = peerConnection.createDataChannel("status", init);
|
||||||
statusDataChannel.registerObserver(new DataChannelObserver(statusDataChannel));
|
statusDataChannel.registerObserver(new DataChannelObserver(statusDataChannel));
|
||||||
|
dataChannels.put("status", statusDataChannel);
|
||||||
|
|
||||||
if (isMCUPublisher) {
|
if (isMCUPublisher) {
|
||||||
peerConnection.createOffer(sdpObserver, mediaConstraints);
|
peerConnection.createOffer(sdpObserver, mediaConstraints);
|
||||||
} else if (hasMCU && "video".equals(this.videoStreamType)) {
|
} else if (hasMCU && "video".equals(this.videoStreamType)) {
|
||||||
@ -233,13 +237,12 @@ public class PeerConnectionWrapper {
|
|||||||
public void removePeerConnection() {
|
public void removePeerConnection() {
|
||||||
signalingMessageReceiver.removeListener(webRtcMessageListener);
|
signalingMessageReceiver.removeListener(webRtcMessageListener);
|
||||||
|
|
||||||
if (statusDataChannel != null) {
|
for (DataChannel dataChannel: dataChannels.values()) {
|
||||||
statusDataChannel.dispose();
|
Log.d(TAG, "Disposed DataChannel " + dataChannel.label());
|
||||||
statusDataChannel = null;
|
|
||||||
Log.d(TAG, "Disposed DataChannel");
|
dataChannel.dispose();
|
||||||
} else {
|
|
||||||
Log.d(TAG, "DataChannel is null.");
|
|
||||||
}
|
}
|
||||||
|
dataChannels.clear();
|
||||||
|
|
||||||
if (peerConnection != null) {
|
if (peerConnection != null) {
|
||||||
peerConnection.close();
|
peerConnection.close();
|
||||||
@ -283,6 +286,7 @@ public class PeerConnectionWrapper {
|
|||||||
*/
|
*/
|
||||||
public void send(DataChannelMessage dataChannelMessage) {
|
public void send(DataChannelMessage dataChannelMessage) {
|
||||||
ByteBuffer buffer;
|
ByteBuffer buffer;
|
||||||
|
DataChannel statusDataChannel = dataChannels.get("status");
|
||||||
if (statusDataChannel != null && dataChannelMessage != null) {
|
if (statusDataChannel != null && dataChannelMessage != null) {
|
||||||
try {
|
try {
|
||||||
buffer = ByteBuffer.wrap(LoganSquare.serialize(dataChannelMessage).getBytes());
|
buffer = ByteBuffer.wrap(LoganSquare.serialize(dataChannelMessage).getBytes());
|
||||||
@ -525,7 +529,23 @@ public class PeerConnectionWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDataChannel(DataChannel dataChannel) {
|
public void onDataChannel(DataChannel dataChannel) {
|
||||||
|
// Another data channel with the same label, no matter if the same instance or a different one, should not
|
||||||
|
// be added, but just in case.
|
||||||
|
DataChannel oldDataChannel = dataChannels.get(dataChannel.label());
|
||||||
|
if (oldDataChannel == dataChannel) {
|
||||||
|
Log.w(TAG, "Data channel with label " + dataChannel.label() + " added again");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldDataChannel != null) {
|
||||||
|
Log.w(TAG, "Data channel with label " + dataChannel.label() + " exists");
|
||||||
|
|
||||||
|
oldDataChannel.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
dataChannel.registerObserver(new DataChannelObserver(dataChannel));
|
dataChannel.registerObserver(new DataChannelObserver(dataChannel));
|
||||||
|
dataChannels.put(dataChannel.label(), dataChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -288,4 +288,47 @@ class PeerConnectionWrapperTest {
|
|||||||
Mockito.verify(mockedDataChannelMessageListener).onAudioOff()
|
Mockito.verify(mockedDataChannelMessageListener).onAudioOff()
|
||||||
Mockito.verifyNoMoreInteractions(mockedDataChannelMessageListener)
|
Mockito.verifyNoMoreInteractions(mockedDataChannelMessageListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRemovePeerConnectionWithOpenRemoteDataChannel() {
|
||||||
|
val peerConnectionObserverArgumentCaptor: ArgumentCaptor<PeerConnection.Observer> =
|
||||||
|
ArgumentCaptor.forClass(PeerConnection.Observer::class.java)
|
||||||
|
|
||||||
|
Mockito.`when`(
|
||||||
|
mockedPeerConnectionFactory!!.createPeerConnection(
|
||||||
|
any(PeerConnection.RTCConfiguration::class.java),
|
||||||
|
peerConnectionObserverArgumentCaptor.capture()
|
||||||
|
)
|
||||||
|
).thenReturn(mockedPeerConnection)
|
||||||
|
|
||||||
|
val mockedStatusDataChannel = Mockito.mock(DataChannel::class.java)
|
||||||
|
Mockito.`when`(mockedStatusDataChannel.label()).thenReturn("status")
|
||||||
|
Mockito.`when`(mockedStatusDataChannel.state()).thenReturn(DataChannel.State.OPEN)
|
||||||
|
Mockito.`when`(mockedPeerConnection!!.createDataChannel(eq("status"), any()))
|
||||||
|
.thenReturn(mockedStatusDataChannel)
|
||||||
|
|
||||||
|
peerConnectionWrapper = PeerConnectionWrapper(
|
||||||
|
mockedPeerConnectionFactory,
|
||||||
|
ArrayList<PeerConnection.IceServer>(),
|
||||||
|
MediaConstraints(),
|
||||||
|
"the-session-id",
|
||||||
|
"the-local-session-id",
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
"video",
|
||||||
|
mockedSignalingMessageReceiver,
|
||||||
|
mockedSignalingMessageSender
|
||||||
|
)
|
||||||
|
|
||||||
|
val mockedRandomIdDataChannel = Mockito.mock(DataChannel::class.java)
|
||||||
|
Mockito.`when`(mockedRandomIdDataChannel.label()).thenReturn("random-id")
|
||||||
|
Mockito.`when`(mockedRandomIdDataChannel.state()).thenReturn(DataChannel.State.OPEN)
|
||||||
|
peerConnectionObserverArgumentCaptor.value.onDataChannel(mockedRandomIdDataChannel)
|
||||||
|
|
||||||
|
peerConnectionWrapper!!.removePeerConnection()
|
||||||
|
|
||||||
|
Mockito.verify(mockedStatusDataChannel).dispose()
|
||||||
|
Mockito.verify(mockedRandomIdDataChannel).dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user