Search in sources :

Example 56 with CallException

use of org.signal.ringrtc.CallException in project Signal-Android by signalapp.

the class IncomingGroupCallActionProcessor method handleGroupCallRingUpdate.

@Override
@NonNull
protected WebRtcServiceState handleGroupCallRingUpdate(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeerGroup, @NonNull GroupId.V2 groupId, long ringId, @NonNull UUID uuid, @NonNull CallManager.RingUpdate ringUpdate) {
    Log.i(TAG, "handleGroupCallRingUpdate(): recipient: " + remotePeerGroup.getId() + " ring: " + ringId + " update: " + ringUpdate);
    Recipient recipient = remotePeerGroup.getRecipient();
    boolean updateForCurrentRingId = ringId == currentState.getCallSetupState(RemotePeer.GROUP_CALL_ID).getRingId();
    boolean isCurrentlyRinging = currentState.getCallInfoState().getGroupCallState().isRinging();
    if (SignalDatabase.groupCallRings().isCancelled(ringId)) {
        try {
            Log.i(TAG, "Ignoring incoming ring request for already cancelled ring: " + ringId);
            webRtcInteractor.getCallManager().cancelGroupRing(groupId.getDecodedId(), ringId, null);
        } catch (CallException e) {
            Log.w(TAG, "Error while trying to cancel ring: " + ringId, e);
        }
        return currentState;
    }
    if (ringUpdate != CallManager.RingUpdate.REQUESTED) {
        SignalDatabase.groupCallRings().insertOrUpdateGroupRing(ringId, System.currentTimeMillis(), ringUpdate);
        if (updateForCurrentRingId && isCurrentlyRinging) {
            Log.i(TAG, "Cancelling current ring: " + ringId);
            currentState = currentState.builder().changeCallInfoState().callState(WebRtcViewModel.State.CALL_DISCONNECTED).build();
            webRtcInteractor.postStateUpdate(currentState);
            return terminateGroupCall(currentState);
        } else {
            return currentState;
        }
    }
    if (!updateForCurrentRingId && isCurrentlyRinging) {
        try {
            Log.i(TAG, "Already ringing so reply busy for new ring: " + ringId);
            webRtcInteractor.getCallManager().cancelGroupRing(groupId.getDecodedId(), ringId, CallManager.RingCancelReason.Busy);
        } catch (CallException e) {
            Log.w(TAG, "Error while trying to cancel ring: " + ringId, e);
        }
        return currentState;
    }
    if (updateForCurrentRingId) {
        Log.i(TAG, "Already ringing for ring: " + ringId);
        return currentState;
    }
    Log.i(TAG, "Requesting new ring: " + ringId);
    SignalDatabase.groupCallRings().insertGroupRing(ringId, System.currentTimeMillis(), ringUpdate);
    currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState, RemotePeer.GROUP_CALL_ID.longValue());
    webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_RINGING, remotePeerGroup);
    webRtcInteractor.updatePhoneState(LockManager.PhoneState.INTERACTIVE);
    webRtcInteractor.initializeAudioForCall();
    boolean shouldDisturbUserWithCall = DoNotDisturbUtil.shouldDisturbUserWithCall(context.getApplicationContext());
    if (shouldDisturbUserWithCall) {
        boolean started = webRtcInteractor.startWebRtcCallActivityIfPossible();
        if (!started) {
            Log.i(TAG, "Unable to start call activity due to OS version or not being in the foreground");
            ApplicationDependencies.getAppForegroundObserver().addListener(webRtcInteractor.getForegroundListener());
        }
    }
    if (shouldDisturbUserWithCall && SignalStore.settings().isCallNotificationsEnabled()) {
        Uri ringtone = recipient.resolve().getCallRingtone();
        RecipientDatabase.VibrateState vibrateState = recipient.resolve().getCallVibrate();
        if (ringtone == null) {
            ringtone = SignalStore.settings().getCallRingtone();
        }
        webRtcInteractor.startIncomingRinger(ringtone, vibrateState == RecipientDatabase.VibrateState.ENABLED || (vibrateState == RecipientDatabase.VibrateState.DEFAULT && SignalStore.settings().isCallVibrateEnabled()));
    }
    webRtcInteractor.registerPowerButtonReceiver();
    return currentState.builder().changeCallSetupState(RemotePeer.GROUP_CALL_ID).isRemoteVideoOffer(true).ringId(ringId).ringerRecipient(Recipient.externalPush(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).putParticipant(remotePeerGroup.getRecipient(), CallParticipant.createRemote(new CallParticipantId(remotePeerGroup.getRecipient()), remotePeerGroup.getRecipient(), null, new BroadcastVideoSink(currentState.getVideoState().getLockableEglBase(), false, true, currentState.getLocalDeviceState().getOrientation().getDegrees()), true, false, 0, true, 0, false, CallParticipant.DeviceOrdinal.PRIMARY)).build();
}
Also used : RecipientDatabase(org.thoughtcrime.securesms.database.RecipientDatabase) CallException(org.signal.ringrtc.CallException) BroadcastVideoSink(org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) Recipient(org.thoughtcrime.securesms.recipients.Recipient) CallParticipantId(org.thoughtcrime.securesms.events.CallParticipantId) Uri(android.net.Uri) NonNull(androidx.annotation.NonNull)

