From 9ae969b0f82c30909c0189fb5d3432d897b9908b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 29 Nov 2022 20:34:32 +0100 Subject: [PATCH] Split call participants and peer connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of trying to create a video peer connection for any joined participant now only a call participant is created for any joined participant, and a video peer connection is created only for those participants that are publishing audio or video. If a call participants does not have a video peer connection the call participant is now seen as "connected" from the UI, as there is no need to show a progress bar for that participant. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 46 +++++++++++++++---- .../talk/adapters/ParticipantDisplayItem.java | 5 +- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java index 43705eccc..ee07afe0b 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -1721,14 +1721,22 @@ public class CallActivity extends CallBaseActivity { } } - List sessionIdsToEnd = new ArrayList(peerConnectionWrapperList.size()); + List peerConnectionIdsToEnd = new ArrayList(peerConnectionWrapperList.size()); for (PeerConnectionWrapper wrapper : peerConnectionWrapperList) { - sessionIdsToEnd.add(wrapper.getSessionId()); + peerConnectionIdsToEnd.add(wrapper.getSessionId()); } - for (String sessionId : sessionIdsToEnd) { + for (String sessionId : peerConnectionIdsToEnd) { endPeerConnection(sessionId, false); } + List callParticipantIdsToEnd = new ArrayList(peerConnectionWrapperList.size()); + for (CallParticipant callParticipant : callParticipants.values()) { + callParticipantIdsToEnd.add(callParticipant.getCallParticipantModel().getSessionId()); + } + for (String sessionId : callParticipantIdsToEnd) { + removeCallParticipant(sessionId); + } + hangupNetworkCalls(shutDownView); ApplicationWideCurrentRoomHolder.getInstance().setInCall(false); } @@ -1798,6 +1806,7 @@ public class CallActivity extends CallBaseActivity { participantsInCall.addAll(unchanged); boolean isSelfInCall = false; + Participant selfParticipant = null; for (Participant participant : participantsInCall) { long inCallFlag = participant.getInCall(); @@ -1809,6 +1818,7 @@ public class CallActivity extends CallBaseActivity { } else { Log.d(TAG, " inCallFlag of currentSessionId: " + inCallFlag); isSelfInCall = inCallFlag != 0; + selfParticipant = participant; } } @@ -1826,6 +1836,7 @@ public class CallActivity extends CallBaseActivity { String sessionId = participant.getSessionId(); Log.d(TAG, " session that will be removed is: " + sessionId); endPeerConnection(sessionId, false); + removeCallParticipant(sessionId); } return; @@ -1841,6 +1852,7 @@ public class CallActivity extends CallBaseActivity { } boolean selfJoined = false; + boolean selfParticipantHasAudioOrVideo = participantInCallFlagsHaveAudioOrVideo(selfParticipant); for (Participant participant : joined) { String sessionId = participant.getSessionId(); @@ -1856,7 +1868,8 @@ public class CallActivity extends CallBaseActivity { } Log.d(TAG, " newSession joined: " + sessionId); - getOrCreatePeerConnectionWrapperForSessionIdAndType(sessionId, VIDEO_STREAM_TYPE_VIDEO, false); + + CallParticipant callParticipant = addCallParticipant(sessionId); String userId = participant.getUserId(); if (userId != null) { @@ -1870,6 +1883,17 @@ public class CallActivity extends CallBaseActivity { nick = offerAnswerNickProviders.get(sessionId) != null ? offerAnswerNickProviders.get(sessionId).getNick() : ""; } callParticipants.get(sessionId).setNick(nick); + + boolean participantHasAudioOrVideo = participantInCallFlagsHaveAudioOrVideo(participant); + + // FIXME Without MCU, PeerConnectionWrapper only sends an offer if the local session ID is higher than the + // remote session ID. However, if the other participant does not have audio nor video that participant + // will not send an offer, so no connection is actually established when the remote participant has a + // higher session ID but is not publishing media. + if ((hasMCU && participantHasAudioOrVideo) || + (!hasMCU && selfParticipantHasAudioOrVideo && (!participantHasAudioOrVideo || sessionId.compareTo(currentSessionId) < 0))) { + getOrCreatePeerConnectionWrapperForSessionIdAndType(sessionId, VIDEO_STREAM_TYPE_VIDEO, false); + } } boolean othersInCall = selfJoined ? joined.size() > 1 : joined.size() > 0; @@ -1881,9 +1905,19 @@ public class CallActivity extends CallBaseActivity { String sessionId = participant.getSessionId(); Log.d(TAG, " oldSession that will be removed is: " + sessionId); endPeerConnection(sessionId, false); + removeCallParticipant(sessionId); } } + private boolean participantInCallFlagsHaveAudioOrVideo(Participant participant) { + if (participant == null) { + return false; + } + + return (participant.getInCall() & Participant.InCallFlags.WITH_AUDIO) > 0 || + (!isVoiceOnlyCall && (participant.getInCall() & Participant.InCallFlags.WITH_VIDEO) > 0); + } + private void deletePeerConnection(PeerConnectionWrapper peerConnectionWrapper) { peerConnectionWrapper.removePeerConnection(); peerConnectionWrapperList.remove(peerConnectionWrapper); @@ -2059,10 +2093,6 @@ public class CallActivity extends CallBaseActivity { } } } - - if (!justScreen) { - removeCallParticipant(sessionId); - } } private void removeCallParticipant(String sessionId) { diff --git a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java index 6a9912ead..418afa1a5 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/ParticipantDisplayItem.java @@ -95,7 +95,10 @@ public class ParticipantDisplayItem { public boolean isConnected() { return iceConnectionState == PeerConnection.IceConnectionState.CONNECTED || - iceConnectionState == PeerConnection.IceConnectionState.COMPLETED; + iceConnectionState == PeerConnection.IceConnectionState.COMPLETED || + // If there is no connection state that means that no connection is needed, so it is a special case that is + // also seen as "connected". + iceConnectionState == null; } public String getNick() {