diff --git a/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.kt index 6075300e22..44d174b9f0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.kt @@ -84,15 +84,15 @@ class WebRtcViewModel(state: WebRtcServiceState) { val state: State = state.callInfoState.callState val groupState: GroupCallState = state.callInfoState.groupCallState val recipient: Recipient = state.callInfoState.callRecipient - val isRemoteVideoOffer: Boolean = state.callSetupState.isRemoteVideoOffer + val isRemoteVideoOffer: Boolean = state.getCallSetupState(state.callInfoState.activePeer?.callId).isRemoteVideoOffer val callConnectedTime: Long = state.callInfoState.callConnectedTime val remoteParticipants: List = state.callInfoState.remoteCallParticipants val identityChangedParticipants: Set = state.callInfoState.identityChangedRecipients val remoteDevicesCount: OptionalLong = state.callInfoState.remoteDevicesCount val participantLimit: Long? = state.callInfoState.participantLimit @get:JvmName("shouldRingGroup") - val ringGroup: Boolean = state.callSetupState.ringGroup - val ringerRecipient: Recipient = state.callSetupState.ringerRecipient + val ringGroup: Boolean = state.getCallSetupState(state.callInfoState.activePeer?.callId).ringGroup + val ringerRecipient: Recipient = state.getCallSetupState(state.callInfoState.activePeer?.callId).ringerRecipient val activeDevice: SignalAudioManager.AudioDevice = state.localDeviceState.activeDevice val availableDevices: Set = state.localDeviceState.availableDevices @@ -123,6 +123,7 @@ class WebRtcViewModel(state: WebRtcServiceState) { participantLimit=$participantLimit, activeDevice=$activeDevice, availableDevices=$availableDevices, + ringGroup=$ringGroup } """.trimIndent() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index 055d299168..32c2923040 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -551,11 +551,11 @@ public final class MessageContentProcessor { MessageDatabase database = DatabaseFactory.getSmsDatabase(context); database.markAsMissedCall(smsMessageId.get(), message.getType() == OfferMessage.Type.VIDEO_CALL); } else { - RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId(), new CallId(message.getId())); byte[] remoteIdentityKey = ApplicationDependencies.getIdentityStore().getIdentityRecord(senderRecipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull(); ApplicationDependencies.getSignalCallManager() - .receivedOffer(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()), + .receivedOffer(new WebRtcData.CallMetadata(remotePeer, content.getSenderDevice()), new WebRtcData.OfferMetadata(message.getOpaque(), message.getSdp(), message.getType()), new WebRtcData.ReceivedOfferMetadata(remoteIdentityKey, content.getServerReceivedTimestamp(), @@ -569,11 +569,11 @@ public final class MessageContentProcessor { @NonNull Recipient senderRecipient) { log(String.valueOf(content), "handleCallAnswerMessage..."); - RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId(), new CallId(message.getId())); byte[] remoteIdentityKey = ApplicationDependencies.getIdentityStore().getIdentityRecord(senderRecipient.getId()).transform(record -> record.getIdentityKey().serialize()).orNull(); ApplicationDependencies.getSignalCallManager() - .receivedAnswer(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()), + .receivedAnswer(new WebRtcData.CallMetadata(remotePeer, content.getSenderDevice()), new WebRtcData.AnswerMetadata(message.getOpaque(), message.getSdp()), new WebRtcData.ReceivedAnswerMetadata(remoteIdentityKey, content.getCallMessage().get().isMultiRing())); } @@ -592,10 +592,10 @@ public final class MessageContentProcessor { callId = iceMessage.getId(); } - RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId(), new CallId(callId)); ApplicationDependencies.getSignalCallManager() - .receivedIceCandidates(new WebRtcData.CallMetadata(remotePeer, new CallId(callId), content.getSenderDevice()), + .receivedIceCandidates(new WebRtcData.CallMetadata(remotePeer, content.getSenderDevice()), iceCandidates); } @@ -608,10 +608,10 @@ public final class MessageContentProcessor { if (smsMessageId.isPresent()) { DatabaseFactory.getSmsDatabase(context).markAsMissedCall(smsMessageId.get(), false); } else { - RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId(), new CallId(message.getId())); ApplicationDependencies.getSignalCallManager() - .receivedCallHangup(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice()), + .receivedCallHangup(new WebRtcData.CallMetadata(remotePeer, content.getSenderDevice()), new WebRtcData.HangupMetadata(message.getType(), message.isLegacy(), message.getDeviceId())); } } @@ -622,10 +622,10 @@ public final class MessageContentProcessor { { log(String.valueOf(content.getTimestamp()), "handleCallBusyMessage"); - RemotePeer remotePeer = new RemotePeer(senderRecipient.getId()); + RemotePeer remotePeer = new RemotePeer(senderRecipient.getId(), new CallId(message.getId())); ApplicationDependencies.getSignalCallManager() - .receivedCallBusy(new WebRtcData.CallMetadata(remotePeer, new CallId(message.getId()), content.getSenderDevice())); + .receivedCallBusy(new WebRtcData.CallMetadata(remotePeer, content.getSenderDevice())); } private void handleCallOpaqueMessage(@NonNull SignalServiceContent content, diff --git a/app/src/main/java/org/thoughtcrime/securesms/ringrtc/RemotePeer.java b/app/src/main/java/org/thoughtcrime/securesms/ringrtc/RemotePeer.java index 504585871a..b9ab2af033 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ringrtc/RemotePeer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ringrtc/RemotePeer.java @@ -22,15 +22,22 @@ public final class RemotePeer implements Remote, Parcelable { private static final String TAG = Log.tag(RemotePeer.class); + public static final CallId NO_CALL_ID = new CallId(-1L); + public static final CallId GROUP_CALL_ID = new CallId(-2L); + @NonNull private final RecipientId recipientId; @NonNull private CallState callState; @NonNull private CallId callId; private long callStartTimestamp; public RemotePeer(@NonNull RecipientId recipientId) { + this(recipientId, new CallId(-1L)); + } + + public RemotePeer(@NonNull RecipientId recipientId, @NonNull CallId callId) { this.recipientId = recipientId; this.callState = CallState.IDLE; - this.callId = new CallId(-1L); + this.callId = callId; this.callStartTimestamp = 0; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java index 67b5f74358..c494b14d74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java @@ -162,7 +162,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { webRtcInteractor.stopForegroundService(); } - webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState(remotePeer).isRemoteVideoOffer()); return terminate(currentState, remotePeer); } @@ -190,7 +190,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { } if (incomingBeforeAccept) { - webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState(remotePeer).isRemoteVideoOffer()); } } else if (endedRemoteEvent == CallEvent.ENDED_REMOTE_BUSY && remotePeerIsActive) { activePeer.receivedBusy(); @@ -199,11 +199,11 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { ringer.start(OutgoingRinger.Type.BUSY); ThreadUtil.runOnMainDelayed(ringer::stop, SignalCallManager.BUSY_TONE_LENGTH); } else if (endedRemoteEvent == CallEvent.ENDED_REMOTE_GLARE && incomingBeforeAccept) { - webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState(remotePeer).isRemoteVideoOffer()); } if (state == WebRtcViewModel.State.CALL_ACCEPTED_ELSEWHERE) { - webRtcInteractor.insertReceivedCall(remotePeer, currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertReceivedCall(remotePeer, currentState.getCallSetupState(remotePeer).isRemoteVideoOffer()); } currentState = currentState.builder() @@ -230,7 +230,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { } if (remotePeer.getState() == CallState.ANSWERING || remotePeer.getState() == CallState.LOCAL_RINGING) { - webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState(remotePeer).isRemoteVideoOffer()); } return terminate(currentState, remotePeer); @@ -261,7 +261,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { webRtcInteractor.postStateUpdate(currentState); if (activePeer.getState() == CallState.ANSWERING || activePeer.getState() == CallState.LOCAL_RINGING) { - webRtcInteractor.insertMissedCall(activePeer, activePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertMissedCall(activePeer, activePeer.getCallStartTimestamp(), currentState.getCallSetupState(activePeer).isRemoteVideoOffer()); } return terminate(currentState, activePeer); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java index fb8476a5e5..71bdd09a3d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java @@ -71,11 +71,11 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor { return callFailure(currentState, "Enabling audio/video failed: ", e); } - if (currentState.getCallSetupState().isAcceptWithVideo()) { + if (currentState.getCallSetupState(activePeer).isAcceptWithVideo()) { currentState = currentState.getActionProcessor().handleSetEnableVideo(currentState, true); } - if (currentState.getCallSetupState().isAcceptWithVideo() || currentState.getLocalDeviceState().getCameraState().isEnabled()) { + if (currentState.getCallSetupState(activePeer).isAcceptWithVideo() || currentState.getLocalDeviceState().getCameraState().isEnabled()) { webRtcInteractor.setDefaultAudioDevice(SignalAudioManager.AudioDevice.SPEAKER_PHONE, false); } else { webRtcInteractor.setDefaultAudioDevice(SignalAudioManager.AudioDevice.EARPIECE, false); @@ -95,9 +95,6 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor { } currentState = currentState.builder() - .changeCallSetupState() - .enableVideoOnCreate(enable) - .commit() .changeLocalDeviceState() .cameraState(camera.getCameraState()) .build(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java index 7ea7fbb4e1..6714f6ec2e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java @@ -185,14 +185,14 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { @Override protected @NonNull WebRtcServiceState handleSetRingGroup(@NonNull WebRtcServiceState currentState, boolean ringGroup) { - Log.i(tag, "handleReceivedOpaqueMessage(): ring: " + ringGroup); + Log.i(tag, "handleSetRingGroup(): ring: " + ringGroup); - if (currentState.getCallSetupState().shouldRingGroup() == ringGroup) { + if (currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).shouldRingGroup() == ringGroup) { return currentState; } return currentState.builder() - .changeCallSetupState() + .changeCallSetupState(RemotePeer.GROUP_CALL_ID) .setRingGroup(ringGroup) .build(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java index 7be8a1bb41..2f17746470 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupConnectedActionProcessor.java @@ -14,6 +14,7 @@ import org.signal.ringrtc.PeekInfo; import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.ringrtc.Camera; +import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import java.util.ArrayList; @@ -114,7 +115,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor { return currentState; } - if (currentState.getCallSetupState().hasSentJoinedMessage()) { + if (currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).hasSentJoinedMessage()) { return currentState; } @@ -128,7 +129,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor { webRtcInteractor.updateGroupCallUpdateMessage(currentState.getCallInfoState().getCallRecipient().getId(), eraId, members, WebRtcUtil.isCallFull(peekInfo)); return currentState.builder() - .changeCallSetupState() + .changeCallSetupState(RemotePeer.GROUP_CALL_ID) .sentJoinedMessage(true) .build(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java index 2acb5b9eb9..7488a075ae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java @@ -10,6 +10,7 @@ import org.signal.ringrtc.CallException; import org.signal.ringrtc.GroupCall; import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.ringrtc.Camera; +import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder; import org.thoughtcrime.securesms.util.FeatureFlags; @@ -80,7 +81,7 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor { throw new RuntimeException(e); } - if (FeatureFlags.groupCallRinging() && currentState.getCallSetupState().shouldRingGroup()) { + if (FeatureFlags.groupCallRinging() && currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).shouldRingGroup()) { try { groupCall.ringAll(); } catch (CallException e) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java index 3c692f6ac6..4e2e50e7a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java @@ -62,6 +62,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { .changeCallInfoState() .groupCall(groupCall) .groupCallState(WebRtcViewModel.GroupCallState.DISCONNECTED) + .activePeer(new RemotePeer(currentState.getCallInfoState().getCallRecipient().getId(), RemotePeer.GROUP_CALL_ID)) .build(); } @@ -177,7 +178,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { currentState.getVideoState().requireCamera().setEnabled(enable); return currentState.builder() - .changeCallSetupState() + .changeCallSetupState(RemotePeer.GROUP_CALL_ID) .enableVideoOnCreate(enable) .commit() .changeLocalDeviceState() diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java index 52519db79a..7c05fbfc4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java @@ -93,10 +93,10 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor { Log.i(TAG, "handleAcceptCall(): call_id: " + activePeer.getCallId()); - DatabaseFactory.getSmsDatabase(context).insertReceivedCall(activePeer.getId(), currentState.getCallSetupState().isRemoteVideoOffer()); + DatabaseFactory.getSmsDatabase(context).insertReceivedCall(activePeer.getId(), currentState.getCallSetupState(activePeer).isRemoteVideoOffer()); currentState = currentState.builder() - .changeCallSetupState() + .changeCallSetupState(activePeer.getCallId()) .acceptWithVideo(answerWithVideo) .build(); @@ -121,7 +121,7 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor { try { webRtcInteractor.getCallManager().hangup(); - DatabaseFactory.getSmsDatabase(context).insertMissedCall(activePeer.getId(), System.currentTimeMillis(), currentState.getCallSetupState().isRemoteVideoOffer()); + DatabaseFactory.getSmsDatabase(context).insertMissedCall(activePeer.getId(), System.currentTimeMillis(), currentState.getCallSetupState(activePeer).isRemoteVideoOffer()); return terminate(currentState, activePeer); } catch (CallException e) { return callFailure(currentState, "hangup() failed: ", e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java index 132cc9be16..d783ad0a81 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingGroupCallActionProcessor.java @@ -54,7 +54,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro Log.i(TAG, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + ringId + " update: " + ringUpdate); Recipient recipient = remotePeerGroup.getRecipient(); - boolean updateForCurrentRingId = ringId == currentState.getCallSetupState().getRingId(); + boolean updateForCurrentRingId = ringId == currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId(); boolean isCurrentlyRinging = currentState.getCallInfoState().getGroupCallState().isRinging(); if (DatabaseFactory.getGroupCallRingDatabase(context).isCancelled(ringId)) { @@ -134,12 +134,13 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro webRtcInteractor.registerPowerButtonReceiver(); return currentState.builder() - .changeCallSetupState() + .changeCallSetupState(RemotePeer.GROUP_CALL_ID) .isRemoteVideoOffer(true) .ringId(ringId) .ringerRecipient(Recipient.externalPush(context, ACI.from(uuid), null, false)) .commit() .changeCallInfoState() + .activePeer(new RemotePeer(currentState.getCallInfoState().getCallRecipient().getId(), RemotePeer.GROUP_CALL_ID)) .callRecipient(remotePeerGroup.getRecipient()) .callState(WebRtcViewModel.State.CALL_INCOMING) .groupCallState(WebRtcViewModel.GroupCallState.RINGING) @@ -186,7 +187,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro .groupCall(groupCall) .groupCallState(WebRtcViewModel.GroupCallState.DISCONNECTED) .commit() - .changeCallSetupState() + .changeCallSetupState(RemotePeer.GROUP_CALL_ID) .isRemoteVideoOffer(false) .enableVideoOnCreate(answerWithVideo) .build(); @@ -220,7 +221,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro protected @NonNull WebRtcServiceState handleDenyCall(@NonNull WebRtcServiceState currentState) { Recipient recipient = currentState.getCallInfoState().getCallRecipient(); Optional groupId = recipient.getGroupId(); - long ringId = currentState.getCallSetupState().getRingId(); + long ringId = currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId(); DatabaseFactory.getGroupCallRingDatabase(context).insertOrUpdateGroupRing(ringId, System.currentTimeMillis(), @@ -242,7 +243,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro return WebRtcVideoUtil.deinitializeVideo(currentState) .builder() .actionProcessor(new IdleActionProcessor(webRtcInteractor)) - .terminate() + .terminate(RemotePeer.GROUP_CALL_ID) .build(); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java index 7f1a91e608..329a5942ad 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java @@ -17,7 +17,6 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientUtil; import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.WebRtcData.CallMetadata; -import org.thoughtcrime.securesms.service.webrtc.WebRtcData.OfferMetadata; import org.thoughtcrime.securesms.service.webrtc.state.VideoState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder; @@ -26,7 +25,6 @@ import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; import org.webrtc.PeerConnection; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; -import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; import java.util.List; import java.util.Objects; @@ -57,28 +55,33 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor { } @Override - protected @NonNull WebRtcServiceState handleStartOutgoingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { + protected @NonNull WebRtcServiceState handleStartOutgoingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer, @NonNull OfferMessage.Type offerType) { Log.i(TAG, "handleStartOutgoingCall():"); WebRtcServiceStateBuilder builder = currentState.builder(); remotePeer.dialing(); - Log.i(TAG, "assign activePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode()); + Log.i(TAG, "assign activePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode() + " type: " + offerType); + + boolean isVideoCall = offerType == OfferMessage.Type.VIDEO_CALL; webRtcInteractor.setCallInProgressNotification(TYPE_OUTGOING_RINGING, remotePeer); - webRtcInteractor.setDefaultAudioDevice(currentState.getCallSetupState().isEnableVideoOnCreate() ? SignalAudioManager.AudioDevice.SPEAKER_PHONE - : SignalAudioManager.AudioDevice.EARPIECE, + webRtcInteractor.setDefaultAudioDevice(isVideoCall ? SignalAudioManager.AudioDevice.SPEAKER_PHONE + : SignalAudioManager.AudioDevice.EARPIECE, false); webRtcInteractor.updatePhoneState(WebRtcUtil.getInCallPhoneState(context)); webRtcInteractor.initializeAudioForCall(); webRtcInteractor.startOutgoingRinger(); RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, Recipient.resolved(remotePeer.getId()), DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(remotePeer.getId())); - DatabaseFactory.getSmsDatabase(context).insertOutgoingCall(remotePeer.getId(), currentState.getCallSetupState().isEnableVideoOnCreate()); + DatabaseFactory.getSmsDatabase(context).insertOutgoingCall(remotePeer.getId(), isVideoCall); webRtcInteractor.retrieveTurnServers(remotePeer); - return builder.changeCallInfoState() + return builder.changeCallSetupState(remotePeer.getCallId()) + .enableVideoOnCreate(isVideoCall) + .commit() + .changeCallInfoState() .activePeer(remotePeer) .callState(WebRtcViewModel.State.CALL_OUTGOING) .commit() @@ -105,7 +108,7 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor { iceServers, isAlwaysTurn, NetworkUtil.getCallingBandwidthMode(context), - currentState.getCallSetupState().isEnableVideoOnCreate()); + currentState.getCallSetupState(activePeer).isEnableVideoOnCreate()); } catch (CallException e) { return callFailure(currentState, "Unable to proceed with call: ", e); } @@ -173,7 +176,7 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor { } @Override - protected @NonNull WebRtcServiceState handleRemoteVideoEnable(@NonNull WebRtcServiceState currentState, boolean enable) { + protected @NonNull WebRtcServiceState handleRemoteVideoEnable(@NonNull WebRtcServiceState currentState, boolean enable) { return activeCallDelegate.handleRemoteVideoEnable(currentState, enable); } @@ -203,7 +206,7 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor { } @Override - protected @NonNull WebRtcServiceState handleSetupFailure(@NonNull WebRtcServiceState currentState, @NonNull CallId callId) { + protected @NonNull WebRtcServiceState handleSetupFailure(@NonNull WebRtcServiceState currentState, @NonNull CallId callId) { return activeCallDelegate.handleSetupFailure(currentState, callId); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/PreJoinActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/PreJoinActionProcessor.java index 413d38fe99..fbe8880f08 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/PreJoinActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/PreJoinActionProcessor.java @@ -62,9 +62,6 @@ public class PreJoinActionProcessor extends DeviceAwareActionProcessor { currentState.getVideoState().getCamera().setEnabled(enable); return currentState.builder() - .changeCallSetupState() - .enableVideoOnCreate(enable) - .commit() .changeLocalDeviceState() .cameraState(currentState.getVideoState().getCamera().getCameraState()) .build(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 6b7fa50cac..fb8dd8948e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -142,6 +142,9 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. } private void process(@NonNull ProcessAction action) { + Throwable t = new Throwable(); + String caller = t.getStackTrace().length > 1 ? t.getStackTrace()[1].getMethodName() : "unknown"; + if (callManager == null) { Log.w(TAG, "Unable to process action, call manager is not initialized"); return; @@ -157,7 +160,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. } } - Log.v(TAG, "Processing action, handler: " + serviceState.getActionProcessor().getTag()); + Log.v(TAG, "Processing action: " + caller + ", handler: " + serviceState.getActionProcessor().getTag()); WebRtcServiceState previous = serviceState; serviceState = action.process(previous, previous.getActionProcessor()); @@ -395,7 +398,7 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. remotePeer.setCallId(callId); if (isOutgoing) { - return p.handleStartOutgoingCall(s, remotePeer); + return p.handleStartOutgoingCall(s, remotePeer, WebRtcUtil.getOfferTypeFromCallMediaType(callMediaType)); } else { return p.handleStartIncomingCall(s, remotePeer); } @@ -503,16 +506,15 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. @NonNull byte[] opaque, @NonNull CallManager.CallMediaType callMediaType) { - Log.i(TAG, "onSendOffer: id: " + callId.format(remoteDevice) + " type: " + callMediaType.name()); - if (!(remote instanceof RemotePeer)) { return; } + RemotePeer remotePeer = (RemotePeer) remote; - RemotePeer remotePeer = (RemotePeer) remote; - OfferMessage.Type offerType = WebRtcUtil.getOfferTypeFromCallMediaType(callMediaType); + Log.i(TAG, "onSendOffer: id: " + remotePeer.getCallId().format(remoteDevice) + " type: " + callMediaType.name()); - WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, callId, remoteDevice); + OfferMessage.Type offerType = WebRtcUtil.getOfferTypeFromCallMediaType(callMediaType); + WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, remoteDevice); WebRtcData.OfferMetadata offerMetadata = new WebRtcData.OfferMetadata(opaque, null, offerType); process((s, p) -> p.handleSendOffer(s, callMetadata, offerMetadata, broadcast)); @@ -525,14 +527,15 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. @NonNull Boolean broadcast, @NonNull byte[] opaque) { - Log.i(TAG, "onSendAnswer: id: " + callId.format(remoteDevice)); - if (!(remote instanceof RemotePeer)) { return; } - RemotePeer remotePeer = (RemotePeer) remote; - WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, callId, remoteDevice); + RemotePeer remotePeer = (RemotePeer) remote; + + Log.i(TAG, "onSendAnswer: id: " + remotePeer.getCallId().format(remoteDevice)); + + WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, remoteDevice); WebRtcData.AnswerMetadata answerMetadata = new WebRtcData.AnswerMetadata(opaque, null); process((s, p) -> p.handleSendAnswer(s, callMetadata, answerMetadata, broadcast)); @@ -545,28 +548,30 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. @NonNull Boolean broadcast, @NonNull List iceCandidates) { - Log.i(TAG, "onSendIceCandidates: id: " + callId.format(remoteDevice)); - if (!(remote instanceof RemotePeer)) { return; } - RemotePeer remotePeer = (RemotePeer) remote; - WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, callId, remoteDevice); + RemotePeer remotePeer = (RemotePeer) remote; + + Log.i(TAG, "onSendIceCandidates: id: " + remotePeer.getCallId().format(remoteDevice)); + + WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, remoteDevice); process((s, p) -> p.handleSendIceCandidates(s, callMetadata, broadcast, iceCandidates)); } @Override public void onSendHangup(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @NonNull CallManager.HangupType hangupType, @NonNull Integer deviceId, @NonNull Boolean useLegacyHangupMessage) { - Log.i(TAG, "onSendHangup: id: " + callId.format(remoteDevice) + " type: " + hangupType.name() + " isLegacy: " + useLegacyHangupMessage); - if (!(remote instanceof RemotePeer)) { return; } - RemotePeer remotePeer = (RemotePeer) remote; - WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, callId, remoteDevice); + RemotePeer remotePeer = (RemotePeer) remote; + + Log.i(TAG, "onSendHangup: id: " + remotePeer.getCallId().format(remoteDevice) + " type: " + hangupType.name() + " isLegacy: " + useLegacyHangupMessage); + + WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, remoteDevice); WebRtcData.HangupMetadata hangupMetadata = new WebRtcData.HangupMetadata(WebRtcUtil.getHangupTypeFromCallHangupType(hangupType), useLegacyHangupMessage, deviceId); process((s, p) -> p.handleSendHangup(s, callMetadata, hangupMetadata, broadcast)); @@ -574,14 +579,15 @@ public final class SignalCallManager implements CallManager.Observer, GroupCall. @Override public void onSendBusy(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast) { - Log.i(TAG, "onSendBusy: id: " + callId.format(remoteDevice)); - if (!(remote instanceof RemotePeer)) { return; } - RemotePeer remotePeer = (RemotePeer) remote; - WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, callId, remoteDevice); + RemotePeer remotePeer = (RemotePeer) remote; + + Log.i(TAG, "onSendBusy: id: " + remotePeer.getCallId().format(remoteDevice)); + + WebRtcData.CallMetadata callMetadata = new WebRtcData.CallMetadata(remotePeer, remoteDevice); process((s, p) -> p.handleSendBusy(s, callMetadata, broadcast)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java index 69f15c1704..964e24c40b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java @@ -116,7 +116,7 @@ public abstract class WebRtcActionProcessor { return currentState; } - protected @NonNull WebRtcServiceState handleStartOutgoingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { + protected @NonNull WebRtcServiceState handleStartOutgoingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer, @NonNull OfferMessage.Type offerType) { Log.i(tag, "handleStartOutgoingCall not processed"); return currentState; } @@ -163,7 +163,7 @@ public abstract class WebRtcActionProcessor { @NonNull OfferMetadata offerMetadata, @NonNull ReceivedOfferMetadata receivedOfferMetadata) { - Log.i(tag, "handleReceivedOffer(): id: " + callMetadata.getCallId().format(callMetadata.getRemoteDevice())); + Log.i(tag, "handleReceivedOffer(): id: " + callMetadata.getCallId().format(callMetadata.getRemoteDevice()) + " offer_type:" + offerMetadata.getOfferType()); if (TelephonyUtil.isAnyPstnLineBusy(context)) { Log.i(tag, "PSTN line is busy."); @@ -191,7 +191,7 @@ public abstract class WebRtcActionProcessor { callMetadata.getRemotePeer().setCallStartTimestamp(receivedOfferMetadata.getServerReceivedTimestamp()); currentState = currentState.builder() - .changeCallSetupState() + .changeCallSetupState(callMetadata.getCallId()) .isRemoteVideoOffer(offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL) .commit() .changeCallInfoState() @@ -228,7 +228,7 @@ public abstract class WebRtcActionProcessor { { Log.i(tag, "handleReceivedOfferExpired(): call_id: " + remotePeer.getCallId()); - webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState().isRemoteVideoOffer()); + webRtcInteractor.insertMissedCall(remotePeer, remotePeer.getCallStartTimestamp(), currentState.getCallSetupState(remotePeer).isRemoteVideoOffer()); return terminate(currentState, remotePeer); } @@ -597,7 +597,7 @@ public abstract class WebRtcActionProcessor { .changeLocalDeviceState() .commit() .actionProcessor(currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_DISCONNECTED ? new DisconnectingCallActionProcessor(webRtcInteractor) : new IdleActionProcessor(webRtcInteractor)) - .terminate() + .terminate(remotePeer.getCallId()) .build(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java index e67a2383d6..508fb5e2e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcData.java @@ -21,12 +21,10 @@ public class WebRtcData { */ public static class CallMetadata { private final @NonNull RemotePeer remotePeer; - private final @NonNull CallId callId; private final int remoteDevice; - public CallMetadata(@NonNull RemotePeer remotePeer, @NonNull CallId callId, int remoteDevice) { + public CallMetadata(@NonNull RemotePeer remotePeer, int remoteDevice) { this.remotePeer = remotePeer; - this.callId = callId; this.remoteDevice = remoteDevice; } @@ -35,7 +33,7 @@ public class WebRtcData { } @NonNull CallId getCallId() { - return callId; + return remotePeer.getCallId(); } int getRemoteDevice() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java index 626fab10fd..0125c8ffbd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java @@ -46,7 +46,7 @@ public final class WebRtcUtil { return offerType == OfferMessage.Type.VIDEO_CALL ? CallManager.CallMediaType.VIDEO_CALL : CallManager.CallMediaType.AUDIO_CALL; } - public static @NonNull OfferMessage.Type getOfferTypeFromCallMediaType(@NonNull CallManager.CallMediaType callMediaType) { + public static @NonNull OfferMessage.Type getOfferTypeFromCallMediaType(@Nullable CallManager.CallMediaType callMediaType) { return callMediaType == CallManager.CallMediaType.VIDEO_CALL ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceState.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceState.java index 71950c69d6..ebacc5c574 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceState.java @@ -1,23 +1,29 @@ package org.thoughtcrime.securesms.service.webrtc.state; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import org.signal.ringrtc.CallId; +import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.WebRtcActionProcessor; +import java.util.HashMap; +import java.util.Map; + /** * Represent the entire state of the call system. */ public final class WebRtcServiceState { - WebRtcActionProcessor actionProcessor; - CallSetupState callSetupState; - CallInfoState callInfoState; - LocalDeviceState localDeviceState; - VideoState videoState; + WebRtcActionProcessor actionProcessor; + Map callSetupStates; + CallInfoState callInfoState; + LocalDeviceState localDeviceState; + VideoState videoState; public WebRtcServiceState(@NonNull WebRtcActionProcessor actionProcessor) { this.actionProcessor = actionProcessor; - this.callSetupState = new CallSetupState(); + this.callSetupStates = new HashMap<>(); this.callInfoState = new CallInfoState(); this.localDeviceState = new LocalDeviceState(); this.videoState = new VideoState(); @@ -25,18 +31,36 @@ public final class WebRtcServiceState { public WebRtcServiceState(@NonNull WebRtcServiceState toCopy) { this.actionProcessor = toCopy.actionProcessor; - this.callSetupState = toCopy.callSetupState.duplicate(); this.callInfoState = new CallInfoState(toCopy.callInfoState); this.localDeviceState = toCopy.localDeviceState.duplicate(); this.videoState = new VideoState(toCopy.videoState); + this.callSetupStates = new HashMap<>(); + + for (Map.Entry entry : toCopy.callSetupStates.entrySet()) { + this.callSetupStates.put(entry.getKey(), entry.getValue().duplicate()); + } } public @NonNull WebRtcActionProcessor getActionProcessor() { return actionProcessor; } - public @NonNull CallSetupState getCallSetupState() { - return callSetupState; + + public @NonNull CallSetupState getCallSetupState(@NonNull RemotePeer remotePeer) { + return getCallSetupState(remotePeer.getCallId()); + } + + public @NonNull CallSetupState getCallSetupState(@Nullable CallId callId) { + if (callId == null) { + return new CallSetupState(); + } + + if (!callSetupStates.containsKey(callId)) { + callSetupStates.put(callId, new CallSetupState()); + } + + //noinspection ConstantConditions + return callSetupStates.get(callId); } public @NonNull CallInfoState getCallInfoState() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java index 698da76840..5c2945b389 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java @@ -5,6 +5,7 @@ import androidx.annotation.Nullable; import com.annimon.stream.OptionalLong; +import org.signal.ringrtc.CallId; import org.signal.ringrtc.GroupCall; import org.thoughtcrime.securesms.components.sensors.Orientation; import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; @@ -43,8 +44,8 @@ public class WebRtcServiceStateBuilder { return this; } - public @NonNull CallSetupStateBuilder changeCallSetupState() { - return new CallSetupStateBuilder(); + public @NonNull CallSetupStateBuilder changeCallSetupState(@NonNull CallId callId) { + return new CallSetupStateBuilder(callId); } public @NonNull CallInfoStateBuilder changeCallInfoState() { @@ -59,8 +60,7 @@ public class WebRtcServiceStateBuilder { return new VideoStateBuilder(); } - public @NonNull WebRtcServiceStateBuilder terminate() { - toBuild.callSetupState = new CallSetupState(); + public @NonNull WebRtcServiceStateBuilder terminate(@NonNull CallId callId) { toBuild.localDeviceState = new LocalDeviceState(); toBuild.videoState = new VideoState(); @@ -68,6 +68,8 @@ public class WebRtcServiceStateBuilder { newCallInfoState.peerMap.putAll(toBuild.callInfoState.peerMap); toBuild.callInfoState = newCallInfoState; + toBuild.callSetupStates.remove(callId); + return this; } @@ -126,13 +128,15 @@ public class WebRtcServiceStateBuilder { public class CallSetupStateBuilder { private CallSetupState toBuild; + private CallId callId; - public CallSetupStateBuilder() { - toBuild = WebRtcServiceStateBuilder.this.toBuild.callSetupState.duplicate(); + public CallSetupStateBuilder(@NonNull CallId callId) { + this.toBuild = WebRtcServiceStateBuilder.this.toBuild.getCallSetupState(callId).duplicate(); + this.callId = callId; } public @NonNull WebRtcServiceStateBuilder commit() { - WebRtcServiceStateBuilder.this.toBuild.callSetupState = toBuild; + WebRtcServiceStateBuilder.this.toBuild.callSetupStates.put(callId, toBuild); return WebRtcServiceStateBuilder.this; }