Example 57 with CallException

use of org.signal.ringrtc.CallException in project Signal-Android by signalapp.

the class WebRtcActionProcessor method handleMessageSentError.

@NonNull
protected WebRtcServiceState handleMessageSentError(@NonNull WebRtcServiceState currentState, @NonNull CallId callId, @NonNull WebRtcViewModel.State errorCallState, @NonNull Optional<IdentityKey> identityKey) {
    Log.w(tag, "handleMessageSentError():");
    try {
        webRtcInteractor.getCallManager().messageSendFailure(callId);
    } catch (CallException e) {
        currentState = callFailure(currentState, "callManager.messageSendFailure() failed: ", e);
    }
    RemotePeer activePeer = currentState.getCallInfoState().getActivePeer();
    if (activePeer == null) {
        return currentState;
    }
    WebRtcServiceStateBuilder builder = currentState.builder();
    if (errorCallState == WebRtcViewModel.State.UNTRUSTED_IDENTITY) {
        CallParticipant participant = Objects.requireNonNull(currentState.getCallInfoState().getRemoteCallParticipant(activePeer.getRecipient()));
        CallParticipant untrusted = participant.withIdentityKey(identityKey.orNull());
        builder.changeCallInfoState().callState(WebRtcViewModel.State.UNTRUSTED_IDENTITY).putParticipant(activePeer.getRecipient(), untrusted).commit();
    } else {
        builder.changeCallInfoState().callState(errorCallState).commit();
    }
    return builder.build();
}
Also used : CallException(org.signal.ringrtc.CallException) CallParticipant(org.thoughtcrime.securesms.events.CallParticipant) WebRtcServiceStateBuilder(org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) NonNull(androidx.annotation.NonNull)

Example 58 with CallException

use of org.signal.ringrtc.CallException in project Signal-Android by signalapp.

the class WebRtcActionProcessor method handleReceivedOffer.

// endregion Outgoing call
// region Incoming call
@NonNull
protected WebRtcServiceState handleReceivedOffer(@NonNull WebRtcServiceState currentState, @NonNull CallMetadata callMetadata, @NonNull OfferMetadata offerMetadata, @NonNull ReceivedOfferMetadata receivedOfferMetadata) {
    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.");
        currentState = currentState.getActionProcessor().handleSendBusy(currentState, callMetadata, true);
        webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
        return currentState;
    }
    if (!RecipientUtil.isCallRequestAccepted(context.getApplicationContext(), callMetadata.getRemotePeer().getRecipient())) {
        Log.w(tag, "Caller is untrusted.");
        currentState = currentState.getActionProcessor().handleSendHangup(currentState, callMetadata, WebRtcData.HangupMetadata.fromType(HangupMessage.Type.NEED_PERMISSION), true);
        webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
        return currentState;
    }
    if (offerMetadata.getOpaque() == null) {
        Log.w(tag, "Opaque data is required.");
        currentState = currentState.getActionProcessor().handleSendHangup(currentState, callMetadata, WebRtcData.HangupMetadata.fromType(HangupMessage.Type.NORMAL), true);
        webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
        return currentState;
    }
    NotificationProfile activeProfile = NotificationProfiles.getActiveProfile(SignalDatabase.notificationProfiles().getProfiles());
    if (activeProfile != null && !(activeProfile.isRecipientAllowed(callMetadata.getRemotePeer().getId()) || activeProfile.getAllowAllCalls())) {
        Log.w(tag, "Caller is excluded by notification profile.");
        currentState = currentState.getActionProcessor().handleSendHangup(currentState, callMetadata, WebRtcData.HangupMetadata.fromType(HangupMessage.Type.NORMAL), true);
        webRtcInteractor.insertMissedCall(callMetadata.getRemotePeer(), receivedOfferMetadata.getServerReceivedTimestamp(), offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL);
        return currentState;
    }
    Log.i(tag, "add remotePeer callId: " + callMetadata.getRemotePeer().getCallId() + " key: " + callMetadata.getRemotePeer().hashCode());
    callMetadata.getRemotePeer().setCallStartTimestamp(receivedOfferMetadata.getServerReceivedTimestamp());
    currentState = currentState.builder().changeCallSetupState(callMetadata.getCallId()).isRemoteVideoOffer(offerMetadata.getOfferType() == OfferMessage.Type.VIDEO_CALL).commit().changeCallInfoState().putRemotePeer(callMetadata.getRemotePeer()).build();
    long messageAgeSec = Math.max(receivedOfferMetadata.getServerDeliveredTimestamp() - receivedOfferMetadata.getServerReceivedTimestamp(), 0) / 1000;
    Log.i(tag, "messageAgeSec: " + messageAgeSec + ", serverReceivedTimestamp: " + receivedOfferMetadata.getServerReceivedTimestamp() + ", serverDeliveredTimestamp: " + receivedOfferMetadata.getServerDeliveredTimestamp());
    try {
        byte[] remoteIdentityKey = WebRtcUtil.getPublicKeyBytes(receivedOfferMetadata.getRemoteIdentityKey());
        byte[] localIdentityKey = WebRtcUtil.getPublicKeyBytes(SignalStore.account().getAciIdentityKey().getPublicKey().serialize());
        webRtcInteractor.getCallManager().receivedOffer(callMetadata.getCallId(), callMetadata.getRemotePeer(), callMetadata.getRemoteDevice(), offerMetadata.getOpaque(), messageAgeSec, WebRtcUtil.getCallMediaTypeFromOfferType(offerMetadata.getOfferType()), SignalStore.account().getDeviceId(), SignalStore.account().isPrimaryDevice(), remoteIdentityKey, localIdentityKey);
    } catch (CallException | InvalidKeyException e) {
        return callFailure(currentState, "Unable to process received offer: ", e);
    }
    return currentState;
}
Also used : CallException(org.signal.ringrtc.CallException) NotificationProfile(org.thoughtcrime.securesms.notifications.profiles.NotificationProfile) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) NonNull(androidx.annotation.NonNull)

