Integrate RingRTC v2.0.1

master
Alex Hart 2020-05-08 14:39:32 -03:00
parent ee9270845a
commit 26e582d806
13 changed files with 493 additions and 214 deletions

View File

@ -302,7 +302,7 @@ dependencies {
implementation 'org.signal:argon2:13.1@aar'
implementation 'org.signal:ringrtc-android:1.3.2'
implementation 'org.signal:ringrtc-android:2.0.1'
implementation "me.leolin:ShortcutBadger:1.1.16"
implementation 'se.emilsjolander:stickylistheaders:2.7.0'

View File

@ -35,6 +35,7 @@ import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatTextView;
@ -63,6 +64,7 @@ import org.thoughtcrime.securesms.util.ViewUtil;
import org.webrtc.SurfaceViewRenderer;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
@ -379,11 +381,12 @@ public class WebRtcCallActivity extends AppCompatActivity {
callScreen.setStatus(getString(R.string.WebRtcCallActivity__calling));
}
private void handleTerminate(@NonNull Recipient recipient, @NonNull SurfaceViewRenderer localRenderer /*, int terminationType */) {
Log.i(TAG, "handleTerminate called");
private void handleTerminate(@NonNull Recipient recipient, @NonNull HangupMessage.Type hangupType) {
Log.i(TAG, "handleTerminate called: " + hangupType.name());
callScreen.setRecipient(recipient);
callScreen.setStatus(getString(R.string.RedPhone_ending_call));
callScreen.setStatusFromHangupType(hangupType);
EventBus.getDefault().removeStickyEvent(WebRtcViewModel.class);
delayedFinish();
@ -431,13 +434,13 @@ public class WebRtcCallActivity extends AppCompatActivity {
dialog.setPositiveButton(R.string.RedPhone_got_it, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
WebRtcCallActivity.this.handleTerminate(event.getRecipient(), event.getLocalRenderer());
WebRtcCallActivity.this.handleTerminate(event.getRecipient(), HangupMessage.Type.NORMAL);
}
});
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
WebRtcCallActivity.this.handleTerminate(event.getRecipient(), event.getLocalRenderer());
WebRtcCallActivity.this.handleTerminate(event.getRecipient(), HangupMessage.Type.NORMAL);
}
});
dialog.show();
@ -448,7 +451,7 @@ public class WebRtcCallActivity extends AppCompatActivity {
final Recipient recipient = event.getRecipient();
if (theirKey == null) {
handleTerminate(recipient, event.getLocalRenderer());
handleTerminate(recipient, HangupMessage.Type.NORMAL);
}
String name = recipient.getDisplayName(this);
@ -479,7 +482,7 @@ public class WebRtcCallActivity extends AppCompatActivity {
})
.setNegativeButton(R.string.WebRtcCallScreen_end_call, (d, w) -> {
d.dismiss();
handleTerminate(recipient, event.getLocalRenderer());
handleTerminate(recipient, HangupMessage.Type.NORMAL);
})
.show();
}
@ -505,16 +508,19 @@ public class WebRtcCallActivity extends AppCompatActivity {
viewModel.setRecipient(event.getRecipient());
switch (event.getState()) {
case CALL_CONNECTED: handleCallConnected(event); break;
case NETWORK_FAILURE: handleServerFailure(event); break;
case CALL_RINGING: handleCallRinging(event); break;
case CALL_DISCONNECTED: handleTerminate(event.getRecipient(), event.getLocalRenderer()); break;
case NO_SUCH_USER: handleNoSuchUser(event); break;
case RECIPIENT_UNAVAILABLE: handleRecipientUnavailable(event); break;
case CALL_INCOMING: handleIncomingCall(event); break;
case CALL_OUTGOING: handleOutgoingCall(event); break;
case CALL_BUSY: handleCallBusy(event); break;
case UNTRUSTED_IDENTITY: handleUntrustedIdentity(event); break;
case CALL_CONNECTED: handleCallConnected(event); break;
case NETWORK_FAILURE: handleServerFailure(event); break;
case CALL_RINGING: handleCallRinging(event); break;
case CALL_DISCONNECTED: handleTerminate(event.getRecipient(), HangupMessage.Type.NORMAL); break;
case CALL_ACCEPTED_ELSEWHERE: handleTerminate(event.getRecipient(), HangupMessage.Type.ACCEPTED); break;
case CALL_DECLINED_ELSEWHERE: handleTerminate(event.getRecipient(), HangupMessage.Type.DECLINED); break;
case CALL_ONGOING_ELSEWHERE: handleTerminate(event.getRecipient(), HangupMessage.Type.BUSY); break;
case NO_SUCH_USER: handleNoSuchUser(event); break;
case RECIPIENT_UNAVAILABLE: handleRecipientUnavailable(event); break;
case CALL_INCOMING: handleIncomingCall(event); break;
case CALL_OUTGOING: handleOutgoingCall(event); break;
case CALL_BUSY: handleCallBusy(event); break;
case UNTRUSTED_IDENTITY: handleUntrustedIdentity(event); break;
}
callScreen.setLocalRenderer(event.getLocalRenderer());

View File

@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.util.AvatarUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.webrtc.RendererCommon;
import org.webrtc.SurfaceViewRenderer;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
public class WebRtcCallView extends FrameLayout {
@ -290,6 +291,25 @@ public class WebRtcCallView extends FrameLayout {
this.status.setText(status);
}
public void setStatusFromHangupType(@NonNull HangupMessage.Type hangupType) {
switch (hangupType) {
case NORMAL:
status.setText(R.string.RedPhone_ending_call);
break;
case ACCEPTED:
status.setText(R.string.WebRtcCallActivity__answered_on_a_linked_device);
break;
case DECLINED:
status.setText(R.string.WebRtcCallActivity__declined_on_a_linked_device);
break;
case BUSY:
status.setText(R.string.WebRtcCallActivity__busy_on_a_linked_device);
break;
default:
throw new IllegalStateException("Unknown hangup type: " + hangupType);
}
}
public void setWebRtcControls(WebRtcControls webRtcControls) {
answerWithVoiceGroup.setVisibility(View.GONE);

View File

@ -24,6 +24,11 @@ public class WebRtcViewModel {
RECIPIENT_UNAVAILABLE,
NO_SUCH_USER,
UNTRUSTED_IDENTITY,
// Multiring Hangup States
CALL_ACCEPTED_ELSEWHERE,
CALL_DECLINED_ELSEWHERE,
CALL_ONGOING_ELSEWHERE
}

View File

@ -350,7 +350,14 @@ public final class PushProcessMessageJob extends BaseJob {
else Log.w(TAG, "Contains no known sync types...");
} else if (content.getCallMessage().isPresent()) {
Log.i(TAG, "Got call message...");
SignalServiceCallMessage message = content.getCallMessage().get();
SignalServiceCallMessage message = content.getCallMessage().get();
Optional<Integer> destinationDeviceId = message.getDestinationDeviceId();
if (destinationDeviceId.isPresent() && destinationDeviceId.get() != 1) {
Log.i(TAG, String.format(Locale.US, "Ignoring call message that is not for this device! intended: %d, this: %d", destinationDeviceId.get(), 1));
return;
}
if (message.getOfferMessage().isPresent()) handleCallOfferMessage(content, message.getOfferMessage().get(), smsMessageId);
else if (message.getAnswerMessage().isPresent()) handleCallAnswerMessage(content, message.getAnswerMessage().get());
@ -454,7 +461,8 @@ public final class PushProcessMessageJob extends BaseJob {
.putExtra(WebRtcCallService.EXTRA_REMOTE_DEVICE, content.getSenderDevice())
.putExtra(WebRtcCallService.EXTRA_OFFER_DESCRIPTION, message.getDescription())
.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, content.getTimestamp())
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, message.getType().getCode());
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, message.getType().getCode())
.putExtra(WebRtcCallService.EXTRA_MULTI_RING, content.getCallMessage().get().isMultiRing());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) context.startForegroundService(intent);
else context.startService(intent);
@ -472,7 +480,8 @@ public final class PushProcessMessageJob extends BaseJob {
.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId())
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, remotePeer)
.putExtra(WebRtcCallService.EXTRA_REMOTE_DEVICE, content.getSenderDevice())
.putExtra(WebRtcCallService.EXTRA_ANSWER_DESCRIPTION, message.getDescription());
.putExtra(WebRtcCallService.EXTRA_ANSWER_DESCRIPTION, message.getDescription())
.putExtra(WebRtcCallService.EXTRA_MULTI_RING, content.getCallMessage().get().isMultiRing());
context.startService(intent);
}
@ -513,9 +522,12 @@ public final class PushProcessMessageJob extends BaseJob {
RemotePeer remotePeer = new RemotePeer(Recipient.externalPush(context, content.getSender()).getId());
intent.setAction(WebRtcCallService.ACTION_RECEIVE_HANGUP)
.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId())
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, remotePeer)
.putExtra(WebRtcCallService.EXTRA_REMOTE_DEVICE, content.getSenderDevice());
.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId())
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, remotePeer)
.putExtra(WebRtcCallService.EXTRA_REMOTE_DEVICE, content.getSenderDevice())
.putExtra(WebRtcCallService.EXTRA_HANGUP_IS_LEGACY, message.isLegacy())
.putExtra(WebRtcCallService.EXTRA_HANGUP_DEVICE_ID, message.getDeviceId())
.putExtra(WebRtcCallService.EXTRA_HANGUP_TYPE, message.getType().getCode());
context.startService(intent);
}

