From dc530235726ff09b5108cc611b1d8b0aa16d619b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 25 Nov 2022 10:59:32 +0100 Subject: [PATCH 01/14] Update displayed nick when received in offers or answers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nick was displayed when updated through a data channel message, or when a ParticipantDisplayItem was created and the nick was already received. However, when the HPB is not used the nick is not sent after a connection is established, as it was sent already in the offer or answer. The nick from the offer or answer has not been received yet when the ParticipantDisplayItem is initially created, so the nick only appeared because a new ParticipantDisplayItem is created again when the connection is finally established. Due to all that the displayed nick is now updated as soon as it is received in an offer or answer, which ensures that the nick is shown independently of when was the ParticipantDisplayItem created. Note that this only applies to non-HPB scenarios; when the HPB is used the nick is got from the participant list update sent through signaling messages, so it is already known when creating the display item (in some very strange cases it might happen that an offer is received before the participant list was updated, but this should not happen, and in any case it will be handled at a later point). Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 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 bfcf198d0..13d48c75b 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2018,7 +2018,7 @@ public class CallActivity extends CallBaseActivity { } if (!publisher && !hasExternalSignalingServer && offerAnswerNickProviders.get(sessionId) == null) { - OfferAnswerNickProvider offerAnswerNickProvider = new OfferAnswerNickProvider(); + OfferAnswerNickProvider offerAnswerNickProvider = new OfferAnswerNickProvider(sessionId); offerAnswerNickProviders.put(sessionId, offerAnswerNickProvider); signalingMessageReceiver.addListener(offerAnswerNickProvider.getVideoWebRtcMessageListener(), sessionId, "video"); signalingMessageReceiver.addListener(offerAnswerNickProvider.getScreenWebRtcMessageListener(), sessionId, "screen"); @@ -2570,18 +2570,18 @@ public class CallActivity extends CallBaseActivity { } } - private static class OfferAnswerNickProvider { + private class OfferAnswerNickProvider { private class WebRtcMessageListener implements SignalingMessageReceiver.WebRtcMessageListener { @Override public void onOffer(String sdp, String nick) { - (OfferAnswerNickProvider.this).nick = nick; + onOfferOrAnswer(nick); } @Override public void onAnswer(String sdp, String nick) { - (OfferAnswerNickProvider.this).nick = nick; + onOfferOrAnswer(nick); } @Override @@ -2596,8 +2596,31 @@ public class CallActivity extends CallBaseActivity { private final WebRtcMessageListener videoWebRtcMessageListener = new WebRtcMessageListener(); private final WebRtcMessageListener screenWebRtcMessageListener = new WebRtcMessageListener(); + private final String sessionId; + private String nick; + private OfferAnswerNickProvider(String sessionId) { + this.sessionId = sessionId; + } + + private void onOfferOrAnswer(String nick) { + this.nick = nick; + + boolean notifyDataSetChanged = false; + if (participantDisplayItems.get(sessionId + "-video") != null) { + participantDisplayItems.get(sessionId + "-video").setNick(nick); + notifyDataSetChanged = true; + } + if (participantDisplayItems.get(sessionId + "-screen") != null) { + participantDisplayItems.get(sessionId + "-screen").setNick(nick); + notifyDataSetChanged = true; + } + if (notifyDataSetChanged) { + participantsAdapter.notifyDataSetChanged(); + } + } + public WebRtcMessageListener getVideoWebRtcMessageListener() { return videoWebRtcMessageListener; } From 29d0574667c022737b888e8331370b1a092ce43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Mon, 21 Nov 2022 21:49:17 +0100 Subject: [PATCH 02/14] Create ParticipantDisplayItem on media event if it does not exist yet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of creating a new ParticipantDisplayItem from scratch, which resets the full grid, now the existing one is updated; a new one is created only if no item existed already for the session and video stream type of the media event. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 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 13d48c75b..c36fc553f 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2225,17 +2225,10 @@ public class CallActivity extends CallBaseActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MediaStreamEvent mediaStreamEvent) { - if (mediaStreamEvent.getMediaStream() != null) { - boolean hasAtLeastOneVideoStream = mediaStreamEvent.getMediaStream().videoTracks != null - && mediaStreamEvent.getMediaStream().videoTracks.size() > 0; - - setupVideoStreamForLayout( - mediaStreamEvent.getMediaStream(), - mediaStreamEvent.getSession(), - null, - hasAtLeastOneVideoStream, - mediaStreamEvent.getVideoStreamType()); - } else { + String participantDisplayItemId = mediaStreamEvent.getSession() + "-" + mediaStreamEvent.getVideoStreamType(); + if (participantDisplayItems.get(participantDisplayItemId) == null) { + // Initial setup, ignore media related properties as they will be set after it. + // userId is unknown from the event, but it will be got based on the session id. setupVideoStreamForLayout( null, mediaStreamEvent.getSession(), @@ -2243,6 +2236,17 @@ public class CallActivity extends CallBaseActivity { false, mediaStreamEvent.getVideoStreamType()); } + + boolean hasAtLeastOneVideoStream = false; + if (mediaStreamEvent.getMediaStream() != null) { + hasAtLeastOneVideoStream = mediaStreamEvent.getMediaStream().videoTracks != null + && mediaStreamEvent.getMediaStream().videoTracks.size() > 0; + } + + ParticipantDisplayItem participantDisplayItem = participantDisplayItems.get(participantDisplayItemId); + participantDisplayItem.setMediaStream(mediaStreamEvent.getMediaStream()); + participantDisplayItem.setStreamEnabled(hasAtLeastOneVideoStream); + participantsAdapter.notifyDataSetChanged(); } @Override From 6e222e7cd244fcad4ed53bc728c6489cecd5e56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Mon, 21 Nov 2022 22:05:04 +0100 Subject: [PATCH 03/14] Create ParticipantDisplayItem when creating the connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ParticipantDisplayItem for "video" was created when a participant joined the room, but the item for "screen" was created when the stream for the screen was connected. Due to this the item for the remote screen share just "popped up" once connected, but there was no hint of a connection being established, like done with the video streams. Now the ParticipantDisplayItems are created as soon as a PeerConnectionWrapper is created and then updated as needed (for example to set the user ID or the stream), which causes the item to immediately appear and a progress bar to be shown until the connection is established. Although the ParticipantDisplayItem may be created on a different thread (the main thread) than the PeerConnectionWrapper "runOnUiThread" executes the enqueued messages in order (and it also establishes a "happens-before" relation with further calls of "runOnUiThread" due to the internal use of synchronized blocks, although it is not explicitly documented), so the item will be already created when later updated. This also holds true when an offer is received even before the participant is seen as joined (a very rare case that can happen if the signaling message with the updated participant list is lost for any reason); the ParticipantDisplayItem is created when the offer is received and it is later updated with the user ID once a new signaling message with the updated participant list is received. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 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 c36fc553f..d8e9dfb09 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -1858,15 +1858,22 @@ public class CallActivity extends CallBaseActivity { getOrCreatePeerConnectionWrapperForSessionIdAndType(sessionId, VIDEO_STREAM_TYPE_VIDEO, false); String userId = userIdsBySessionId.get(sessionId); - - runOnUiThread(() -> { - setupVideoStreamForLayout( - null, - sessionId, - userId, - false, - VIDEO_STREAM_TYPE_VIDEO); - }); + if (userId != null) { + runOnUiThread(() -> { + boolean notifyDataSetChanged = false; + if (participantDisplayItems.get(sessionId + "-video") != null) { + participantDisplayItems.get(sessionId + "-video").setUserId(userId); + notifyDataSetChanged = true; + } + if (participantDisplayItems.get(sessionId + "-screen") != null) { + participantDisplayItems.get(sessionId + "-screen").setUserId(userId); + notifyDataSetChanged = true; + } + if (notifyDataSetChanged) { + participantsAdapter.notifyDataSetChanged(); + } + }); + } } if (newSessions.size() > 0 && currentCallStatus != CallStatus.IN_CONVERSATION) { @@ -2024,6 +2031,18 @@ public class CallActivity extends CallBaseActivity { signalingMessageReceiver.addListener(offerAnswerNickProvider.getScreenWebRtcMessageListener(), sessionId, "screen"); } + if (!publisher) { + runOnUiThread(() -> { + // userId is unknown here, but it will be got based on the session id, and the stream will be + // updated once it is added to the connection. + setupVideoStreamForLayout( + null, + sessionId, + false, + type); + }); + } + if (publisher) { startSendingNick(); } @@ -2227,14 +2246,7 @@ public class CallActivity extends CallBaseActivity { public void onMessageEvent(MediaStreamEvent mediaStreamEvent) { String participantDisplayItemId = mediaStreamEvent.getSession() + "-" + mediaStreamEvent.getVideoStreamType(); if (participantDisplayItems.get(participantDisplayItemId) == null) { - // Initial setup, ignore media related properties as they will be set after it. - // userId is unknown from the event, but it will be got based on the session id. - setupVideoStreamForLayout( - null, - mediaStreamEvent.getSession(), - null, - false, - mediaStreamEvent.getVideoStreamType()); + return; } boolean hasAtLeastOneVideoStream = false; @@ -2260,7 +2272,6 @@ public class CallActivity extends CallBaseActivity { private void setupVideoStreamForLayout(@Nullable MediaStream mediaStream, String session, - String userId, boolean videoStreamEnabled, String videoStreamType) { PeerConnectionWrapper peerConnectionWrapper = getPeerConnectionWrapperForSessionIdAndType(session, @@ -2280,20 +2291,17 @@ public class CallActivity extends CallBaseActivity { nick = offerAnswerNickProviders.get(session) != null ? offerAnswerNickProviders.get(session).getNick() : ""; } - String userId4Usage = userId; - - if (userId4Usage == null) { - if (hasMCU) { - userId4Usage = webSocketClient.getUserIdForSession(session); - } else if (participantMap.get(session) != null && participantMap.get(session).getCalculatedActorType() == Participant.ActorType.USERS) { - userId4Usage = participantMap.get(session).getCalculatedActorId(); - } + String userId = null; + if (hasMCU) { + userId = webSocketClient.getUserIdForSession(session); + } else if (participantMap.get(session) != null && participantMap.get(session).getCalculatedActorType() == Participant.ActorType.USERS) { + userId = participantMap.get(session).getCalculatedActorId(); } String defaultGuestNick = getResources().getString(R.string.nc_nick_guest); ParticipantDisplayItem participantDisplayItem = new ParticipantDisplayItem(baseUrl, - userId4Usage, + userId, session, connected, nick, From 29117e8b1b6a1304d949e496bb229583f59c4622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Sun, 27 Nov 2022 14:38:11 +0100 Subject: [PATCH 04/14] Get user ID from signaling message when creating ParticipantDisplayItem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user ID set when creating the ParticipantDisplayItem was got from the join event when the external signaling server was used, and from an API call when the internal signaling server was used. However, the user ID is already known from the signaling message that updates the participant list, and is the one set on the ParticipantDisplayItems when a participant joins the call. Therefore the other sources are not needed, so now it is unified to always use the value from the signaling message. Note that in the rare cases in which a ParticipantDisplayItem is created before the participant is seen as in the call the user ID will be temporary unknown, although it will be automatically fixed once the participant list update is received. Moreover, even if the other sources were used it was not guaranteed that the user ID was known, so this should not be a problem. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 53 ++----------------- .../talk/webrtc/MagicWebSocketInstance.java | 11 ---- 2 files changed, 3 insertions(+), 61 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 d8e9dfb09..cb07bc62a 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -74,7 +74,6 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall; import com.nextcloud.talk.models.json.conversations.RoomsOverall; import com.nextcloud.talk.models.json.generic.GenericOverall; import com.nextcloud.talk.models.json.participants.Participant; -import com.nextcloud.talk.models.json.participants.ParticipantsOverall; import com.nextcloud.talk.models.json.signaling.DataChannelMessage; import com.nextcloud.talk.models.json.signaling.NCMessagePayload; import com.nextcloud.talk.models.json.signaling.NCSignalingMessage; @@ -236,7 +235,7 @@ public class CallActivity extends CallBaseActivity { private MediaStream localStream; private String credentials; private List peerConnectionWrapperList = new ArrayList<>(); - private Map participantMap = new HashMap<>(); + private Map userIdsBySessionId = new HashMap<>(); private boolean videoOn = false; private boolean microphoneOn = false; @@ -1775,7 +1774,7 @@ public class CallActivity extends CallBaseActivity { Log.d(TAG, "processUsersInRoom"); List newSessions = new ArrayList<>(); Set oldSessions = new HashSet<>(); - Map userIdsBySessionId = new HashMap<>(); + userIdsBySessionId = new HashMap<>(); hasMCU = hasExternalSignalingServer && webSocketClient != null && webSocketClient.hasMCU(); Log.d(TAG, " hasMCU is " + hasMCU); @@ -1844,10 +1843,6 @@ public class CallActivity extends CallBaseActivity { return; } - if (newSessions.size() > 0 && !hasMCU) { - getPeersForCall(); - } - if (hasMCU) { // Ensure that own publishing peer is set up. getOrCreatePeerConnectionWrapperForSessionIdAndType(webSocketClient.getSessionId(), VIDEO_STREAM_TYPE_VIDEO, true); @@ -1886,43 +1881,6 @@ public class CallActivity extends CallBaseActivity { } } - private void getPeersForCall() { - Log.d(TAG, "getPeersForCall"); - int apiVersion = ApiUtils.getCallApiVersion(conversationUser, new int[]{ApiUtils.APIv4, 1}); - - ncApi.getPeersForCall( - credentials, - ApiUtils.getUrlForCall( - apiVersion, - baseUrl, - roomToken)) - .subscribeOn(Schedulers.io()) - .subscribe(new Observer() { - @Override - public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) { - // unused atm - } - - @Override - public void onNext(@io.reactivex.annotations.NonNull ParticipantsOverall participantsOverall) { - participantMap = new HashMap<>(); - for (Participant participant : participantsOverall.getOcs().getData()) { - participantMap.put(participant.getSessionId(), participant); - } - } - - @Override - public void onError(@io.reactivex.annotations.NonNull Throwable e) { - Log.e(TAG, "error while executing getPeersForCall", e); - } - - @Override - public void onComplete() { - // unused atm - } - }); - } - private void deletePeerConnection(PeerConnectionWrapper peerConnectionWrapper) { peerConnectionWrapper.removePeerConnection(); peerConnectionWrapperList.remove(peerConnectionWrapper); @@ -2291,12 +2249,7 @@ public class CallActivity extends CallBaseActivity { nick = offerAnswerNickProviders.get(session) != null ? offerAnswerNickProviders.get(session).getNick() : ""; } - String userId = null; - if (hasMCU) { - userId = webSocketClient.getUserIdForSession(session); - } else if (participantMap.get(session) != null && participantMap.get(session).getCalculatedActorType() == Participant.ActorType.USERS) { - userId = participantMap.get(session).getCalculatedActorId(); - } + String userId = userIdsBySessionId.get(session); String defaultGuestNick = getResources().getString(R.string.nc_nick_guest); diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java index 49df4b00e..da98e27f3 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/MagicWebSocketInstance.java @@ -386,17 +386,6 @@ public class MagicWebSocketInstance extends WebSocketListener { return ""; } - public String getUserIdForSession(String session) { - Participant participant = usersHashMap.get(session); - if (participant != null) { - if (participant.getCalculatedActorType() == USERS) { - return participant.getCalculatedActorId(); - } - } - - return ""; - } - @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onMessageEvent(NetworkEvent networkEvent) { if (networkEvent.getNetworkConnectionEvent() == NetworkEvent.NetworkConnectionEvent.NETWORK_CONNECTED && !isConnected()) { From 30aafed0e8777096f8f03393a7cce598445c1af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 01:24:40 +0100 Subject: [PATCH 05/14] Post MediaStreamEvent when the stream is actually added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MediaStreamEvent was posted when the connection with the remote peer was established. However, the MediaStream is added earlier (as soon as the remote description is received), so the event is moved to better reflect that. Note that checking if the connection is an MCU publisher is no longer needed, as publisher connections are sender only and therefore no remote stream is added for publisher connections. In any case, note that the stream will not start until the connection is established, and a progress bar will be anyway shown on the ParticipantDisplayItem until it is connected. Signed-off-by: Daniel Calviño Sánchez --- .../com/nextcloud/talk/webrtc/PeerConnectionWrapper.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java index c5b2f66b2..5ea4806c7 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java @@ -100,7 +100,6 @@ public class PeerConnectionWrapper { private final MediaConstraints mediaConstraints; private DataChannel dataChannel; private final MagicSdpObserver magicSdpObserver; - private MediaStream remoteStream; private final boolean hasInitiated; @@ -416,10 +415,6 @@ public class PeerConnectionWrapper { EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED, sessionId, null, null, videoStreamType)); - if (!isMCUPublisher) { - EventBus.getDefault().post(new MediaStreamEvent(remoteStream, sessionId, videoStreamType)); - } - if (hasInitiated) { sendInitialMediaStatus(); } @@ -477,7 +472,7 @@ public class PeerConnectionWrapper { @Override public void onAddStream(MediaStream mediaStream) { - remoteStream = mediaStream; + EventBus.getDefault().post(new MediaStreamEvent(mediaStream, sessionId, videoStreamType)); } @Override From 64c4f8c7ee6bae413c5df88cd86c02e57aa2f0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 01:28:01 +0100 Subject: [PATCH 06/14] Remove unneeded condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The publisher peer connection when the HPB is used is a sender only connection, so it never adds or removes a remote stream. Signed-off-by: Daniel Calviño Sánchez --- .../java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java index 5ea4806c7..48cb1f581 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java @@ -477,9 +477,7 @@ public class PeerConnectionWrapper { @Override public void onRemoveStream(MediaStream mediaStream) { - if (!isMCUPublisher) { - EventBus.getDefault().post(new MediaStreamEvent(null, sessionId, videoStreamType)); - } + EventBus.getDefault().post(new MediaStreamEvent(null, sessionId, videoStreamType)); } @Override From 4457e925042b5bcf0088a2bcb9fc46e63569c59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 13:33:26 +0100 Subject: [PATCH 07/14] Generalize PUBLISHER_FAILED event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than emitting PUBLISHER_FAILED when the publisher connection fails now PEER_FAILED is emitted when any connection fails, and the handler checks if the connection was the publisher one to apply the specific behaviour. Signed-off-by: Daniel Calviño Sánchez --- .../com/nextcloud/talk/activities/CallActivity.java | 10 ++++++---- .../com/nextcloud/talk/events/PeerConnectionEvent.java | 2 +- .../nextcloud/talk/webrtc/PeerConnectionWrapper.java | 5 ++--- 3 files changed, 9 insertions(+), 8 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 cb07bc62a..e2eab2d30 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2153,10 +2153,12 @@ public class CallActivity extends CallBaseActivity { } } } else if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PUBLISHER_FAILED) { - setCallState(CallStatus.PUBLISHER_FAILED); - webSocketClient.clearResumeId(); - hangup(false); + PeerConnectionEvent.PeerConnectionEventType.PEER_FAILED) { + if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { + setCallState(CallStatus.PUBLISHER_FAILED); + webSocketClient.clearResumeId(); + hangup(false); + } } } diff --git a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java b/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java index fd10c30ce..e83385ac4 100644 --- a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java +++ b/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java @@ -120,6 +120,6 @@ public class PeerConnectionEvent { } public enum PeerConnectionEventType { - PEER_CONNECTED, PEER_DISCONNECTED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR, PUBLISHER_FAILED + PEER_CONNECTED, PEER_DISCONNECTED, PEER_FAILED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR } } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java index 48cb1f581..bcf3773d6 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java @@ -432,9 +432,8 @@ public class PeerConnectionWrapper { } else if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED, sessionId, null, null, videoStreamType)); - if (isMCUPublisher) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PUBLISHER_FAILED, sessionId, null, null, videoStreamType)); - } + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_FAILED, + sessionId, null, null, videoStreamType)); } } From 337f3d4b5e3b555f69b9ea956b9c0cbcd4d4f980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 13:40:58 +0100 Subject: [PATCH 08/14] Extract methods to handle connections and disconnections of peers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 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 e2eab2d30..9f3604af2 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2117,24 +2117,13 @@ public class CallActivity extends CallBaseActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) { String sessionId = peerConnectionEvent.getSessionId(); - String participantDisplayItemId = sessionId + "-" + peerConnectionEvent.getVideoStreamType(); if (peerConnectionEvent.getPeerConnectionEventType() == PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED) { - if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { - updateSelfVideoViewConnected(true); - } else if (participantDisplayItems.get(participantDisplayItemId) != null) { - participantDisplayItems.get(participantDisplayItemId).setConnected(true); - participantsAdapter.notifyDataSetChanged(); - } + handlePeerConnected(sessionId, peerConnectionEvent.getVideoStreamType()); } else if (peerConnectionEvent.getPeerConnectionEventType() == PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED) { - if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { - updateSelfVideoViewConnected(false); - } else if (participantDisplayItems.get(participantDisplayItemId) != null) { - participantDisplayItems.get(participantDisplayItemId).setConnected(false); - participantsAdapter.notifyDataSetChanged(); - } + handlePeerDisconnected(sessionId, peerConnectionEvent.getVideoStreamType()); } else if (peerConnectionEvent.getPeerConnectionEventType() == PeerConnectionEvent.PeerConnectionEventType.PEER_CLOSED) { endPeerConnection(sessionId, VIDEO_STREAM_TYPE_SCREEN.equals(peerConnectionEvent.getVideoStreamType())); @@ -2162,6 +2151,28 @@ public class CallActivity extends CallBaseActivity { } } + private void handlePeerConnected(String sessionId, String videoStreamType) { + String participantDisplayItemId = sessionId + "-" + videoStreamType; + + if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { + updateSelfVideoViewConnected(true); + } else if (participantDisplayItems.get(participantDisplayItemId) != null) { + participantDisplayItems.get(participantDisplayItemId).setConnected(true); + participantsAdapter.notifyDataSetChanged(); + } + } + + private void handlePeerDisconnected(String sessionId, String videoStreamType) { + String participantDisplayItemId = sessionId + "-" + videoStreamType; + + if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { + updateSelfVideoViewConnected(false); + } else if (participantDisplayItems.get(participantDisplayItemId) != null) { + participantDisplayItems.get(participantDisplayItemId).setConnected(false); + participantsAdapter.notifyDataSetChanged(); + } + } + private void startSendingNick() { DataChannelMessage dataChannelMessage = new DataChannelMessage(); dataChannelMessage.setType("nickChanged"); From fcbfc1926d7b8924c21d053c2467b90f8cd39956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 13:54:19 +0100 Subject: [PATCH 09/14] Post MediaStreamEvents for each connection state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than simplifying the states to "CONNECTED" and "DISCONNECTED" now the raw state is posted, and the handler then decides how to treat them (which, for now, is exactly as before). Signed-off-by: Daniel Calviño Sánchez --- .../nextcloud/talk/activities/CallActivity.java | 12 ++++++++++-- .../nextcloud/talk/events/PeerConnectionEvent.java | 2 +- .../talk/webrtc/PeerConnectionWrapper.java | 14 ++++++++------ 3 files changed, 19 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 9f3604af2..8d25ebd80 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2119,10 +2119,16 @@ public class CallActivity extends CallBaseActivity { String sessionId = peerConnectionEvent.getSessionId(); if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED) { + PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED || + peerConnectionEvent.getPeerConnectionEventType() == + PeerConnectionEvent.PeerConnectionEventType.PEER_COMPLETED) { handlePeerConnected(sessionId, peerConnectionEvent.getVideoStreamType()); } else if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED) { + PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED || + peerConnectionEvent.getPeerConnectionEventType() == + PeerConnectionEvent.PeerConnectionEventType.PEER_NEW || + peerConnectionEvent.getPeerConnectionEventType() == + PeerConnectionEvent.PeerConnectionEventType.PEER_CHECKING) { handlePeerDisconnected(sessionId, peerConnectionEvent.getVideoStreamType()); } else if (peerConnectionEvent.getPeerConnectionEventType() == PeerConnectionEvent.PeerConnectionEventType.PEER_CLOSED) { @@ -2147,6 +2153,8 @@ public class CallActivity extends CallBaseActivity { setCallState(CallStatus.PUBLISHER_FAILED); webSocketClient.clearResumeId(); hangup(false); + } else { + handlePeerDisconnected(sessionId, peerConnectionEvent.getVideoStreamType()); } } } diff --git a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java b/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java index e83385ac4..28ff31ab3 100644 --- a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java +++ b/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java @@ -120,6 +120,6 @@ public class PeerConnectionEvent { } public enum PeerConnectionEventType { - PEER_CONNECTED, PEER_DISCONNECTED, PEER_FAILED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR + PEER_NEW, PEER_CHECKING, PEER_CONNECTED, PEER_COMPLETED, PEER_DISCONNECTED, PEER_FAILED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR } } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java index bcf3773d6..5c9eac672 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java @@ -419,19 +419,21 @@ public class PeerConnectionWrapper { sendInitialMediaStatus(); } } else if (iceConnectionState == PeerConnection.IceConnectionState.COMPLETED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED, + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_COMPLETED, sessionId, null, null, videoStreamType)); } else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType .PEER_CLOSED, sessionId, null, null, videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED || - iceConnectionState == PeerConnection.IceConnectionState.NEW || - iceConnectionState == PeerConnection.IceConnectionState.CHECKING) { + } else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) { EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED, sessionId, null, null, videoStreamType)); + } else if (iceConnectionState == PeerConnection.IceConnectionState.NEW) { + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_NEW, + sessionId, null, null, videoStreamType)); + } else if (iceConnectionState == PeerConnection.IceConnectionState.CHECKING) { + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_CHECKING, + sessionId, null, null, videoStreamType)); } else if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED, - sessionId, null, null, videoStreamType)); EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_FAILED, sessionId, null, null, videoStreamType)); } From 04f1679e2a7c304a6b4f9e14e196a103b8fe5958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 19:24:39 +0100 Subject: [PATCH 10/14] Add observer for peer connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The observer is just an adapter for the "PeerConnection.Observer" provided by the WebRTC library; a custom observer is used to expose only the events needed outside "PeerConnectionWrapper". For now only the same events that were already handled are taken into account, but at a later point additional events (like "onAddTrack" instead of "onAddStream", which is deprecated) could be added too. Note that the thread used to handle the events has changed; the EventBus subscriber mode was "MAIN", but as the events were posted from a PeerConnection observer, which run in a worker thread rather than in the main thread, the subscriber was executed in the main thread rather than in the same thread as the poster. Due to this the actions performed by the handler now must be explicitly run in the main thread. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 123 +++++++++++------- .../talk/webrtc/PeerConnectionNotifier.java | 68 ++++++++++ .../talk/webrtc/PeerConnectionWrapper.java | 62 +++++---- 3 files changed, 180 insertions(+), 73 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java 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 8d25ebd80..8acd14b52 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -63,7 +63,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.databinding.CallActivityBinding; import com.nextcloud.talk.events.ConfigurationChangeEvent; -import com.nextcloud.talk.events.MediaStreamEvent; import com.nextcloud.talk.events.NetworkEvent; import com.nextcloud.talk.events.PeerConnectionEvent; import com.nextcloud.talk.events.WebSocketCommunicationEvent; @@ -269,6 +268,8 @@ public class CallActivity extends CallBaseActivity { private Map dataChannelMessageListeners = new HashMap<>(); + private Map peerConnectionObservers = new HashMap<>(); + private SignalingMessageReceiver.ParticipantListMessageListener participantListMessageListener = new SignalingMessageReceiver.ParticipantListMessageListener() { @Override @@ -1989,6 +1990,11 @@ public class CallActivity extends CallBaseActivity { signalingMessageReceiver.addListener(offerAnswerNickProvider.getScreenWebRtcMessageListener(), sessionId, "screen"); } + PeerConnectionWrapper.PeerConnectionObserver peerConnectionObserver = + new CallActivityPeerConnectionObserver(sessionId, type); + peerConnectionObservers.put(sessionId + "-" + type, peerConnectionObserver); + peerConnectionWrapper.addObserver(peerConnectionObserver); + if (!publisher) { runOnUiThread(() -> { // userId is unknown here, but it will be got based on the session id, and the stream will be @@ -2031,6 +2037,9 @@ public class CallActivity extends CallBaseActivity { } String videoStreamType = peerConnectionWrapper.getVideoStreamType(); if (VIDEO_STREAM_TYPE_SCREEN.equals(videoStreamType) || !justScreen) { + PeerConnectionWrapper.PeerConnectionObserver peerConnectionObserver = peerConnectionObservers.remove(sessionId + "-" + videoStreamType); + peerConnectionWrapper.removeObserver(peerConnectionObserver); + runOnUiThread(() -> removeMediaStream(sessionId, videoStreamType)); deletePeerConnection(peerConnectionWrapper); } @@ -2116,24 +2125,7 @@ public class CallActivity extends CallBaseActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) { - String sessionId = peerConnectionEvent.getSessionId(); - - if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED || - peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_COMPLETED) { - handlePeerConnected(sessionId, peerConnectionEvent.getVideoStreamType()); - } else if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED || - peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_NEW || - peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_CHECKING) { - handlePeerDisconnected(sessionId, peerConnectionEvent.getVideoStreamType()); - } else if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_CLOSED) { - endPeerConnection(sessionId, VIDEO_STREAM_TYPE_SCREEN.equals(peerConnectionEvent.getVideoStreamType())); - } else if (peerConnectionEvent.getPeerConnectionEventType() == + if (peerConnectionEvent.getPeerConnectionEventType() == PeerConnectionEvent.PeerConnectionEventType.SENSOR_FAR || peerConnectionEvent.getPeerConnectionEventType() == PeerConnectionEvent.PeerConnectionEventType.SENSOR_NEAR) { @@ -2147,15 +2139,6 @@ public class CallActivity extends CallBaseActivity { toggleMedia(enableVideo, true); } } - } else if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.PEER_FAILED) { - if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { - setCallState(CallStatus.PUBLISHER_FAILED); - webSocketClient.clearResumeId(); - hangup(false); - } else { - handlePeerDisconnected(sessionId, peerConnectionEvent.getVideoStreamType()); - } } } @@ -2221,25 +2204,6 @@ public class CallActivity extends CallBaseActivity { } } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(MediaStreamEvent mediaStreamEvent) { - String participantDisplayItemId = mediaStreamEvent.getSession() + "-" + mediaStreamEvent.getVideoStreamType(); - if (participantDisplayItems.get(participantDisplayItemId) == null) { - return; - } - - boolean hasAtLeastOneVideoStream = false; - if (mediaStreamEvent.getMediaStream() != null) { - hasAtLeastOneVideoStream = mediaStreamEvent.getMediaStream().videoTracks != null - && mediaStreamEvent.getMediaStream().videoTracks.size() > 0; - } - - ParticipantDisplayItem participantDisplayItem = participantDisplayItems.get(participantDisplayItemId); - participantDisplayItem.setMediaStream(mediaStreamEvent.getMediaStream()); - participantDisplayItem.setStreamEnabled(hasAtLeastOneVideoStream); - participantsAdapter.notifyDataSetChanged(); - } - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -2694,6 +2658,71 @@ public class CallActivity extends CallBaseActivity { } } + private class CallActivityPeerConnectionObserver implements PeerConnectionWrapper.PeerConnectionObserver { + + private final String sessionId; + private final String videoStreamType; + private final String participantDisplayItemId; + + private CallActivityPeerConnectionObserver(String sessionId, String videoStreamType) { + this.sessionId = sessionId; + this.videoStreamType = videoStreamType; + this.participantDisplayItemId = sessionId + "-" + videoStreamType; + } + + @Override + public void onStreamAdded(MediaStream mediaStream) { + handleStream(mediaStream); + } + + @Override + public void onStreamRemoved(MediaStream mediaStream) { + handleStream(null); + } + + private void handleStream(MediaStream mediaStream) { + runOnUiThread(() -> { + if (participantDisplayItems.get(participantDisplayItemId) == null) { + return; + } + + boolean hasAtLeastOneVideoStream = false; + if (mediaStream != null) { + hasAtLeastOneVideoStream = mediaStream.videoTracks != null && mediaStream.videoTracks.size() > 0; + } + + ParticipantDisplayItem participantDisplayItem = participantDisplayItems.get(participantDisplayItemId); + participantDisplayItem.setMediaStream(mediaStream); + participantDisplayItem.setStreamEnabled(hasAtLeastOneVideoStream); + participantsAdapter.notifyDataSetChanged(); + }); + } + + @Override + public void onIceConnectionStateChanged(PeerConnection.IceConnectionState iceConnectionState) { + runOnUiThread(() -> { + if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED || + iceConnectionState == PeerConnection.IceConnectionState.COMPLETED) { + handlePeerConnected(sessionId, videoStreamType); + } else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED || + iceConnectionState == PeerConnection.IceConnectionState.NEW || + iceConnectionState == PeerConnection.IceConnectionState.CHECKING) { + handlePeerDisconnected(sessionId, videoStreamType); + } else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { + endPeerConnection(sessionId, VIDEO_STREAM_TYPE_SCREEN.equals(videoStreamType)); + } else if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { + if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { + setCallState(CallStatus.PUBLISHER_FAILED); + webSocketClient.clearResumeId(); + hangup(false); + } else { + handlePeerDisconnected(sessionId, videoStreamType); + } + } + }); + } + } + private class InternalSignalingMessageSender implements SignalingMessageSender { @Override diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java new file mode 100644 index 000000000..d2a9db207 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionNotifier.java @@ -0,0 +1,68 @@ +/* + * Nextcloud Talk application + * + * @author Daniel Calviño Sánchez + * Copyright (C) 2022 Daniel Calviño Sánchez + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.nextcloud.talk.webrtc; + +import org.webrtc.MediaStream; +import org.webrtc.PeerConnection; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Helper class to register and notify PeerConnectionObserver. + * + * This class is only meant for internal use by PeerConnectionWrapper; observers must register themselves against + * a PeerConnectionWrapper rather than against a PeerConnectionNotifier. + */ +public class PeerConnectionNotifier { + + private final Set peerConnectionObservers = new LinkedHashSet<>(); + + public synchronized void addObserver(PeerConnectionWrapper.PeerConnectionObserver observer) { + if (observer == null) { + throw new IllegalArgumentException("PeerConnectionObserver can not be null"); + } + + peerConnectionObservers.add(observer); + } + + public synchronized void removeObserver(PeerConnectionWrapper.PeerConnectionObserver observer) { + peerConnectionObservers.remove(observer); + } + + public synchronized void notifyStreamAdded(MediaStream stream) { + for (PeerConnectionWrapper.PeerConnectionObserver observer : new ArrayList<>(peerConnectionObservers)) { + observer.onStreamAdded(stream); + } + } + + public synchronized void notifyStreamRemoved(MediaStream stream) { + for (PeerConnectionWrapper.PeerConnectionObserver observer : new ArrayList<>(peerConnectionObservers)) { + observer.onStreamRemoved(stream); + } + } + + public synchronized void notifyIceConnectionStateChanged(PeerConnection.IceConnectionState state) { + for (PeerConnectionWrapper.PeerConnectionObserver observer : new ArrayList<>(peerConnectionObservers)) { + observer.onIceConnectionStateChanged(state); + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java index 5c9eac672..f4a7d6b7e 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java @@ -28,8 +28,6 @@ import android.util.Log; import com.bluelinelabs.logansquare.LoganSquare; import com.nextcloud.talk.application.NextcloudTalkApplication; -import com.nextcloud.talk.events.MediaStreamEvent; -import com.nextcloud.talk.events.PeerConnectionEvent; import com.nextcloud.talk.models.json.signaling.DataChannelMessage; import com.nextcloud.talk.models.json.signaling.NCIceCandidate; import com.nextcloud.talk.models.json.signaling.NCMessagePayload; @@ -37,7 +35,6 @@ import com.nextcloud.talk.models.json.signaling.NCSignalingMessage; import com.nextcloud.talk.signaling.SignalingMessageReceiver; import com.nextcloud.talk.signaling.SignalingMessageSender; -import org.greenrobot.eventbus.EventBus; import org.webrtc.AudioTrack; import org.webrtc.DataChannel; import org.webrtc.IceCandidate; @@ -85,6 +82,21 @@ public class PeerConnectionWrapper { void onNickChanged(String nick); } + /** + * Observer for changes on the peer connection. + * + * The changes are bound to a specific peer connection, so each observer is expected to handle messages only for + * a single peer connection. + * + * All methods are called on the so called "signaling" thread of WebRTC, which is an internal thread created by the + * WebRTC library and NOT the same thread where signaling messages are received. + */ + public interface PeerConnectionObserver { + void onStreamAdded(MediaStream mediaStream); + void onStreamRemoved(MediaStream mediaStream); + void onIceConnectionStateChanged(PeerConnection.IceConnectionState iceConnectionState); + } + private static final String TAG = PeerConnectionWrapper.class.getCanonicalName(); private final SignalingMessageReceiver signalingMessageReceiver; @@ -94,6 +106,8 @@ public class PeerConnectionWrapper { private final DataChannelMessageNotifier dataChannelMessageNotifier = new DataChannelMessageNotifier(); + private final PeerConnectionNotifier peerConnectionNotifier = new PeerConnectionNotifier(); + private List iceCandidates = new ArrayList<>(); private PeerConnection peerConnection; private String sessionId; @@ -186,6 +200,21 @@ public class PeerConnectionWrapper { dataChannelMessageNotifier.removeListener(listener); } + /** + * Adds an observer for peer connection changes. + * + * An observer is expected to be added only once. If the same observer is added again it will be notified just once. + * + * @param observer the PeerConnectionObserver + */ + public void addObserver(PeerConnectionObserver observer) { + peerConnectionNotifier.addObserver(observer); + } + + public void removeObserver(PeerConnectionObserver observer) { + peerConnectionNotifier.removeObserver(observer); + } + public String getVideoStreamType() { return videoStreamType; } @@ -412,31 +441,12 @@ public class PeerConnectionWrapper { Log.d("iceConnectionChangeTo: ", iceConnectionState.name() + " over " + peerConnection.hashCode() + " " + sessionId); if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_CONNECTED, - sessionId, null, null, videoStreamType)); - if (hasInitiated) { sendInitialMediaStatus(); } - } else if (iceConnectionState == PeerConnection.IceConnectionState.COMPLETED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_COMPLETED, - sessionId, null, null, videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType - .PEER_CLOSED, sessionId, null, null, videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_DISCONNECTED, - sessionId, null, null, videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.NEW) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_NEW, - sessionId, null, null, videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.CHECKING) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_CHECKING, - sessionId, null, null, videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.PEER_FAILED, - sessionId, null, null, videoStreamType)); } + + peerConnectionNotifier.notifyIceConnectionStateChanged(iceConnectionState); } @Override @@ -473,12 +483,12 @@ public class PeerConnectionWrapper { @Override public void onAddStream(MediaStream mediaStream) { - EventBus.getDefault().post(new MediaStreamEvent(mediaStream, sessionId, videoStreamType)); + peerConnectionNotifier.notifyStreamAdded(mediaStream); } @Override public void onRemoveStream(MediaStream mediaStream) { - EventBus.getDefault().post(new MediaStreamEvent(null, sessionId, videoStreamType)); + peerConnectionNotifier.notifyStreamRemoved(mediaStream); } @Override From 34498efa72c0b97936f0cda408f965e1dc66aca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 23 Nov 2022 12:40:01 +0100 Subject: [PATCH 11/14] Rewrite if/else chain as if/return blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just a matter of preference :-) Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 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 8acd14b52..9b2d71eb6 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2704,13 +2704,25 @@ public class CallActivity extends CallBaseActivity { if (iceConnectionState == PeerConnection.IceConnectionState.CONNECTED || iceConnectionState == PeerConnection.IceConnectionState.COMPLETED) { handlePeerConnected(sessionId, videoStreamType); - } else if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED || + + return; + } + + if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED || iceConnectionState == PeerConnection.IceConnectionState.NEW || iceConnectionState == PeerConnection.IceConnectionState.CHECKING) { handlePeerDisconnected(sessionId, videoStreamType); - } else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { + + return; + } + + if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { endPeerConnection(sessionId, VIDEO_STREAM_TYPE_SCREEN.equals(videoStreamType)); - } else if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { + + return; + } + + if (iceConnectionState == PeerConnection.IceConnectionState.FAILED) { if (webSocketClient != null && webSocketClient.getSessionId() != null && webSocketClient.getSessionId().equals(sessionId)) { setCallState(CallStatus.PUBLISHER_FAILED); webSocketClient.clearResumeId(); @@ -2718,6 +2730,8 @@ public class CallActivity extends CallBaseActivity { } else { handlePeerDisconnected(sessionId, videoStreamType); } + + return; } }); } From c8398695f4fa6554997b90967cb00b711157a48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 19:37:02 +0100 Subject: [PATCH 12/14] Remove no longer needed code after removing EventBus message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../talk/events/MediaStreamEvent.java | 96 ------------------- .../talk/events/PeerConnectionEvent.java | 60 +----------- .../talk/webrtc/WebRtcAudioManager.java | 6 +- 3 files changed, 6 insertions(+), 156 deletions(-) delete mode 100644 app/src/main/java/com/nextcloud/talk/events/MediaStreamEvent.java diff --git a/app/src/main/java/com/nextcloud/talk/events/MediaStreamEvent.java b/app/src/main/java/com/nextcloud/talk/events/MediaStreamEvent.java deleted file mode 100644 index 9db02e2b4..000000000 --- a/app/src/main/java/com/nextcloud/talk/events/MediaStreamEvent.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Nextcloud Talk application - * - * @author Mario Danic - * Copyright (C) 2017 Mario Danic - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.nextcloud.talk.events; - -import org.webrtc.MediaStream; - -import androidx.annotation.Nullable; - -public class MediaStreamEvent { - private final MediaStream mediaStream; - private final String session; - private final String videoStreamType; - - public MediaStreamEvent(@Nullable MediaStream mediaStream, String session, String videoStreamType) { - this.mediaStream = mediaStream; - this.session = session; - this.videoStreamType = videoStreamType; - } - - public MediaStream getMediaStream() { - return this.mediaStream; - } - - public String getSession() { - return this.session; - } - - public String getVideoStreamType() { - return this.videoStreamType; - } - - public boolean equals(final Object o) { - if (o == this) { - return true; - } - if (!(o instanceof MediaStreamEvent)) { - return false; - } - final MediaStreamEvent other = (MediaStreamEvent) o; - if (!other.canEqual((Object) this)) { - return false; - } - final Object this$mediaStream = this.getMediaStream(); - final Object other$mediaStream = other.getMediaStream(); - if (this$mediaStream == null ? other$mediaStream != null : !this$mediaStream.equals(other$mediaStream)) { - return false; - } - final Object this$session = this.getSession(); - final Object other$session = other.getSession(); - if (this$session == null ? other$session != null : !this$session.equals(other$session)) { - return false; - } - final Object this$videoStreamType = this.getVideoStreamType(); - final Object other$videoStreamType = other.getVideoStreamType(); - - return this$videoStreamType == null ? other$videoStreamType == null : this$videoStreamType.equals(other$videoStreamType); - } - - protected boolean canEqual(final Object other) { - return other instanceof MediaStreamEvent; - } - - public int hashCode() { - final int PRIME = 59; - int result = 1; - final Object $mediaStream = this.getMediaStream(); - result = result * PRIME + ($mediaStream == null ? 43 : $mediaStream.hashCode()); - final Object $session = this.getSession(); - result = result * PRIME + ($session == null ? 43 : $session.hashCode()); - final Object $videoStreamType = this.getVideoStreamType(); - result = result * PRIME + ($videoStreamType == null ? 43 : $videoStreamType.hashCode()); - return result; - } - - public String toString() { - return "MediaStreamEvent(mediaStream=" + this.getMediaStream() + ", session=" + this.getSession() + ", videoStreamType=" + this.getVideoStreamType() + ")"; - } -} diff --git a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java b/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java index 28ff31ab3..143325e5c 100644 --- a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java +++ b/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java @@ -20,44 +20,17 @@ package com.nextcloud.talk.events; -import androidx.annotation.Nullable; - public class PeerConnectionEvent { private final PeerConnectionEventType peerConnectionEventType; - private final String sessionId; - private final String nick; - private final Boolean changeValue; - private final String videoStreamType; - public PeerConnectionEvent(PeerConnectionEventType peerConnectionEventType, @Nullable String sessionId, - @Nullable String nick, Boolean changeValue, @Nullable String videoStreamType) { + public PeerConnectionEvent(PeerConnectionEventType peerConnectionEventType) { this.peerConnectionEventType = peerConnectionEventType; - this.nick = nick; - this.changeValue = changeValue; - this.sessionId = sessionId; - this.videoStreamType = videoStreamType; } public PeerConnectionEventType getPeerConnectionEventType() { return this.peerConnectionEventType; } - public String getSessionId() { - return this.sessionId; - } - - public String getNick() { - return this.nick; - } - - public Boolean getChangeValue() { - return this.changeValue; - } - - public String getVideoStreamType() { - return this.videoStreamType; - } - public boolean equals(final Object o) { if (o == this) { return true; @@ -74,25 +47,8 @@ public class PeerConnectionEvent { if (this$peerConnectionEventType == null ? other$peerConnectionEventType != null : !this$peerConnectionEventType.equals(other$peerConnectionEventType)) { return false; } - final Object this$sessionId = this.getSessionId(); - final Object other$sessionId = other.getSessionId(); - if (this$sessionId == null ? other$sessionId != null : !this$sessionId.equals(other$sessionId)) { - return false; - } - final Object this$nick = this.getNick(); - final Object other$nick = other.getNick(); - if (this$nick == null ? other$nick != null : !this$nick.equals(other$nick)) { - return false; - } - final Object this$changeValue = this.getChangeValue(); - final Object other$changeValue = other.getChangeValue(); - if (this$changeValue == null ? other$changeValue != null : !this$changeValue.equals(other$changeValue)) { - return false; - } - final Object this$videoStreamType = this.getVideoStreamType(); - final Object other$videoStreamType = other.getVideoStreamType(); - return this$videoStreamType == null ? other$videoStreamType == null : this$videoStreamType.equals(other$videoStreamType); + return true; } protected boolean canEqual(final Object other) { @@ -104,22 +60,14 @@ public class PeerConnectionEvent { int result = 1; final Object $peerConnectionEventType = this.getPeerConnectionEventType(); result = result * PRIME + ($peerConnectionEventType == null ? 43 : $peerConnectionEventType.hashCode()); - final Object $sessionId = this.getSessionId(); - result = result * PRIME + ($sessionId == null ? 43 : $sessionId.hashCode()); - final Object $nick = this.getNick(); - result = result * PRIME + ($nick == null ? 43 : $nick.hashCode()); - final Object $changeValue = this.getChangeValue(); - result = result * PRIME + ($changeValue == null ? 43 : $changeValue.hashCode()); - final Object $videoStreamType = this.getVideoStreamType(); - result = result * PRIME + ($videoStreamType == null ? 43 : $videoStreamType.hashCode()); return result; } public String toString() { - return "PeerConnectionEvent(peerConnectionEventType=" + this.getPeerConnectionEventType() + ", sessionId=" + this.getSessionId() + ", nick=" + this.getNick() + ", changeValue=" + this.getChangeValue() + ", videoStreamType=" + this.getVideoStreamType() + ")"; + return "PeerConnectionEvent(peerConnectionEventType=" + this.getPeerConnectionEventType() + ")"; } public enum PeerConnectionEventType { - PEER_NEW, PEER_CHECKING, PEER_CONNECTED, PEER_COMPLETED, PEER_DISCONNECTED, PEER_FAILED, PEER_CLOSED, SENSOR_FAR, SENSOR_NEAR + SENSOR_FAR, SENSOR_NEAR } } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java index dd0818a4f..1d3914849 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java @@ -136,15 +136,13 @@ public class WebRtcAudioManager { setAudioDeviceInternal(AudioDevice.EARPIECE); Log.d(TAG, "switched to EARPIECE because userSelectedAudioDevice was SPEAKER_PHONE and proximity=near"); - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType - .SENSOR_NEAR, null, null, null, null)); + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.SENSOR_NEAR)); } else { setAudioDeviceInternal(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE); Log.d(TAG, "switched to SPEAKER_PHONE because userSelectedAudioDevice was SPEAKER_PHONE and proximity=far"); - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType - .SENSOR_FAR, null, null, null, null)); + EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.SENSOR_FAR)); } } } From 5d7b5160b7ccada6cf4969b2de03cf7e73c154dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 19:47:00 +0100 Subject: [PATCH 13/14] Rename PeerConnectionEvent to ProximitySensorEvent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proximity sensor events should not have been part of PeerConnectionEvent. However, now that all the peer connection related properties were removed the remaining event can be renamed to something more accurate. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 16 +++++----- ...onEvent.java => ProximitySensorEvent.java} | 32 +++++++++---------- .../talk/webrtc/WebRtcAudioManager.java | 6 ++-- 3 files changed, 27 insertions(+), 27 deletions(-) rename app/src/main/java/com/nextcloud/talk/events/{PeerConnectionEvent.java => ProximitySensorEvent.java} (52%) 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 9b2d71eb6..fddc97f59 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -64,7 +64,7 @@ import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.databinding.CallActivityBinding; import com.nextcloud.talk.events.ConfigurationChangeEvent; import com.nextcloud.talk.events.NetworkEvent; -import com.nextcloud.talk.events.PeerConnectionEvent; +import com.nextcloud.talk.events.ProximitySensorEvent; import com.nextcloud.talk.events.WebSocketCommunicationEvent; import com.nextcloud.talk.models.ExternalSignalingServer; import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall; @@ -2124,15 +2124,15 @@ public class CallActivity extends CallBaseActivity { } @Subscribe(threadMode = ThreadMode.MAIN) - public void onMessageEvent(PeerConnectionEvent peerConnectionEvent) { - if (peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.SENSOR_FAR || - peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.SENSOR_NEAR) { + public void onMessageEvent(ProximitySensorEvent proximitySensorEvent) { + if (proximitySensorEvent.getProximitySensorEventType() == + ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR || + proximitySensorEvent.getProximitySensorEventType() == + ProximitySensorEvent.ProximitySensorEventType.SENSOR_NEAR) { if (!isVoiceOnlyCall) { - boolean enableVideo = peerConnectionEvent.getPeerConnectionEventType() == - PeerConnectionEvent.PeerConnectionEventType.SENSOR_FAR && videoOn; + boolean enableVideo = proximitySensorEvent.getProximitySensorEventType() == + ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR && videoOn; if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && (currentCallStatus == CallStatus.CONNECTING || isConnectionEstablished()) && videoOn && enableVideo != localVideoTrack.enabled()) { diff --git a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java b/app/src/main/java/com/nextcloud/talk/events/ProximitySensorEvent.java similarity index 52% rename from app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java rename to app/src/main/java/com/nextcloud/talk/events/ProximitySensorEvent.java index 143325e5c..9864db731 100644 --- a/app/src/main/java/com/nextcloud/talk/events/PeerConnectionEvent.java +++ b/app/src/main/java/com/nextcloud/talk/events/ProximitySensorEvent.java @@ -20,31 +20,31 @@ package com.nextcloud.talk.events; -public class PeerConnectionEvent { - private final PeerConnectionEventType peerConnectionEventType; +public class ProximitySensorEvent { + private final ProximitySensorEventType proximitySensorEventType; - public PeerConnectionEvent(PeerConnectionEventType peerConnectionEventType) { - this.peerConnectionEventType = peerConnectionEventType; + public ProximitySensorEvent(ProximitySensorEventType proximitySensorEventType) { + this.proximitySensorEventType = proximitySensorEventType; } - public PeerConnectionEventType getPeerConnectionEventType() { - return this.peerConnectionEventType; + public ProximitySensorEventType getProximitySensorEventType() { + return this.proximitySensorEventType; } public boolean equals(final Object o) { if (o == this) { return true; } - if (!(o instanceof PeerConnectionEvent)) { + if (!(o instanceof ProximitySensorEvent)) { return false; } - final PeerConnectionEvent other = (PeerConnectionEvent) o; + final ProximitySensorEvent other = (ProximitySensorEvent) o; if (!other.canEqual((Object) this)) { return false; } - final Object this$peerConnectionEventType = this.getPeerConnectionEventType(); - final Object other$peerConnectionEventType = other.getPeerConnectionEventType(); - if (this$peerConnectionEventType == null ? other$peerConnectionEventType != null : !this$peerConnectionEventType.equals(other$peerConnectionEventType)) { + final Object this$proximitySensorEventType = this.getProximitySensorEventType(); + final Object other$proximitySensorEventType = other.getProximitySensorEventType(); + if (this$proximitySensorEventType == null ? other$proximitySensorEventType != null : !this$proximitySensorEventType.equals(other$proximitySensorEventType)) { return false; } @@ -52,22 +52,22 @@ public class PeerConnectionEvent { } protected boolean canEqual(final Object other) { - return other instanceof PeerConnectionEvent; + return other instanceof ProximitySensorEvent; } public int hashCode() { final int PRIME = 59; int result = 1; - final Object $peerConnectionEventType = this.getPeerConnectionEventType(); - result = result * PRIME + ($peerConnectionEventType == null ? 43 : $peerConnectionEventType.hashCode()); + final Object $proximitySensorEventType = this.getProximitySensorEventType(); + result = result * PRIME + ($proximitySensorEventType == null ? 43 : $proximitySensorEventType.hashCode()); return result; } public String toString() { - return "PeerConnectionEvent(peerConnectionEventType=" + this.getPeerConnectionEventType() + ")"; + return "ProximitySensorEvent(proximitySensorEventType=" + this.getProximitySensorEventType() + ")"; } - public enum PeerConnectionEventType { + public enum ProximitySensorEventType { SENSOR_FAR, SENSOR_NEAR } } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java index 1d3914849..f7e36034e 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java @@ -43,7 +43,7 @@ import android.media.AudioDeviceInfo; import android.media.AudioManager; import android.util.Log; -import com.nextcloud.talk.events.PeerConnectionEvent; +import com.nextcloud.talk.events.ProximitySensorEvent; import com.nextcloud.talk.utils.power.PowerManagerUtils; import org.greenrobot.eventbus.EventBus; @@ -136,13 +136,13 @@ public class WebRtcAudioManager { setAudioDeviceInternal(AudioDevice.EARPIECE); Log.d(TAG, "switched to EARPIECE because userSelectedAudioDevice was SPEAKER_PHONE and proximity=near"); - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.SENSOR_NEAR)); + EventBus.getDefault().post(new ProximitySensorEvent(ProximitySensorEvent.ProximitySensorEventType.SENSOR_NEAR)); } else { setAudioDeviceInternal(WebRtcAudioManager.AudioDevice.SPEAKER_PHONE); Log.d(TAG, "switched to SPEAKER_PHONE because userSelectedAudioDevice was SPEAKER_PHONE and proximity=far"); - EventBus.getDefault().post(new PeerConnectionEvent(PeerConnectionEvent.PeerConnectionEventType.SENSOR_FAR)); + EventBus.getDefault().post(new ProximitySensorEvent(ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR)); } } } From 4516de4add2ad12299bbf4b78757c7ca07f53177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 22 Nov 2022 19:49:51 +0100 Subject: [PATCH 14/14] Remove no longer needed condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the event is posted only for proximity sensor changes the condition is no longer needed. Signed-off-by: Daniel Calviño Sánchez --- .../talk/activities/CallActivity.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 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 fddc97f59..2402579e6 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.java @@ -2125,19 +2125,13 @@ public class CallActivity extends CallBaseActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(ProximitySensorEvent proximitySensorEvent) { - if (proximitySensorEvent.getProximitySensorEventType() == - ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR || - proximitySensorEvent.getProximitySensorEventType() == - ProximitySensorEvent.ProximitySensorEventType.SENSOR_NEAR) { - - if (!isVoiceOnlyCall) { - boolean enableVideo = proximitySensorEvent.getProximitySensorEventType() == - ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR && videoOn; - if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && - (currentCallStatus == CallStatus.CONNECTING || isConnectionEstablished()) && videoOn - && enableVideo != localVideoTrack.enabled()) { - toggleMedia(enableVideo, true); - } + if (!isVoiceOnlyCall) { + boolean enableVideo = proximitySensorEvent.getProximitySensorEventType() == + ProximitySensorEvent.ProximitySensorEventType.SENSOR_FAR && videoOn; + if (EffortlessPermissions.hasPermissions(this, PERMISSIONS_CAMERA) && + (currentCallStatus == CallStatus.CONNECTING || isConnectionEstablished()) && videoOn + && enableVideo != localVideoTrack.enabled()) { + toggleMedia(enableVideo, true); } } }