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() {