Fix call setup state management bugs.

This commit is contained in:
Cody Henthorne
2021-11-10 10:38:15 -05:00
parent c0a468e42b
commit 8a05626791
19 changed files with 144 additions and 103 deletions

View File

@@ -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<CallParticipant> = state.callInfoState.remoteCallParticipants
val identityChangedParticipants: Set<RecipientId> = 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<SignalAudioManager.AudioDevice> = state.localDeviceState.availableDevices
@@ -123,6 +123,7 @@ class WebRtcViewModel(state: WebRtcServiceState) {
participantLimit=$participantLimit,
activeDevice=$activeDevice,
availableDevices=$availableDevices,
ringGroup=$ringGroup
}
""".trimIndent()
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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();
}

View File

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

View File

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

View File

@@ -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);

View File

@@ -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> 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();
}
}

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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<byte[]> 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));
}

View File

@@ -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();
}

View File

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

View File

@@ -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;
}

View File

@@ -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<CallId, CallSetupState> 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<CallId, CallSetupState> 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() {

View File

@@ -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;
}