Example 59 with CallException

use of org.signal.ringrtc.CallException in project Signal-Android by signalapp.

the class ActiveCallActionProcessorDelegate method handleLocalHangup.

@Override
@NonNull
protected WebRtcServiceState handleLocalHangup(@NonNull WebRtcServiceState currentState) {
    RemotePeer remotePeer = currentState.getCallInfoState().getActivePeer();
    if (remotePeer == null) {
        Log.i(tag, "handleLocalHangup(): no active peer");
    } else {
        Log.i(tag, "handleLocalHangup(): call_id: " + remotePeer.getCallId());
    }
    ApplicationDependencies.getSignalServiceAccountManager().cancelInFlightRequests();
    ApplicationDependencies.getSignalServiceMessageSender().cancelInFlightRequests();
    try {
        webRtcInteractor.getCallManager().hangup();
        currentState = currentState.builder().changeCallInfoState().callState(WebRtcViewModel.State.CALL_DISCONNECTED).build();
        webRtcInteractor.postStateUpdate(currentState);
        return terminate(currentState, remotePeer);
    } catch (CallException e) {
        return callFailure(currentState, "hangup() failed: ", e);
    }
}
Also used : CallException(org.signal.ringrtc.CallException) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) NonNull(androidx.annotation.NonNull)

Example 60 with CallException

use of org.signal.ringrtc.CallException in project Signal-Android by signalapp.

the class ActiveCallActionProcessorDelegate method handleSetupFailure.

@Override
@NonNull
protected WebRtcServiceState handleSetupFailure(@NonNull WebRtcServiceState currentState, @NonNull CallId callId) {
    Log.i(tag, "handleSetupFailure(): call_id: " + callId);
    RemotePeer activePeer = currentState.getCallInfoState().getActivePeer();
    if (activePeer != null && activePeer.getCallId().equals(callId)) {
        try {
            if (activePeer.getState() == CallState.DIALING || activePeer.getState() == CallState.REMOTE_RINGING) {
                webRtcInteractor.getCallManager().hangup();
            } else {
                webRtcInteractor.getCallManager().drop(callId);
            }
        } catch (CallException e) {
            return callFailure(currentState, "Unable to drop call due to setup failure", e);
        }
        currentState = currentState.builder().changeCallInfoState().callState(WebRtcViewModel.State.NETWORK_FAILURE).build();
        webRtcInteractor.postStateUpdate(currentState);
        if (activePeer.getState() == CallState.ANSWERING || activePeer.getState() == CallState.LOCAL_RINGING) {
            webRtcInteractor.insertMissedCall(activePeer, activePeer.getCallStartTimestamp(), currentState.getCallSetupState(activePeer).isRemoteVideoOffer());
        }
        return terminate(currentState, activePeer);
    }
    return currentState;
}
Also used : CallException(org.signal.ringrtc.CallException) RemotePeer(org.thoughtcrime.securesms.ringrtc.RemotePeer) NonNull(androidx.annotation.NonNull)

Aggregations

CallException (org.signal.ringrtc.CallException)70 NonNull (androidx.annotation.NonNull)62 RemotePeer (org.thoughtcrime.securesms.ringrtc.RemotePeer)36 GroupCall (org.signal.ringrtc.GroupCall)34 Recipient (org.thoughtcrime.securesms.recipients.Recipient)16 WebRtcServiceState (org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState)12 CallParticipant (org.thoughtcrime.securesms.events.CallParticipant)10 Stream (com.annimon.stream.Stream)8 List (java.util.List)8 Log (org.signal.core.util.logging.Log)8 WebRtcViewModel (org.thoughtcrime.securesms.events.WebRtcViewModel)8 VideoState (org.thoughtcrime.securesms.service.webrtc.state.VideoState)8 ResultReceiver (android.os.ResultReceiver)6 Nullable (androidx.annotation.Nullable)6 Collection (java.util.Collection)6 Collections (java.util.Collections)6 Set (java.util.Set)6 UUID (java.util.UUID)6 CallManager (org.signal.ringrtc.CallManager)6 GroupManager (org.thoughtcrime.securesms.groups.GroupManager)6