View File

@ -10,19 +10,19 @@ import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.os.ResultReceiver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.greenrobot.eventbus.EventBus;
import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager;
import org.signal.ringrtc.CallManager.CallEvent;
import org.signal.ringrtc.Remote;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
@ -73,7 +73,6 @@ import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import java.lang.Thread;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
@ -107,51 +106,58 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
public static final String EXTRA_REMOTE_DEVICE = "remote_device";
public static final String EXTRA_OFFER_DESCRIPTION = "offer_description";
public static final String EXTRA_OFFER_TYPE = "offer_type";
public static final String EXTRA_MULTI_RING = "multi_ring";
public static final String EXTRA_HANGUP_TYPE = "hangup_type";
public static final String EXTRA_HANGUP_IS_LEGACY = "hangup_is_legacy";
public static final String EXTRA_HANGUP_DEVICE_ID = "hangup_device_id";
public static final String EXTRA_ANSWER_DESCRIPTION = "answer_description";
public static final String EXTRA_ICE_CANDIDATES = "ice_candidates";
public static final String EXTRA_ENABLE = "enable_value";
public static final String EXTRA_BROADCAST = "broadcast";
public static final String EXTRA_ANSWER_WITH_VIDEO = "enable_video";
public static final String ACTION_OUTGOING_CALL = "CALL_OUTGOING";
public static final String ACTION_DENY_CALL = "DENY_CALL";
public static final String ACTION_LOCAL_HANGUP = "LOCAL_HANGUP";
public static final String ACTION_SET_MUTE_AUDIO = "SET_MUTE_AUDIO";
public static final String ACTION_FLIP_CAMERA = "FLIP_CAMERA";
public static final String ACTION_BLUETOOTH_CHANGE = "BLUETOOTH_CHANGE";
public static final String ACTION_WIRED_HEADSET_CHANGE = "WIRED_HEADSET_CHANGE";
public static final String ACTION_SCREEN_OFF = "SCREEN_OFF";
public static final String ACTION_IS_IN_CALL_QUERY = "IS_IN_CALL";
public static final String ACTION_SET_AUDIO_SPEAKER = "SET_AUDIO_SPEAKER";
public static final String ACTION_SET_AUDIO_BLUETOOTH = "SET_AUDIO_BLUETOOTH";
public static final String ACTION_CALL_CONNECTED = "CALL_CONNECTED";
public static final String ACTION_START_OUTGOING_CALL = "START_OUTGOING_CALL";
public static final String ACTION_START_INCOMING_CALL = "START_INCOMING_CALL";
public static final String ACTION_LOCAL_RINGING = "LOCAL_RINGING";
public static final String ACTION_REMOTE_RINGING = "REMOTE_RINGING";
public static final String ACTION_ACCEPT_CALL = "ACCEPT_CALL";
public static final String ACTION_SEND_OFFER = "SEND_OFFER";
public static final String ACTION_SEND_ANSWER = "SEND_ANSWER";
public static final String ACTION_SEND_ICE_CANDIDATES = "SEND_ICE_CANDIDATES";
public static final String ACTION_SEND_HANGUP = "SEND_HANGUP";
public static final String ACTION_SEND_BUSY = "SEND_BUSY";
public static final String ACTION_RECEIVE_OFFER = "RECEIVE_OFFER";
public static final String ACTION_RECEIVE_ANSWER = "RECEIVE_ANSWER";
public static final String ACTION_RECEIVE_ICE_CANDIDATES = "RECEIVE_ICE_CANDIDATES";
public static final String ACTION_RECEIVE_HANGUP = "RECEIVE_HANGUP";
public static final String ACTION_RECEIVE_BUSY = "RECEIVE_BUSY";
public static final String ACTION_REMOTE_VIDEO_ENABLE = "REMOTE_VIDEO_ENABLE";
public static final String ACTION_SET_ENABLE_VIDEO = "SET_ENABLE_VIDEO";
public static final String ACTION_ENDED_REMOTE_HANGUP = "ENDED_REMOTE_HANGUP";
public static final String ACTION_ENDED_REMOTE_BUSY = "ENDED_REMOTE_BUSY";
public static final String ACTION_ENDED_REMOTE_GLARE = "ENDED_REMOTE_GLARE";
public static final String ACTION_ENDED_TIMEOUT = "ENDED_TIMEOUT";
public static final String ACTION_ENDED_INTERNAL_FAILURE = "ENDED_INTERNAL_FAILURE";
public static final String ACTION_ENDED_SIGNALING_FAILURE = "ENDED_SIGNALING_FAILURE";
public static final String ACTION_ENDED_CONNECTION_FAILURE = "ENDED_CONNECTION_FAILURE";
public static final String ACTION_ENDED_RX_OFFER_EXPIRED = "ENDED_RX_OFFER_EXPIRED";
public static final String ACTION_ENDED_RX_OFFER_WHILE_ACTIVE = "ENDED_RX_OFFER_WHILE_ACTIVE";
public static final String ACTION_CALL_CONCLUDED = "CALL_CONCLUDED";
public static final String ACTION_OUTGOING_CALL = "CALL_OUTGOING";
public static final String ACTION_DENY_CALL = "DENY_CALL";
public static final String ACTION_LOCAL_HANGUP = "LOCAL_HANGUP";
public static final String ACTION_SET_MUTE_AUDIO = "SET_MUTE_AUDIO";
public static final String ACTION_FLIP_CAMERA = "FLIP_CAMERA";
public static final String ACTION_BLUETOOTH_CHANGE = "BLUETOOTH_CHANGE";
public static final String ACTION_WIRED_HEADSET_CHANGE = "WIRED_HEADSET_CHANGE";
public static final String ACTION_SCREEN_OFF = "SCREEN_OFF";
public static final String ACTION_IS_IN_CALL_QUERY = "IS_IN_CALL";
public static final String ACTION_SET_AUDIO_SPEAKER = "SET_AUDIO_SPEAKER";
public static final String ACTION_SET_AUDIO_BLUETOOTH = "SET_AUDIO_BLUETOOTH";
public static final String ACTION_CALL_CONNECTED = "CALL_CONNECTED";
public static final String ACTION_START_OUTGOING_CALL = "START_OUTGOING_CALL";
public static final String ACTION_START_INCOMING_CALL = "START_INCOMING_CALL";
public static final String ACTION_LOCAL_RINGING = "LOCAL_RINGING";
public static final String ACTION_REMOTE_RINGING = "REMOTE_RINGING";
public static final String ACTION_ACCEPT_CALL = "ACCEPT_CALL";
public static final String ACTION_SEND_OFFER = "SEND_OFFER";
public static final String ACTION_SEND_ANSWER = "SEND_ANSWER";
public static final String ACTION_SEND_ICE_CANDIDATES = "SEND_ICE_CANDIDATES";
public static final String ACTION_SEND_HANGUP = "SEND_HANGUP";
public static final String ACTION_SEND_BUSY = "SEND_BUSY";
public static final String ACTION_RECEIVE_OFFER = "RECEIVE_OFFER";
public static final String ACTION_RECEIVE_ANSWER = "RECEIVE_ANSWER";
public static final String ACTION_RECEIVE_ICE_CANDIDATES = "RECEIVE_ICE_CANDIDATES";
public static final String ACTION_RECEIVE_HANGUP = "RECEIVE_HANGUP";
public static final String ACTION_RECEIVE_BUSY = "RECEIVE_BUSY";
public static final String ACTION_REMOTE_VIDEO_ENABLE = "REMOTE_VIDEO_ENABLE";
public static final String ACTION_SET_ENABLE_VIDEO = "SET_ENABLE_VIDEO";
public static final String ACTION_ENDED_REMOTE_HANGUP = "ENDED_REMOTE_HANGUP";
public static final String ACTION_ENDED_REMOTE_HANGUP_ACCEPTED = "ENDED_REMOTE_HANGUP_ACCEPTED";
public static final String ACTION_ENDED_REMOTE_HANGUP_DECLINED = "ENDED_REMOTE_HANGUP_DECLINED";
public static final String ACTION_ENDED_REMOTE_HANGUP_BUSY = "ENDED_REMOTE_HANGUP_BUSY";
public static final String ACTION_ENDED_REMOTE_BUSY = "ENDED_REMOTE_BUSY";
public static final String ACTION_ENDED_REMOTE_GLARE = "ENDED_REMOTE_GLARE";
public static final String ACTION_ENDED_TIMEOUT = "ENDED_TIMEOUT";
public static final String ACTION_ENDED_INTERNAL_FAILURE = "ENDED_INTERNAL_FAILURE";
public static final String ACTION_ENDED_SIGNALING_FAILURE = "ENDED_SIGNALING_FAILURE";
public static final String ACTION_ENDED_CONNECTION_FAILURE = "ENDED_CONNECTION_FAILURE";
public static final String ACTION_ENDED_RX_OFFER_EXPIRED = "ENDED_RX_OFFER_EXPIRED";
public static final String ACTION_ENDED_RX_OFFER_WHILE_ACTIVE = "ENDED_RX_OFFER_WHILE_ACTIVE";
public static final String ACTION_CALL_CONCLUDED = "CALL_CONCLUDED";
private CameraState localCameraState = CameraState.UNKNOWN;
private boolean microphoneEnabled = true;
@ -204,45 +210,48 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
if (intent == null || intent.getAction() == null) return START_NOT_STICKY;
serviceExecutor.execute(() -> {
if (intent.getAction().equals(ACTION_RECEIVE_OFFER)) handleReceivedOffer(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_BUSY)) handleReceivedBusy(intent);
else if (intent.getAction().equals(ACTION_OUTGOING_CALL) && isIdle()) handleOutgoingCall(intent);
else if (intent.getAction().equals(ACTION_DENY_CALL)) handleDenyCall(intent);
else if (intent.getAction().equals(ACTION_LOCAL_HANGUP)) handleLocalHangup(intent);
else if (intent.getAction().equals(ACTION_SET_MUTE_AUDIO)) handleSetMuteAudio(intent);
else if (intent.getAction().equals(ACTION_FLIP_CAMERA)) handleSetCameraFlip(intent);
else if (intent.getAction().equals(ACTION_BLUETOOTH_CHANGE)) handleBluetoothChange(intent);
else if (intent.getAction().equals(ACTION_WIRED_HEADSET_CHANGE)) handleWiredHeadsetChange(intent);
else if (intent.getAction().equals(ACTION_SCREEN_OFF)) handleScreenOffChange(intent);
else if (intent.getAction().equals(ACTION_CALL_CONNECTED)) handleCallConnected(intent);
else if (intent.getAction().equals(ACTION_IS_IN_CALL_QUERY)) handleIsInCallQuery(intent);
else if (intent.getAction().equals(ACTION_SET_AUDIO_SPEAKER)) handleSetSpeakerAudio(intent);
else if (intent.getAction().equals(ACTION_SET_AUDIO_BLUETOOTH)) handleSetBluetoothAudio(intent);
else if (intent.getAction().equals(ACTION_START_OUTGOING_CALL)) handleStartOutgoingCall(intent);
else if (intent.getAction().equals(ACTION_START_INCOMING_CALL)) handleStartIncomingCall(intent);
else if (intent.getAction().equals(ACTION_ACCEPT_CALL)) handleAcceptCall(intent);
else if (intent.getAction().equals(ACTION_LOCAL_RINGING)) handleLocalRinging(intent);
else if (intent.getAction().equals(ACTION_REMOTE_RINGING)) handleRemoteRinging(intent);
else if (intent.getAction().equals(ACTION_SEND_OFFER)) handleSendOffer(intent);
else if (intent.getAction().equals(ACTION_SEND_ANSWER)) handleSendAnswer(intent);
else if (intent.getAction().equals(ACTION_SEND_ICE_CANDIDATES)) handleSendIceCandidates(intent);
else if (intent.getAction().equals(ACTION_SEND_HANGUP)) handleSendHangup(intent);
else if (intent.getAction().equals(ACTION_SEND_BUSY)) handleSendBusy(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_ANSWER)) handleReceivedAnswer(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_ICE_CANDIDATES)) handleReceivedIceCandidates(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_HANGUP)) handleReceivedHangup(intent);
else if (intent.getAction().equals(ACTION_REMOTE_VIDEO_ENABLE)) handleRemoteVideoEnable(intent);
else if (intent.getAction().equals(ACTION_SET_ENABLE_VIDEO)) handleSetEnableVideo(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_HANGUP)) handleEndedRemoteHangup(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_BUSY)) handleEndedRemoteBusy(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_GLARE)) handleEndedRemoteGlare(intent);
else if (intent.getAction().equals(ACTION_ENDED_TIMEOUT)) handleEndedTimeout(intent);
else if (intent.getAction().equals(ACTION_ENDED_INTERNAL_FAILURE)) handleEndedInternalFailure(intent);
else if (intent.getAction().equals(ACTION_ENDED_SIGNALING_FAILURE)) handleEndedSignalingFailure(intent);
else if (intent.getAction().equals(ACTION_ENDED_CONNECTION_FAILURE)) handleEndedConnectionFailure(intent);
else if (intent.getAction().equals(ACTION_ENDED_RX_OFFER_EXPIRED)) handleEndedReceivedOfferExpired(intent);
else if (intent.getAction().equals(ACTION_ENDED_RX_OFFER_WHILE_ACTIVE)) handleEndedReceivedOfferWhileActive(intent);
else if (intent.getAction().equals(ACTION_CALL_CONCLUDED)) handleCallConcluded(intent);
if (intent.getAction().equals(ACTION_RECEIVE_OFFER)) handleReceivedOffer(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_BUSY)) handleReceivedBusy(intent);
else if (intent.getAction().equals(ACTION_OUTGOING_CALL) && isIdle()) handleOutgoingCall(intent);
else if (intent.getAction().equals(ACTION_DENY_CALL)) handleDenyCall(intent);
else if (intent.getAction().equals(ACTION_LOCAL_HANGUP)) handleLocalHangup(intent);
else if (intent.getAction().equals(ACTION_SET_MUTE_AUDIO)) handleSetMuteAudio(intent);
else if (intent.getAction().equals(ACTION_FLIP_CAMERA)) handleSetCameraFlip(intent);
else if (intent.getAction().equals(ACTION_BLUETOOTH_CHANGE)) handleBluetoothChange(intent);
else if (intent.getAction().equals(ACTION_WIRED_HEADSET_CHANGE)) handleWiredHeadsetChange(intent);
else if (intent.getAction().equals(ACTION_SCREEN_OFF)) handleScreenOffChange(intent);
else if (intent.getAction().equals(ACTION_CALL_CONNECTED)) handleCallConnected(intent);
else if (intent.getAction().equals(ACTION_IS_IN_CALL_QUERY)) handleIsInCallQuery(intent);
else if (intent.getAction().equals(ACTION_SET_AUDIO_SPEAKER)) handleSetSpeakerAudio(intent);
else if (intent.getAction().equals(ACTION_SET_AUDIO_BLUETOOTH)) handleSetBluetoothAudio(intent);
else if (intent.getAction().equals(ACTION_START_OUTGOING_CALL)) handleStartOutgoingCall(intent);
else if (intent.getAction().equals(ACTION_START_INCOMING_CALL)) handleStartIncomingCall(intent);
else if (intent.getAction().equals(ACTION_ACCEPT_CALL)) handleAcceptCall(intent);
else if (intent.getAction().equals(ACTION_LOCAL_RINGING)) handleLocalRinging(intent);
else if (intent.getAction().equals(ACTION_REMOTE_RINGING)) handleRemoteRinging(intent);
else if (intent.getAction().equals(ACTION_SEND_OFFER)) handleSendOffer(intent);
else if (intent.getAction().equals(ACTION_SEND_ANSWER)) handleSendAnswer(intent);
else if (intent.getAction().equals(ACTION_SEND_ICE_CANDIDATES)) handleSendIceCandidates(intent);
else if (intent.getAction().equals(ACTION_SEND_HANGUP)) handleSendHangup(intent);
else if (intent.getAction().equals(ACTION_SEND_BUSY)) handleSendBusy(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_ANSWER)) handleReceivedAnswer(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_ICE_CANDIDATES)) handleReceivedIceCandidates(intent);
else if (intent.getAction().equals(ACTION_RECEIVE_HANGUP)) handleReceivedHangup(intent);
else if (intent.getAction().equals(ACTION_REMOTE_VIDEO_ENABLE)) handleRemoteVideoEnable(intent);
else if (intent.getAction().equals(ACTION_SET_ENABLE_VIDEO)) handleSetEnableVideo(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_HANGUP)) handleEndedRemoteHangup(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_HANGUP_ACCEPTED)) handleEndedRemoteHangupAccepted(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_HANGUP_BUSY)) handleEndedRemoteHangupBusy(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_HANGUP_DECLINED)) handleEndedRemoteHangupDeclined(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_BUSY)) handleEndedRemoteBusy(intent);
else if (intent.getAction().equals(ACTION_ENDED_REMOTE_GLARE)) handleEndedRemoteGlare(intent);
else if (intent.getAction().equals(ACTION_ENDED_TIMEOUT)) handleEndedTimeout(intent);
else if (intent.getAction().equals(ACTION_ENDED_INTERNAL_FAILURE)) handleEndedInternalFailure(intent);
else if (intent.getAction().equals(ACTION_ENDED_SIGNALING_FAILURE)) handleEndedSignalingFailure(intent);
else if (intent.getAction().equals(ACTION_ENDED_CONNECTION_FAILURE)) handleEndedConnectionFailure(intent);
else if (intent.getAction().equals(ACTION_ENDED_RX_OFFER_EXPIRED)) handleEndedReceivedOfferExpired(intent);
else if (intent.getAction().equals(ACTION_ENDED_RX_OFFER_WHILE_ACTIVE)) handleEndedReceivedOfferWhileActive(intent);
else if (intent.getAction().equals(ACTION_CALL_CONCLUDED)) handleCallConcluded(intent);
});
@ -378,6 +387,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
String offer = intent.getStringExtra(EXTRA_OFFER_DESCRIPTION);
Long timeStamp = intent.getLongExtra(EXTRA_TIMESTAMP, -1);
OfferMessage.Type offerType = OfferMessage.Type.fromCode(intent.getStringExtra(EXTRA_OFFER_TYPE));
boolean isMultiRing = intent.getBooleanExtra(EXTRA_MULTI_RING, false);
Log.i(TAG, "handleReceivedOffer(): id: " + callId.format(remoteDevice));
@ -399,8 +409,10 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
isRemoteVideoOffer = offerType == OfferMessage.Type.VIDEO_CALL;
CallManager.CallMediaType callType = getCallMediaTypeFromOfferType(offerType);
try {
callManager.receivedOffer(callId, remotePeer, remoteDevice, offer, timeStamp);
callManager.receivedOffer(callId, remotePeer, remoteDevice, offer, timeStamp, callType, isMultiRing, true);
} catch (CallException e) {
callFailure("Unable to process received offer: ", e);
}
@ -417,8 +429,11 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
initializeVideo();
OfferMessage.Type offerType = OfferMessage.Type.fromCode(intent.getStringExtra(EXTRA_OFFER_TYPE));
CallManager.CallMediaType callMediaType = getCallMediaTypeFromOfferType(offerType);
try {
callManager.call(remotePeer);
callManager.call(remotePeer, callMediaType);
} catch (CallException e) {
callFailure("Unable to create outgoing call: ", e);
}
@ -605,8 +620,10 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
camera,
iceServers,
isAlwaysTurn,
1,
deviceList,
enableVideoOnCreate);
enableVideoOnCreate,
true);
} catch (CallException e) {
callFailure("Unable to proceed with call: ", e);
}
@ -637,7 +654,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this);
boolean hideIp = !activePeer.getRecipient().isSystemContact() || isAlwaysTurn;
LinkedList<Integer> deviceList = new LinkedList<Integer>();
LinkedList<Integer> deviceList = new LinkedList<>();
try {
callManager.proceed(activePeer.getCallId(),
@ -648,8 +665,10 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
camera,
iceServers,
hideIp,
1,
deviceList,
false);
false,
true);
} catch (CallException e) {
callFailure("Unable to proceed with call: ", e);
}
@ -686,7 +705,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
RemotePeer remotePeer = getRemotePeer(intent);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
Boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
String offer = intent.getStringExtra(EXTRA_OFFER_DESCRIPTION);
OfferMessage.Type offerType = OfferMessage.Type.fromCode(intent.getStringExtra(EXTRA_OFFER_TYPE));
@ -697,32 +716,34 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
offerType = OfferMessage.Type.NEED_PERMISSION;
}
OfferMessage offerMessage = new OfferMessage(callId.longValue(), offer, offerType);
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forOffer(offerMessage);
OfferMessage offerMessage = new OfferMessage(callId.longValue(), offer, offerType);
Integer destinationDeviceId = broadcast ? null : remoteDevice;
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forOffer(offerMessage, true, destinationDeviceId);
sendCallMessage(remotePeer, remoteDevice, broadcast, callMessage);
sendCallMessage(remotePeer, callMessage);
}
private void handleSendAnswer(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
Boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
String answer = intent.getStringExtra(EXTRA_ANSWER_DESCRIPTION);
Log.i(TAG, "handleSendAnswer: id: " + callId.format(remoteDevice));
AnswerMessage answerMessage = new AnswerMessage(callId.longValue(), answer);
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forAnswer(answerMessage);
AnswerMessage answerMessage = new AnswerMessage(callId.longValue(), answer);
Integer destinationDeviceId = broadcast ? null : remoteDevice;
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forAnswer(answerMessage, true, destinationDeviceId);
sendCallMessage(remotePeer, remoteDevice, broadcast, callMessage);
sendCallMessage(remotePeer, callMessage);
}
private void handleSendIceCandidates(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
Boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
ArrayList<IceCandidateParcel> iceCandidates = intent.getParcelableArrayListExtra(EXTRA_ICE_CANDIDATES);
Log.i(TAG, "handleSendIceCandidates: id: " + callId.format(remoteDevice));
@ -732,48 +753,55 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
iceUpdateMessages.add(parcel.getIceUpdateMessage(callId));
}
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forIceUpdates(iceUpdateMessages);
Integer destinationDeviceId = broadcast ? null : remoteDevice;
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forIceUpdates(iceUpdateMessages, true, destinationDeviceId);
sendCallMessage(remotePeer, remoteDevice, broadcast, callMessage);
sendCallMessage(remotePeer, callMessage);
}
private void handleSendHangup(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
Boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
RemotePeer remotePeer = getRemotePeer(intent);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
HangupMessage.Type type = HangupMessage.Type.fromCode(intent.getStringExtra(EXTRA_HANGUP_TYPE));
boolean isLegacy = intent.getBooleanExtra(EXTRA_HANGUP_IS_LEGACY, true);
int deviceId = intent.getIntExtra(EXTRA_HANGUP_DEVICE_ID, 0);
Log.i(TAG, "handleSendHangup: id: " + callId.format(remoteDevice));
HangupMessage hangupMessage = new HangupMessage(callId.longValue());
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forHangup(hangupMessage);
HangupMessage hangupMessage = new HangupMessage(callId.longValue(), type, deviceId, isLegacy);
Integer destinationDeviceId = broadcast ? null : remoteDevice;
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forHangup(hangupMessage, true, destinationDeviceId);
sendCallMessage(remotePeer, remoteDevice, broadcast, callMessage);
sendCallMessage(remotePeer, callMessage);
}
private void handleSendBusy(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
Boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
boolean broadcast = intent.getBooleanExtra(EXTRA_BROADCAST, false);
Log.i(TAG, "handleSendBusy: id: " + callId.format(remoteDevice));
BusyMessage busyMessage = new BusyMessage(callId.longValue());
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forBusy(busyMessage);
BusyMessage busyMessage = new BusyMessage(callId.longValue());
Integer destinationDeviceId = broadcast ? null : remoteDevice;
SignalServiceCallMessage callMessage = SignalServiceCallMessage.forBusy(busyMessage, true, destinationDeviceId);
sendCallMessage(remotePeer, remoteDevice, broadcast, callMessage);
sendCallMessage(remotePeer, callMessage);
}
private void handleReceivedAnswer(Intent intent) {
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
String description = intent.getStringExtra(EXTRA_ANSWER_DESCRIPTION);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
String description = intent.getStringExtra(EXTRA_ANSWER_DESCRIPTION);
boolean isMultiRing = intent.getBooleanExtra(EXTRA_MULTI_RING, false);
Log.i(TAG, "handleReceivedAnswer(): id: " + callId.format(remoteDevice));
try {
callManager.receivedAnswer(callId, remoteDevice, description);
callManager.receivedAnswer(callId, remoteDevice, description , isMultiRing);
} catch (CallException e) {
callFailure("receivedAnswer() failed: ", e);
}
@ -799,13 +827,16 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
}
private void handleReceivedHangup(Intent intent) {
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
CallId callId = getCallId(intent);
Integer remoteDevice = intent.getIntExtra(EXTRA_REMOTE_DEVICE, -1);
HangupMessage.Type hangupType = HangupMessage.Type.fromCode(intent.getStringExtra(EXTRA_HANGUP_TYPE));
Integer deviceId = intent.getIntExtra(EXTRA_HANGUP_DEVICE_ID, 0);
CallManager.HangupType callHangupType = getCallHangupTypeFromHangupType(hangupType);
Log.i(TAG, "handleReceivedHangup(): id: " + callId.format(remoteDevice));
try {
callManager.receivedHangup(callId, remoteDevice);
callManager.receivedHangup(callId, remoteDevice, callHangupType, deviceId);
} catch (CallException e) {
callFailure("receivedHangup() failed: ", e);
}
@ -1043,6 +1074,30 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
}
}
private void handleEndedRemoteHangupAccepted(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
if (remotePeer.callIdEquals(activePeer)) {
sendMessage(WebRtcViewModel.State.CALL_ACCEPTED_ELSEWHERE, remotePeer, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled, isRemoteVideoOffer);
}
}
private void handleEndedRemoteHangupBusy(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
if (remotePeer.callIdEquals(activePeer)) {
sendMessage(WebRtcViewModel.State.CALL_ONGOING_ELSEWHERE, remotePeer, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled, isRemoteVideoOffer);
}
}
private void handleEndedRemoteHangupDeclined(Intent intent) {
RemotePeer remotePeer = getRemotePeer(intent);
if (remotePeer.callIdEquals(activePeer)) {
sendMessage(WebRtcViewModel.State.CALL_DECLINED_ELSEWHERE, remotePeer, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled, isRemoteVideoOffer);
}
}
private void delayedBusyFinish(CallId callId) {
if (activePeer != null && callId.equals(activePeer.getCallId())) {
Log.i(TAG, "delayedBusyFinish(): calling terminate()");
@ -1268,11 +1323,11 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
this.startActivity(activityIntent);
}
private @NonNull CallId getCallId(Intent intent) {
private static @NonNull CallId getCallId(Intent intent) {
return new CallId(intent.getLongExtra(EXTRA_CALL_ID, -1));
}
private @NonNull RemotePeer getRemotePeer(Intent intent) {
private static @NonNull RemotePeer getRemotePeer(Intent intent) {
RemotePeer remotePeer = intent.getParcelableExtra(EXTRA_REMOTE_PEER);
if (remotePeer == null) throw new AssertionError("No RemotePeer in intent!");
@ -1299,6 +1354,44 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
terminate();
}
private static @NonNull CallManager.CallMediaType getCallMediaTypeFromOfferType(@NonNull OfferMessage.Type offerType) {
return offerType == OfferMessage.Type.VIDEO_CALL ? CallManager.CallMediaType.VIDEO_CALL : CallManager.CallMediaType.AUDIO_CALL;
}
private static @NonNull OfferMessage.Type getOfferTypeFromCallMediaType(@NonNull CallManager.CallMediaType mediaType) {
return mediaType == CallManager.CallMediaType.VIDEO_CALL ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL;
}
private static @NonNull CallManager.HangupType getCallHangupTypeFromHangupType(@NonNull HangupMessage.Type hangupType) {
switch (hangupType) {
case ACCEPTED:
return CallManager.HangupType.ACCEPTED;
case BUSY:
return CallManager.HangupType.BUSY;
case NORMAL:
return CallManager.HangupType.NORMAL;
case DECLINED:
return CallManager.HangupType.DECLINED;
default:
throw new IllegalArgumentException("Unexpected hangup type: " + hangupType);
}
}
private static @NonNull HangupMessage.Type getHangupTypeFromCallHangupType(@NonNull CallManager.HangupType hangupType) {
switch (hangupType) {
case ACCEPTED:
return HangupMessage.Type.ACCEPTED;
case BUSY:
return HangupMessage.Type.BUSY;
case NORMAL:
return HangupMessage.Type.NORMAL;
case DECLINED:
return HangupMessage.Type.DECLINED;
default:
throw new IllegalArgumentException("Unexpected hangup type: " + hangupType);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
@ -1530,9 +1623,9 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
}
}
private void sendCallMessage(RemotePeer remotePeer, Integer remoteDevice, Boolean broadcast, SignalServiceCallMessage callMessage) {
private void sendCallMessage(RemotePeer remotePeer, SignalServiceCallMessage callMessage) {
ListenableFutureTask<Boolean> listenableFutureTask = sendMessage(remotePeer, callMessage);
listenableFutureTask.addListener(new SendCallMessageListener<Boolean>(remotePeer));
listenableFutureTask.addListener(new SendCallMessageListener<>(remotePeer));
}
private LockManager.PhoneState getInCallPhoneState() {
@ -1613,6 +1706,15 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
case ENDED_REMOTE_HANGUP:
intent.setAction(ACTION_ENDED_REMOTE_HANGUP);
break;
case ENDED_REMOTE_HANGUP_ACCEPTED:
intent.setAction(ACTION_ENDED_REMOTE_HANGUP_ACCEPTED);
break;
case ENDED_REMOTE_HANGUP_BUSY:
intent.setAction(ACTION_ENDED_REMOTE_HANGUP_BUSY);
break;
case ENDED_REMOTE_HANGUP_DECLINED:
intent.setAction(ACTION_ENDED_REMOTE_HANGUP_DECLINED);
break;
case ENDED_REMOTE_BUSY:
intent.setAction(ACTION_ENDED_REMOTE_BUSY);
break;
@ -1639,6 +1741,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
break;
case ENDED_LOCAL_HANGUP:
case ENDED_APP_DROPPED_CALL:
case ENDED_IGNORE_CALLS_FROM_NON_MULTIRING_CALLERS:
Log.i(TAG, "Ignoring event: " + event);
return;
default:
@ -1667,11 +1770,12 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
}
@Override
public void onSendOffer(CallId callId, Remote remote, Integer remoteDevice, Boolean broadcast, String offer) {
Log.i(TAG, "onSendOffer: id: " + callId.format(remoteDevice));
public void onSendOffer(CallId callId, Remote remote, Integer remoteDevice, Boolean broadcast, String offer, CallManager.CallMediaType callMediaType) {
Log.i(TAG, "onSendOffer: id: " + callId.format(remoteDevice) + " type: " + callMediaType.name());
if (remote instanceof RemotePeer) {
RemotePeer remotePeer = (RemotePeer)remote;
String offerType = getOfferTypeFromCallMediaType(callMediaType).getCode();
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(ACTION_SEND_OFFER)
@ -1680,7 +1784,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
.putExtra(EXTRA_REMOTE_DEVICE, remoteDevice)
.putExtra(EXTRA_BROADCAST, broadcast)
.putExtra(EXTRA_OFFER_DESCRIPTION, offer)
.putExtra(EXTRA_OFFER_TYPE, (enableVideoOnCreate ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL).getCode());
.putExtra(EXTRA_OFFER_TYPE, offerType);
startService(intent);
} else {
@ -1736,18 +1840,21 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
}
@Override
public void onSendHangup(CallId callId, Remote remote, Integer remoteDevice, Boolean broadcast) {
Log.i(TAG, "onSendHangup: id: " + callId.format(remoteDevice));
public void onSendHangup(CallId callId, Remote remote, Integer remoteDevice, Boolean broadcast, CallManager.HangupType hangupType, Integer deviceId, Boolean useLegacyHangupMessage) {
Log.i(TAG, "onSendHangup: id: " + callId.format(remoteDevice) + " type: " + hangupType.name() + " isLegacy: " + useLegacyHangupMessage);
if (remote instanceof RemotePeer) {
RemotePeer remotePeer = (RemotePeer)remote;
Intent intent = new Intent(this, WebRtcCallService.class);
intent.setAction(ACTION_SEND_HANGUP)
.putExtra(EXTRA_CALL_ID, callId.longValue())
.putExtra(EXTRA_REMOTE_PEER, remotePeer)
.putExtra(EXTRA_REMOTE_DEVICE, remoteDevice)
.putExtra(EXTRA_BROADCAST, broadcast);
.putExtra(EXTRA_CALL_ID, callId.longValue())
.putExtra(EXTRA_REMOTE_PEER, remotePeer)
.putExtra(EXTRA_REMOTE_DEVICE, remoteDevice)
.putExtra(EXTRA_BROADCAST, broadcast)
.putExtra(EXTRA_HANGUP_DEVICE_ID, deviceId.intValue())
.putExtra(EXTRA_HANGUP_IS_LEGACY, useLegacyHangupMessage.booleanValue())
.putExtra(EXTRA_HANGUP_TYPE, getHangupTypeFromCallHangupType(hangupType).getCode());
startService(intent);
} else {

View File

@ -1258,6 +1258,9 @@
<!-- WebRtcCallActivity -->
<string name="WebRtcCallActivity_to_answer_the_call_from_s_give_signal_access_to_your_microphone">To answer the call from %s, give Signal access to your microphone.</string>
<string name="WebRtcCallActivity_signal_requires_microphone_and_camera_permissions_in_order_to_make_or_receive_calls">Signal requires Microphone and Camera permissions in order to make or receive calls, but they have been permanently denied. Please continue to app settings, select \"Permissions\", and enable \"Microphone\" and \"Camera\".</string>
<string name="WebRtcCallActivity__answered_on_a_linked_device">Answered on a linked device.</string>
<string name="WebRtcCallActivity__declined_on_a_linked_device">Declined on a linked device.</string>
<string name="WebRtcCallActivity__busy_on_a_linked_device">Busy on a linked device.</string>
<!-- WebRtcCallScreen -->
<string name="WebRtcCallScreen_new_safety_numbers">The safety number for your conversation with %1$s has changed. This could either mean that someone is trying to intercept your communication, or that %2$s simply re-installed Signal.</string>

View File

@ -372,8 +372,8 @@ dependencyVerification {
['org.signal:argon2:13.1',
'0f686ccff0d4842bfcc74d92e8dc780a5f159b9376e37a1189fabbcdac458bef'],
['org.signal:ringrtc-android:1.3.2',
'f59abe9f33a835cf2ab00953994fe5de477cc4107caec3fe2b2bb778325b6384'],
['org.signal:ringrtc-android:2.0.1',
'1b5d87ad449fe90d337727e6f307439b65c0c57d410a7fc021970de0a0244a58'],
['org.signal:signal-metadata-java:0.1.2',
'6aaeb6a33bf3161a3e6ac9db7678277f7a4cf5a2c96b84342e4007ee49bab1bd'],

View File

@ -684,11 +684,30 @@ public class SignalServiceMessageSender {
.setSdpMLineIndex(update.getSdpMLineIndex()));
}
} else if (callMessage.getHangupMessage().isPresent()) {
builder.setHangup(CallMessage.Hangup.newBuilder().setId(callMessage.getHangupMessage().get().getId()));
CallMessage.Hangup.Type protoType = callMessage.getHangupMessage().get().getType().getProtoType();
CallMessage.Hangup.Builder builderForHangup = CallMessage.Hangup.newBuilder()
.setType(protoType)
.setId(callMessage.getHangupMessage().get().getId());
if (protoType != CallMessage.Hangup.Type.HANGUP_NORMAL) {
builderForHangup.setDeviceId(callMessage.getHangupMessage().get().getDeviceId());
}
if (callMessage.getHangupMessage().get().isLegacy()) {
builder.setLegacyHangup(builderForHangup);
} else {
builder.setHangup(builderForHangup);
}
} else if (callMessage.getBusyMessage().isPresent()) {
builder.setBusy(CallMessage.Busy.newBuilder().setId(callMessage.getBusyMessage().get().getId()));
}
builder.setMultiRing(callMessage.isMultiRing());
if (callMessage.getDestinationDeviceId().isPresent()) {
builder.setDestinationDeviceId(callMessage.getDestinationDeviceId().get());
}
container.setCallMessage(builder);
return container.build().toByteArray();
}

View File

@ -530,12 +530,15 @@ public final class SignalServiceContent {
}
private static SignalServiceCallMessage createCallMessage(SignalServiceProtos.CallMessage content) {
boolean isMultiRing = content.getMultiRing();
Integer destinationDeviceId = content.hasDestinationDeviceId() ? content.getDestinationDeviceId() : null;
if (content.hasOffer()) {
SignalServiceProtos.CallMessage.Offer offerContent = content.getOffer();
return SignalServiceCallMessage.forOffer(new OfferMessage(offerContent.getId(), offerContent.getDescription(), OfferMessage.Type.fromProto(offerContent.getType())));
return SignalServiceCallMessage.forOffer(new OfferMessage(offerContent.getId(), offerContent.getDescription(), OfferMessage.Type.fromProto(offerContent.getType())), isMultiRing, destinationDeviceId);
} else if (content.hasAnswer()) {
SignalServiceProtos.CallMessage.Answer answerContent = content.getAnswer();
return SignalServiceCallMessage.forAnswer(new AnswerMessage(answerContent.getId(), answerContent.getDescription()));
return SignalServiceCallMessage.forAnswer(new AnswerMessage(answerContent.getId(), answerContent.getDescription()), isMultiRing, destinationDeviceId);
} else if (content.getIceUpdateCount() > 0) {
List<IceUpdateMessage> iceUpdates = new LinkedList<>();
@ -543,13 +546,13 @@ public final class SignalServiceContent {
iceUpdates.add(new IceUpdateMessage(iceUpdate.getId(), iceUpdate.getSdpMid(), iceUpdate.getSdpMLineIndex(), iceUpdate.getSdp()));
}
return SignalServiceCallMessage.forIceUpdates(iceUpdates);
return SignalServiceCallMessage.forIceUpdates(iceUpdates, isMultiRing, destinationDeviceId);
} else if (content.hasHangup()) {
SignalServiceProtos.CallMessage.Hangup hangup = content.getHangup();
return SignalServiceCallMessage.forHangup(new HangupMessage(hangup.getId()));
SignalServiceProtos.CallMessage.Hangup hangup = content.hasLegacyHangup() ? content.getLegacyHangup() : content.getHangup();
return SignalServiceCallMessage.forHangup(new HangupMessage(hangup.getId(), HangupMessage.Type.fromProto(hangup.getType()), hangup.getDeviceId(), content.hasLegacyHangup()), isMultiRing, destinationDeviceId);
} else if (content.hasBusy()) {
SignalServiceProtos.CallMessage.Busy busy = content.getBusy();
return SignalServiceCallMessage.forBusy(new BusyMessage(busy.getId()));
return SignalServiceCallMessage.forBusy(new BusyMessage(busy.getId()), isMultiRing, destinationDeviceId);
}
return SignalServiceCallMessage.empty();

View File

@ -1,15 +1,78 @@
package org.whispersystems.signalservice.api.messages.calls;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
public class HangupMessage {
private final long id;
private final long id;
private final Type type;
private final int deviceId;
private final boolean isLegacy;
public HangupMessage(long id) {
this.id = id;
public HangupMessage(long id, Type type, int deviceId, boolean isLegacy) {
this.id = id;
this.type = type;
this.deviceId = deviceId;
this.isLegacy = isLegacy;
}
public long getId() {
return id;
}
public Type getType() {
return type;
}
public int getDeviceId() {
return deviceId;
}
public boolean isLegacy() {
return isLegacy;
}
public enum Type {
NORMAL("normal", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_NORMAL),
ACCEPTED("accepted", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_ACCEPTED),
DECLINED("declined", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_DECLINED),
BUSY("busy", SignalServiceProtos.CallMessage.Hangup.Type.HANGUP_BUSY);
private final String code;
private final SignalServiceProtos.CallMessage.Hangup.Type protoType;
Type(String code, SignalServiceProtos.CallMessage.Hangup.Type protoType) {
this.code = code;
this.protoType = protoType;
}
public String getCode() {
return code;
}
public SignalServiceProtos.CallMessage.Hangup.Type getProtoType() {
return protoType;
}
public static Type fromCode(String code) {
for (Type type : Type.values()) {
if (type.getCode().equals(code)) {
return type;
}
}
throw new IllegalArgumentException("Unexpected code: " + code);
}
public static Type fromProto(SignalServiceProtos.CallMessage.Hangup.Type hangupType) {
for (Type type : Type.values()) {
if (type.getProtoType().equals(hangupType)) {
return type;
}
}
throw new IllegalArgumentException("Unexpected type: " + hangupType.name());
}
}
}

View File

@ -12,78 +12,98 @@ public class SignalServiceCallMessage {
private final Optional<HangupMessage> hangupMessage;
private final Optional<BusyMessage> busyMessage;
private final Optional<List<IceUpdateMessage>> iceUpdateMessages;
private final Optional<Integer> destinationDeviceId;
private final boolean isMultiRing;
private SignalServiceCallMessage(Optional<OfferMessage> offerMessage,
Optional<AnswerMessage> answerMessage,
Optional<List<IceUpdateMessage>> iceUpdateMessages,
Optional<HangupMessage> hangupMessage,
Optional<BusyMessage> busyMessage)
Optional<BusyMessage> busyMessage,
boolean isMultiRing,
Optional<Integer> destinationDeviceId)
{
this.offerMessage = offerMessage;
this.answerMessage = answerMessage;
this.iceUpdateMessages = iceUpdateMessages;
this.hangupMessage = hangupMessage;
this.busyMessage = busyMessage;
this.offerMessage = offerMessage;
this.answerMessage = answerMessage;
this.iceUpdateMessages = iceUpdateMessages;
this.hangupMessage = hangupMessage;
this.busyMessage = busyMessage;
this.isMultiRing = isMultiRing;
this.destinationDeviceId = destinationDeviceId;
}
public static SignalServiceCallMessage forOffer(OfferMessage offerMessage) {
public static SignalServiceCallMessage forOffer(OfferMessage offerMessage, boolean isMultiRing, Integer destinationDeviceId) {
return new SignalServiceCallMessage(Optional.of(offerMessage),
Optional.<AnswerMessage>absent(),
Optional.<List<IceUpdateMessage>>absent(),
Optional.<HangupMessage>absent(),
Optional.<BusyMessage>absent());
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
isMultiRing,
Optional.fromNullable(destinationDeviceId));
}
public static SignalServiceCallMessage forAnswer(AnswerMessage answerMessage) {
return new SignalServiceCallMessage(Optional.<OfferMessage>absent(),
public static SignalServiceCallMessage forAnswer(AnswerMessage answerMessage, boolean isMultiRing, Integer destinationDeviceId) {
return new SignalServiceCallMessage(Optional.absent(),
Optional.of(answerMessage),
Optional.<List<IceUpdateMessage>>absent(),
Optional.<HangupMessage>absent(),
Optional.<BusyMessage>absent());
Optional.absent(),
Optional.absent(),
Optional.absent(),
isMultiRing,
Optional.fromNullable(destinationDeviceId));
}
public static SignalServiceCallMessage forIceUpdates(List<IceUpdateMessage> iceUpdateMessages) {
return new SignalServiceCallMessage(Optional.<OfferMessage>absent(),
Optional.<AnswerMessage>absent(),
public static SignalServiceCallMessage forIceUpdates(List<IceUpdateMessage> iceUpdateMessages, boolean isMultiRing, Integer destinationDeviceId) {
return new SignalServiceCallMessage(Optional.absent(),
Optional.absent(),
Optional.of(iceUpdateMessages),
Optional.<HangupMessage>absent(),
Optional.<BusyMessage>absent());
Optional.absent(),
Optional.absent(),
isMultiRing,
Optional.fromNullable(destinationDeviceId));
}
public static SignalServiceCallMessage forIceUpdate(final IceUpdateMessage iceUpdateMessage) {
public static SignalServiceCallMessage forIceUpdate(final IceUpdateMessage iceUpdateMessage, boolean isMultiRing, Integer destinationDeviceId) {
List<IceUpdateMessage> iceUpdateMessages = new LinkedList<>();
iceUpdateMessages.add(iceUpdateMessage);
return new SignalServiceCallMessage(Optional.<OfferMessage>absent(),
Optional.<AnswerMessage>absent(),
return new SignalServiceCallMessage(Optional.absent(),
Optional.absent(),
Optional.of(iceUpdateMessages),
Optional.<HangupMessage>absent(),
Optional.<BusyMessage>absent());
Optional.absent(),
Optional.absent(),
isMultiRing,
Optional.fromNullable(destinationDeviceId));
}
public static SignalServiceCallMessage forHangup(HangupMessage hangupMessage) {
return new SignalServiceCallMessage(Optional.<OfferMessage>absent(),
Optional.<AnswerMessage>absent(),
Optional.<List<IceUpdateMessage>>absent(),
public static SignalServiceCallMessage forHangup(HangupMessage hangupMessage, boolean isMultiRing, Integer destinationDeviceId) {
return new SignalServiceCallMessage(Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.of(hangupMessage),
Optional.<BusyMessage>absent());
Optional.absent(),
isMultiRing,
Optional.fromNullable(destinationDeviceId));
}
public static SignalServiceCallMessage forBusy(BusyMessage busyMessage) {
return new SignalServiceCallMessage(Optional.<OfferMessage>absent(),
Optional.<AnswerMessage>absent(),
Optional.<List<IceUpdateMessage>>absent(),
Optional.<HangupMessage>absent(),
Optional.of(busyMessage));
public static SignalServiceCallMessage forBusy(BusyMessage busyMessage, boolean isMultiRing, Integer destinationDeviceId) {
return new SignalServiceCallMessage(Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.of(busyMessage),
isMultiRing,
Optional.fromNullable(destinationDeviceId));
}
public static SignalServiceCallMessage empty() {
return new SignalServiceCallMessage(Optional.<OfferMessage>absent(),
Optional.<AnswerMessage>absent(),
Optional.<List<IceUpdateMessage>>absent(),
Optional.<HangupMessage>absent(),
Optional.<BusyMessage>absent());
return new SignalServiceCallMessage(Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
false,
Optional.absent());
}
public Optional<List<IceUpdateMessage>> getIceUpdateMessages() {
@ -105,4 +125,12 @@ public class SignalServiceCallMessage {
public Optional<BusyMessage> getBusyMessage() {
return busyMessage;
}
public boolean isMultiRing() {
return isMultiRing;
}
public Optional<Integer> getDestinationDeviceId() {
return destinationDeviceId;
}
}

View File

@ -71,15 +71,28 @@ message CallMessage {
}
message Hangup {
optional uint64 id = 1;
enum Type {
HANGUP_NORMAL = 0;
HANGUP_ACCEPTED = 1;
HANGUP_DECLINED = 2;
HANGUP_BUSY = 3;
}
optional uint64 id = 1;
optional Type type = 2;
optional uint32 deviceId = 3;
}
optional Offer offer = 1;
optional Answer answer = 2;
repeated IceUpdate iceUpdate = 3;
optional Hangup hangup = 4;
optional Busy busy = 5;
optional Offer offer = 1;
optional Answer answer = 2;
repeated IceUpdate iceUpdate = 3;
optional Hangup legacyHangup = 4;
optional Busy busy = 5;
// 6 is reserved.
optional Hangup hangup = 7;
optional bool multiRing = 8;
optional uint32 destinationDeviceId = 9;
}
message DataMessage {