diff --git a/app/build.gradle b/app/build.gradle index c4fcfb51a..169054de6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -344,7 +344,7 @@ dependencies { implementation 'com.google.protobuf:protobuf-javalite:3.10.0' implementation 'org.signal:argon2:13.1@aar' - implementation 'org.signal:ringrtc-android:2.8.10' + implementation 'org.signal:ringrtc-android:2.9.0' implementation "me.leolin:ShortcutBadger:1.1.16" implementation 'se.emilsjolander:stickylistheaders:2.7.0' diff --git a/app/src/main/java/org/thoughtcrime/securesms/ringrtc/IceCandidateParcel.java b/app/src/main/java/org/thoughtcrime/securesms/ringrtc/IceCandidateParcel.java index 64d6d5dac..ef7e93c2c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ringrtc/IceCandidateParcel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ringrtc/IceCandidateParcel.java @@ -6,7 +6,6 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import org.signal.ringrtc.CallId; -import org.signal.ringrtc.IceCandidate; import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage; /** @@ -17,29 +16,28 @@ import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage; */ public class IceCandidateParcel implements Parcelable { - @NonNull private final IceCandidate iceCandidate; + @NonNull private final byte[] iceCandidate; - public IceCandidateParcel(@NonNull IceCandidate iceCandidate) { + public IceCandidateParcel(@NonNull byte[] iceCandidate) { this.iceCandidate = iceCandidate; } public IceCandidateParcel(@NonNull IceUpdateMessage iceUpdateMessage) { - this.iceCandidate = new IceCandidate(iceUpdateMessage.getOpaque(), iceUpdateMessage.getSdp()); + this.iceCandidate = iceUpdateMessage.getOpaque(); } private IceCandidateParcel(@NonNull Parcel in) { - this.iceCandidate = new IceCandidate(in.createByteArray(), - in.readString()); + this.iceCandidate = in.createByteArray(); } - public @NonNull IceCandidate getIceCandidate() { + public @NonNull byte[] getIceCandidate() { return iceCandidate; } public @NonNull IceUpdateMessage getIceUpdateMessage(@NonNull CallId callId) { return new IceUpdateMessage(callId.longValue(), - iceCandidate.getOpaque(), - iceCandidate.getSdp()); + iceCandidate, + null); } @Override @@ -49,8 +47,7 @@ public class IceCandidateParcel implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeByteArray(iceCandidate.getOpaque()); - dest.writeString(iceCandidate.getSdp()); + dest.writeByteArray(iceCandidate); } public static final Creator CREATOR = new Creator() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java index 7c07373f1..6cde49d62 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -28,7 +28,6 @@ import org.signal.ringrtc.CallManager; import org.signal.ringrtc.CallManager.CallEvent; import org.signal.ringrtc.GroupCall; import org.signal.ringrtc.HttpHeader; -import org.signal.ringrtc.IceCandidate; import org.signal.ringrtc.Remote; import org.signal.storageservice.protos.groups.GroupExternalCredential; import org.signal.zkgroup.VerificationFailedException; @@ -930,7 +929,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer, } @Override - public void onSendOffer(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @Nullable byte[] opaque, @Nullable String sdp, @NonNull CallManager.CallMediaType callMediaType) { + public void onSendOffer(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @NonNull byte[] opaque, @NonNull CallManager.CallMediaType callMediaType) { Log.i(TAG, "onSendOffer: id: " + callId.format(remoteDevice) + " type: " + callMediaType.name()); if (remote instanceof RemotePeer) { @@ -944,7 +943,6 @@ public class WebRtcCallService extends Service implements CallManager.Observer, .putExtra(EXTRA_REMOTE_DEVICE, remoteDevice) .putExtra(EXTRA_BROADCAST, broadcast) .putExtra(EXTRA_OFFER_OPAQUE, opaque) - .putExtra(EXTRA_OFFER_SDP, sdp) .putExtra(EXTRA_OFFER_TYPE, offerType); startService(intent); @@ -954,7 +952,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer, } @Override - public void onSendAnswer(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @Nullable byte[] opaque, @Nullable String sdp) { + public void onSendAnswer(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @NonNull byte[] opaque) { Log.i(TAG, "onSendAnswer: id: " + callId.format(remoteDevice)); if (remote instanceof RemotePeer) { @@ -966,8 +964,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer, .putExtra(EXTRA_REMOTE_PEER, remotePeer) .putExtra(EXTRA_REMOTE_DEVICE, remoteDevice) .putExtra(EXTRA_BROADCAST, broadcast) - .putExtra(EXTRA_ANSWER_OPAQUE, opaque) - .putExtra(EXTRA_ANSWER_SDP, sdp); + .putExtra(EXTRA_ANSWER_OPAQUE, opaque); startService(intent); } else { @@ -976,7 +973,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer, } @Override - public void onSendIceCandidates(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @NonNull List iceCandidates) { + public void onSendIceCandidates(@NonNull CallId callId, @Nullable Remote remote, @NonNull Integer remoteDevice, @NonNull Boolean broadcast, @NonNull List iceCandidates) { Log.i(TAG, "onSendIceCandidates: id: " + callId.format(remoteDevice)); if (remote instanceof RemotePeer) { @@ -984,7 +981,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer, Intent intent = new Intent(this, WebRtcCallService.class); ArrayList iceCandidateParcels = new ArrayList<>(iceCandidates.size()); - for (IceCandidate iceCandidate : iceCandidates) { + for (byte[] iceCandidate : iceCandidates) { iceCandidateParcels.add(new IceCandidateParcel(iceCandidate)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java index 55cd153a4..8561d268e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java @@ -8,7 +8,6 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallException; import org.signal.ringrtc.CallId; -import org.signal.ringrtc.IceCandidate; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.events.WebRtcViewModel; @@ -96,7 +95,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor { { Log.i(tag, "handleReceivedIceCandidates(): id: " + callMetadata.getCallId().format(callMetadata.getRemoteDevice()) + ", count: " + iceCandidateParcels.size()); - LinkedList iceCandidates = new LinkedList<>(); + LinkedList iceCandidates = new LinkedList<>(); for (IceCandidateParcel parcel : iceCandidateParcels) { iceCandidates.add(parcel.getIceCandidate()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java index eced2f15c..61e00d20d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/CallSetupActionProcessorDelegate.java @@ -63,7 +63,7 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor { callManager.setCommunicationMode(); callManager.setAudioEnable(currentState.getLocalDeviceState().isMicrophoneEnabled()); callManager.setVideoEnable(currentState.getLocalDeviceState().getCameraState().isEnabled()); - callManager.setLowBandwidthMode(NetworkUtil.useLowBandwidthCalling(context)); + callManager.updateBandwidthMode(NetworkUtil.getCallingBandwidthMode(context)); } catch (CallException e) { return callFailure(currentState, "Enabling audio/video failed: ", e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java index 055d932ec..c1481b779 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupJoiningActionProcessor.java @@ -7,6 +7,7 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallException; +import org.signal.ringrtc.CallManager; import org.signal.ringrtc.GroupCall; import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.ringrtc.Camera; @@ -75,7 +76,7 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor { try { groupCall.setOutgoingVideoMuted(!currentState.getLocalDeviceState().getCameraState().isEnabled()); groupCall.setOutgoingAudioMuted(!currentState.getLocalDeviceState().isMicrophoneEnabled()); - groupCall.setBandwidthMode(NetworkUtil.useLowBandwidthCalling(context) ? GroupCall.BandwidthMode.LOW : GroupCall.BandwidthMode.NORMAL); + groupCall.setBandwidthMode(NetworkUtil.getCallingBandwidthMode(context)); } catch (CallException e) { Log.e(tag, e); throw new RuntimeException(e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java index c6adafb60..2b4db95c7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java @@ -8,6 +8,7 @@ import com.annimon.stream.Stream; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallException; +import org.signal.ringrtc.CallManager; import org.signal.ringrtc.GroupCall; import org.signal.ringrtc.PeekInfo; import org.thoughtcrime.securesms.BuildConfig; @@ -52,7 +53,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { try { groupCall.setOutgoingAudioMuted(true); groupCall.setOutgoingVideoMuted(true); - groupCall.setBandwidthMode(NetworkUtil.useLowBandwidthCalling(context) ? GroupCall.BandwidthMode.LOW : GroupCall.BandwidthMode.NORMAL); + groupCall.setBandwidthMode(NetworkUtil.getCallingBandwidthMode(context)); Log.i(TAG, "Connecting to group call: " + currentState.getCallInfoState().getCallRecipient().getId()); groupCall.connect(); @@ -151,7 +152,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { groupCall.setOutgoingVideoSource(currentState.getVideoState().requireLocalSink(), currentState.getVideoState().requireCamera()); groupCall.setOutgoingVideoMuted(!currentState.getLocalDeviceState().getCameraState().isEnabled()); groupCall.setOutgoingAudioMuted(!currentState.getLocalDeviceState().isMicrophoneEnabled()); - groupCall.setBandwidthMode(NetworkUtil.useLowBandwidthCalling(context) ? GroupCall.BandwidthMode.LOW : GroupCall.BandwidthMode.NORMAL); + groupCall.setBandwidthMode(NetworkUtil.getCallingBandwidthMode(context)); groupCall.join(); } catch (CallException e) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java index 5d930d2be..f870a1654 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/IncomingCallActionProcessor.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallException; import org.signal.ringrtc.CallId; +import org.signal.ringrtc.CallManager; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.events.CallParticipant; @@ -20,6 +21,7 @@ import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel; import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.service.webrtc.state.VideoState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; +import org.thoughtcrime.securesms.util.NetworkUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.webrtc.locks.LockManager; import org.webrtc.PeerConnection; @@ -91,6 +93,7 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor { videoState.requireCamera(), iceServers, hideIp, + NetworkUtil.getCallingBandwidthMode(context), false); } catch (CallException e) { return callFailure(currentState, "Unable to proceed with call: ", e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java index bb9948295..ed6b696ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/OutgoingCallActionProcessor.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallException; import org.signal.ringrtc.CallId; +import org.signal.ringrtc.CallManager; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.events.CallParticipant; @@ -20,6 +21,7 @@ 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; +import org.thoughtcrime.securesms.util.NetworkUtil; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger; import org.webrtc.PeerConnection; @@ -117,6 +119,7 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor { videoState.requireCamera(), iceServers, isAlwaysTurn, + NetworkUtil.getCallingBandwidthMode(context), currentState.getCallSetupState().isEnableVideoOnCreate()); } catch (CallException e) { return callFailure(currentState, "Unable to proceed with call: ", e); @@ -147,11 +150,15 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor { { Log.i(TAG, "handleReceivedAnswer(): id: " + callMetadata.getCallId().format(callMetadata.getRemoteDevice())); + if (answerMetadata.getOpaque() == null) { + return callFailure(currentState, "receivedAnswer() failed: answerMetadata did not contain opaque", null); + } + try { byte[] remoteIdentityKey = WebRtcUtil.getPublicKeyBytes(receivedAnswerMetadata.getRemoteIdentityKey()); byte[] localIdentityKey = WebRtcUtil.getPublicKeyBytes(IdentityKeyUtil.getIdentityKey(context).serialize()); - webRtcInteractor.getCallManager().receivedAnswer(callMetadata.getCallId(), callMetadata.getRemoteDevice(), answerMetadata.getOpaque(), answerMetadata.getSdp(), receivedAnswerMetadata.isMultiRing(), remoteIdentityKey, localIdentityKey); + webRtcInteractor.getCallManager().receivedAnswer(callMetadata.getCallId(), callMetadata.getRemoteDevice(), answerMetadata.getOpaque(), receivedAnswerMetadata.isMultiRing(), remoteIdentityKey, localIdentityKey); } catch (CallException | InvalidKeyException e) { return callFailure(currentState, "receivedAnswer() failed: ", e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java index 130297e10..0a9496fc1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java @@ -11,6 +11,7 @@ import androidx.annotation.Nullable; import org.signal.core.util.logging.Log; import org.signal.ringrtc.CallException; import org.signal.ringrtc.CallId; +import org.signal.ringrtc.CallManager; import org.signal.ringrtc.GroupCall; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.events.CallParticipant; @@ -342,6 +343,13 @@ public abstract class WebRtcActionProcessor { 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(), true, 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()); @@ -365,7 +373,6 @@ public abstract class WebRtcActionProcessor { callMetadata.getRemotePeer(), callMetadata.getRemoteDevice(), offerMetadata.getOpaque(), - offerMetadata.getSdp(), messageAgeSec, WebRtcUtil.getCallMediaTypeFromOfferType(offerMetadata.getOfferType()), 1, @@ -611,7 +618,7 @@ public abstract class WebRtcActionProcessor { protected @NonNull WebRtcServiceState handleBandwidthModeUpdate(@NonNull WebRtcServiceState currentState) { try { - webRtcInteractor.getCallManager().setLowBandwidthMode(NetworkUtil.useLowBandwidthCalling(context)); + webRtcInteractor.getCallManager().updateBandwidthMode(NetworkUtil.getCallingBandwidthMode(context)); } catch (CallException e) { Log.i(tag, "handleBandwidthModeUpdate: could not update bandwidth mode."); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/NetworkUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/NetworkUtil.java index 86c655a06..e031a241d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/NetworkUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/NetworkUtil.java @@ -6,6 +6,7 @@ import android.net.NetworkInfo; import androidx.annotation.NonNull; +import org.signal.ringrtc.CallManager; import org.thoughtcrime.securesms.keyvalue.SignalStore; public final class NetworkUtil { @@ -27,7 +28,11 @@ public final class NetworkUtil { return info != null && info.isConnected() && info.isRoaming() && info.getType() == ConnectivityManager.TYPE_MOBILE; } - public static boolean useLowBandwidthCalling(@NonNull Context context) { + public static @NonNull CallManager.BandwidthMode getCallingBandwidthMode(@NonNull Context context) { + return useLowBandwidthCalling(context) ? CallManager.BandwidthMode.LOW : CallManager.BandwidthMode.NORMAL; + } + + private static boolean useLowBandwidthCalling(@NonNull Context context) { switch (SignalStore.settings().getCallBandwidthMode()) { case HIGH_ON_WIFI: return !NetworkUtil.isConnectedWifi(context); diff --git a/app/witness-verifications.gradle b/app/witness-verifications.gradle index ad4384ae0..4503a9d1b 100644 --- a/app/witness-verifications.gradle +++ b/app/witness-verifications.gradle @@ -441,8 +441,8 @@ dependencyVerification { ['org.signal:argon2:13.1', '0f686ccff0d4842bfcc74d92e8dc780a5f159b9376e37a1189fabbcdac458bef'], - ['org.signal:ringrtc-android:2.8.10', - 'ccc04ef045a022906bc63d7e6796e8bcd7cdca128c2f17538f6b104538a2434b'], + ['org.signal:ringrtc-android:2.9.0', + '058ff7dc0c01c1c0db363e7396e357bdcfc6f9a3ddc313c2abae032e979d691f'], ['org.signal:zkgroup-android:0.7.0', '52b172565bd01526e93ebf1796b834bdc449d4fe3422c1b827e49cb8d4f13fbd'],