From 97cc8b7777192e6a75bac8db6b49974a2f92d994 Mon Sep 17 00:00:00 2001 From: Curt Brune Date: Wed, 11 Sep 2019 11:14:55 -0700 Subject: [PATCH] Revert "Add ringrtc support." Revert the following commits: "Handle busy call while in PSTN call." Commit 23a0bb3ce0c719aee673ab6a68f15dfd9a1304ec. "Add ringrtc support." Commit 3ac540c68711d90843db0a07959ede1d5ff913d4. --- build.gradle | 4 +- proguard-webrtc.pro | 3 + .../securesms/ApplicationContext.java | 9 +- .../components/webrtc/WebRtcCallScreen.java | 2 +- .../securesms/events/WebRtcViewModel.java | 2 +- .../ringrtc/CallConnectionWrapper.java | 293 --- .../securesms/ringrtc/MessageRecipient.java | 115 - .../securesms/service/WebRtcCallService.java | 808 +++--- .../{ringrtc => webrtc}/CameraState.java | 2 +- .../webrtc/PeerConnectionFactoryOptions.java | 11 + .../webrtc/PeerConnectionWrapper.java | 424 ++++ .../securesms/webrtc/WebRtcDataProtos.java | 2248 +++++++++++++++++ 12 files changed, 3140 insertions(+), 781 deletions(-) create mode 100644 proguard-webrtc.pro delete mode 100644 src/org/thoughtcrime/securesms/ringrtc/CallConnectionWrapper.java delete mode 100644 src/org/thoughtcrime/securesms/ringrtc/MessageRecipient.java rename src/org/thoughtcrime/securesms/{ringrtc => webrtc}/CameraState.java (93%) create mode 100644 src/org/thoughtcrime/securesms/webrtc/PeerConnectionFactoryOptions.java create mode 100644 src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java create mode 100644 src/org/thoughtcrime/securesms/webrtc/WebRtcDataProtos.java diff --git a/build.gradle b/build.gradle index 9c50465eb..5c31415db 100644 --- a/build.gradle +++ b/build.gradle @@ -88,7 +88,7 @@ dependencies { implementation 'org.whispersystems:signal-service-android:2.13.7' - implementation 'org.signal:ringrtc-android:0.1.1' + implementation 'org.whispersystems:webrtc-android:M75' implementation "me.leolin:ShortcutBadger:1.1.16" implementation 'se.emilsjolander:stickylistheaders:2.7.0' @@ -198,7 +198,7 @@ dependencyVerification { 'org.conscrypt:conscrypt-android:400ca559a49b860a82862b22cee0e3110764bdcf7ee7c79e7479895c25cdfc09', 'org.signal:aesgcmprovider:6eb4422e8a618b3b76cb2096a3619d251f9e27989dc68307a1e5414c3710f2d1', 'org.whispersystems:signal-service-android:5115aa434c52ca671c513995e6ae67d73f3abaaa605f9e6cf64c2e01da961c7e', - 'org.signal:ringrtc-android:91d4d89847c10e718bc8badfa0353f0095678855c35c2575509fea97f615de86', + 'org.whispersystems:webrtc-android:f8231bb57923afb243760213dc58924e85cce42f2f3cc8cb33a6d883672a921a', 'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774', 'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb', 'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa', diff --git a/proguard-webrtc.pro b/proguard-webrtc.pro new file mode 100644 index 000000000..7a1e3dea5 --- /dev/null +++ b/proguard-webrtc.pro @@ -0,0 +1,3 @@ +-dontwarn org.webrtc.NetworkMonitorAutoDetect +-dontwarn android.net.Network +-keep class org.webrtc.** { *; } diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 11fcf5402..5b9122ada 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -33,7 +33,6 @@ import com.google.android.gms.security.ProviderInstaller; import org.conscrypt.Conscrypt; import org.signal.aesgcmprovider.AesGcmProvider; -import org.signal.ringrtc.CallConnectionFactory; import org.thoughtcrime.securesms.components.TypingStatusRepository; import org.thoughtcrime.securesms.components.TypingStatusSender; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -71,6 +70,8 @@ import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener; import org.thoughtcrime.securesms.service.UpdateApkRefreshListener; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper; +import org.webrtc.PeerConnectionFactory; +import org.webrtc.PeerConnectionFactory.InitializationOptions; import org.webrtc.voiceengine.WebRtcAudioManager; import org.webrtc.voiceengine.WebRtcAudioUtils; import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider; @@ -125,7 +126,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi initializeSignedPreKeyCheck(); initializePeriodicTasks(); initializeCircumvention(); - initializeRingRtc(); + initializeWebRtc(); initializePendingMessages(); initializeUnidentifiedDeliveryAbilityRefresh(); initializeBlobProvider(); @@ -281,7 +282,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi } } - private void initializeRingRtc() { + private void initializeWebRtc() { try { Set HARDWARE_AEC_BLACKLIST = new HashSet() {{ add("Pixel"); @@ -310,7 +311,7 @@ public class ApplicationContext extends MultiDexApplication implements DefaultLi WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true); } - CallConnectionFactory.initialize(this); + PeerConnectionFactory.initialize(InitializationOptions.builder(this).createInitializationOptions()); } catch (UnsatisfiedLinkError e) { Log.w(TAG, e); } diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java index a9a6c0eaa..331ba35f1 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java @@ -43,10 +43,10 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; -import org.thoughtcrime.securesms.ringrtc.CameraState; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.VerifySpan; import org.thoughtcrime.securesms.util.ViewUtil; +import org.thoughtcrime.securesms.webrtc.CameraState; import org.webrtc.SurfaceViewRenderer; import org.whispersystems.libsignal.IdentityKey; diff --git a/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java b/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java index d93d052c5..a376b888e 100644 --- a/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java +++ b/src/org/thoughtcrime/securesms/events/WebRtcViewModel.java @@ -4,7 +4,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.ringrtc.CameraState; +import org.thoughtcrime.securesms.webrtc.CameraState; import org.webrtc.SurfaceViewRenderer; import org.whispersystems.libsignal.IdentityKey; diff --git a/src/org/thoughtcrime/securesms/ringrtc/CallConnectionWrapper.java b/src/org/thoughtcrime/securesms/ringrtc/CallConnectionWrapper.java deleted file mode 100644 index cd3f02ff6..000000000 --- a/src/org/thoughtcrime/securesms/ringrtc/CallConnectionWrapper.java +++ /dev/null @@ -1,293 +0,0 @@ -package org.thoughtcrime.securesms.ringrtc; - - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.IOException; - -import org.signal.ringrtc.CallConnection; -import org.signal.ringrtc.CallConnectionFactory; -import org.signal.ringrtc.CallException; -import org.signal.ringrtc.SignalMessageRecipient; - -import org.thoughtcrime.securesms.logging.Log; - -import org.webrtc.AudioSource; -import org.webrtc.AudioTrack; -import org.webrtc.Camera1Enumerator; -import org.webrtc.Camera2Enumerator; -import org.webrtc.CameraEnumerator; -import org.webrtc.CameraVideoCapturer; -import org.webrtc.EglBase; -import org.webrtc.IceCandidate; -import org.webrtc.MediaConstraints; -import org.webrtc.MediaStream; -import org.webrtc.SurfaceTextureHelper; -import org.webrtc.VideoSink; -import org.webrtc.VideoSource; -import org.webrtc.VideoTrack; - -import org.whispersystems.signalservice.api.SignalServiceAccountManager; -import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; - -import static org.thoughtcrime.securesms.ringrtc.CameraState.Direction.BACK; -import static org.thoughtcrime.securesms.ringrtc.CameraState.Direction.FRONT; -import static org.thoughtcrime.securesms.ringrtc.CameraState.Direction.NONE; -import static org.thoughtcrime.securesms.ringrtc.CameraState.Direction.PENDING; - -public class CallConnectionWrapper { - private static final String TAG = Log.tag(CallConnectionWrapper.class); - - @NonNull private final CallConnection callConnection; - @NonNull private final AudioTrack audioTrack; - @NonNull private final AudioSource audioSource; - @NonNull private final Camera camera; - @Nullable private final VideoSource videoSource; - @Nullable private final VideoTrack videoTrack; - - public CallConnectionWrapper(@NonNull Context context, - @NonNull CallConnectionFactory factory, - @NonNull CallConnection.Observer observer, - @NonNull VideoSink localRenderer, - @NonNull CameraEventListener cameraEventListener, - @NonNull EglBase eglBase, - boolean hideIp, - long callId, - boolean outBound, - @NonNull SignalMessageRecipient recipient, - @NonNull SignalServiceAccountManager accountManager) - throws UnregisteredUserException, IOException, CallException - { - - CallConnection.Configuration configuration = new CallConnection.Configuration(callId, - outBound, - recipient, - accountManager, - hideIp); - - this.callConnection = factory.createCallConnection(configuration, observer); - this.callConnection.setAudioPlayout(false); - this.callConnection.setAudioRecording(false); - - MediaStream mediaStream = factory.createLocalMediaStream("ARDAMS"); - MediaConstraints audioConstraints = new MediaConstraints(); - - audioConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); - this.audioSource = factory.createAudioSource(audioConstraints); - this.audioTrack = factory.createAudioTrack("ARDAMSa0", audioSource); - this.audioTrack.setEnabled(false); - mediaStream.addTrack(audioTrack); - - this.camera = new Camera(context, cameraEventListener); - - if (camera.capturer != null) { - this.videoSource = factory.createVideoSource(false); - this.videoTrack = factory.createVideoTrack("ARDAMSv0", videoSource); - - camera.capturer.initialize(SurfaceTextureHelper.create("WebRTC-SurfaceTextureHelper", eglBase.getEglBaseContext()), context, videoSource.getCapturerObserver()); - - this.videoTrack.addSink(localRenderer); - this.videoTrack.setEnabled(false); - mediaStream.addTrack(videoTrack); - } else { - this.videoSource = null; - this.videoTrack = null; - } - - this.callConnection.addStream(mediaStream); - } - - public boolean addIceCandidate(IceCandidate candidate) { - return callConnection.addIceCandidate(candidate); - } - - public void sendOffer() throws CallException { - callConnection.sendOffer(); - } - - public boolean validateResponse(SignalMessageRecipient recipient, Long inCallId) - throws CallException - { - return callConnection.validateResponse(recipient, inCallId); - } - - public void handleOfferAnswer(String sessionDescription) throws CallException { - callConnection.handleOfferAnswer(sessionDescription); - } - - public void acceptOffer(String offer) throws CallException { - callConnection.acceptOffer(offer); - } - - public void hangUp() throws CallException { - callConnection.hangUp(); - } - - public void answerCall() throws CallException { - callConnection.answerCall(); - } - - public void sendBusy(SignalMessageRecipient recipient, Long inCallId) throws CallException - { - callConnection.sendBusy(recipient, inCallId); - } - - public void setVideoEnabled(boolean enabled) throws CallException { - if (videoTrack != null) { - videoTrack.setEnabled(enabled); - } - camera.setEnabled(enabled); - callConnection.sendVideoStatus(enabled); - } - - public void flipCamera() { - camera.flip(); - } - - public CameraState getCameraState() { - return new CameraState(camera.getActiveDirection(), camera.getCount()); - } - - public void setCommunicationMode() { - callConnection.setAudioPlayout(true); - callConnection.setAudioRecording(true); - } - - public void setAudioEnabled(boolean enabled) { - audioTrack.setEnabled(enabled); - } - - public void dispose() { - camera.dispose(); - - if (videoSource != null) { - videoSource.dispose(); - } - - audioSource.dispose(); - callConnection.dispose(); - } - - private static class Camera implements CameraVideoCapturer.CameraSwitchHandler { - - @Nullable - private final CameraVideoCapturer capturer; - private final CameraEventListener cameraEventListener; - private final int cameraCount; - - private CameraState.Direction activeDirection; - private boolean enabled; - - Camera(@NonNull Context context, @NonNull CameraEventListener cameraEventListener) - { - this.cameraEventListener = cameraEventListener; - CameraEnumerator enumerator = getCameraEnumerator(context); - cameraCount = enumerator.getDeviceNames().length; - - CameraVideoCapturer capturerCandidate = createVideoCapturer(enumerator, FRONT); - if (capturerCandidate != null) { - activeDirection = FRONT; - } else { - capturerCandidate = createVideoCapturer(enumerator, BACK); - if (capturerCandidate != null) { - activeDirection = BACK; - } else { - activeDirection = NONE; - } - } - capturer = capturerCandidate; - } - - void flip() { - if (capturer == null || cameraCount < 2) { - throw new AssertionError("Tried to flip the camera, but we only have " + cameraCount + - " of them."); - } - activeDirection = PENDING; - capturer.switchCamera(this); - } - - void setEnabled(boolean enabled) { - this.enabled = enabled; - - if (capturer == null) { - return; - } - - try { - if (enabled) { - capturer.startCapture(1280, 720, 30); - } else { - capturer.stopCapture(); - } - } catch (InterruptedException e) { - Log.w(TAG, "Got interrupted while trying to stop video capture", e); - } - } - - void dispose() { - if (capturer != null) { - capturer.dispose(); - } - } - - int getCount() { - return cameraCount; - } - - @NonNull CameraState.Direction getActiveDirection() { - return enabled ? activeDirection : NONE; - } - - @Nullable CameraVideoCapturer getCapturer() { - return capturer; - } - - private @Nullable CameraVideoCapturer createVideoCapturer(@NonNull CameraEnumerator enumerator, - @NonNull CameraState.Direction direction) - { - String[] deviceNames = enumerator.getDeviceNames(); - for (String deviceName : deviceNames) { - if ((direction == FRONT && enumerator.isFrontFacing(deviceName)) || - (direction == BACK && enumerator.isBackFacing(deviceName))) - { - return enumerator.createCapturer(deviceName, null); - } - } - - return null; - } - - private @NonNull CameraEnumerator getCameraEnumerator(@NonNull Context context) { - boolean camera2EnumeratorIsSupported = false; - try { - camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(context); - } catch (final Throwable throwable) { - Log.w(TAG, "Camera2Enumator.isSupport() threw.", throwable); - } - - Log.i(TAG, "Camera2 enumerator supported: " + camera2EnumeratorIsSupported); - - return camera2EnumeratorIsSupported ? new Camera2Enumerator(context) - : new Camera1Enumerator(true); - } - - @Override - public void onCameraSwitchDone(boolean isFrontFacing) { - activeDirection = isFrontFacing ? FRONT : BACK; - cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount())); - } - - @Override - public void onCameraSwitchError(String errorMessage) { - Log.e(TAG, "onCameraSwitchError: " + errorMessage); - cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount())); - } - } - - public interface CameraEventListener { - void onCameraSwitchCompleted(@NonNull CameraState newCameraState); - } -} diff --git a/src/org/thoughtcrime/securesms/ringrtc/MessageRecipient.java b/src/org/thoughtcrime/securesms/ringrtc/MessageRecipient.java deleted file mode 100644 index 6f0740c29..000000000 --- a/src/org/thoughtcrime/securesms/ringrtc/MessageRecipient.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.thoughtcrime.securesms.ringrtc; - -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.IOException; -import java.util.List; - -import org.signal.ringrtc.SignalMessageRecipient; - -import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; -import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.util.Util; - -import org.whispersystems.signalservice.api.SignalServiceMessageSender; -import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; -import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; -import org.whispersystems.signalservice.api.messages.calls.AnswerMessage; -import org.whispersystems.signalservice.api.messages.calls.BusyMessage; -import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage; -import org.whispersystems.signalservice.api.messages.calls.HangupMessage; -import org.whispersystems.signalservice.api.messages.calls.OfferMessage; -import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; - -public final class MessageRecipient implements SignalMessageRecipient { - - private static final String TAG = Log.tag(MessageRecipient.class); - - @NonNull private final Recipient recipient; - @NonNull private final SignalServiceMessageSender messageSender; - - public MessageRecipient(SignalServiceMessageSender messageSender, - Recipient recipient) - { - this.recipient = recipient; - this.messageSender = messageSender; - } - - public @NonNull Address getAddress() { - return recipient.getAddress(); - } - - @Override - public boolean isEqual(@NonNull SignalMessageRecipient o) { - if (!(o instanceof MessageRecipient)) { - return false; - } - - MessageRecipient that = (MessageRecipient) o; - - return recipient.equals(that.recipient); - } - - void sendMessage(Context context, SignalServiceCallMessage callMessage) - throws IOException, UntrustedIdentityException, IOException - { - messageSender.sendCallMessage(new SignalServiceAddress(recipient.getAddress().toPhoneString()), - UnidentifiedAccessUtil.getAccessFor(context, recipient), - callMessage); - } - - @Override - public void sendOfferMessage(Context context, long callId, String description) - throws IOException, UntrustedIdentityException, IOException - { - Log.i(TAG, "MessageRecipient::sendOfferMessage(): callId: " + callId); - - OfferMessage offerMessage = new OfferMessage(callId, description); - sendMessage(context, SignalServiceCallMessage.forOffer(offerMessage)); - } - - @Override - public void sendAnswerMessage(Context context, long callId, String description) - throws IOException, UntrustedIdentityException, IOException - { - Log.i(TAG, "MessageRecipient::sendAnswerMessage(): callId: " + callId); - - AnswerMessage answerMessage = new AnswerMessage(callId, description); - sendMessage(context, SignalServiceCallMessage.forAnswer(answerMessage)); - } - - @Override - public void sendIceUpdates(Context context, List iceUpdateMessages) - throws IOException, UntrustedIdentityException, IOException - { - Log.i(TAG, "MessageRecipient::sendIceUpdates(): iceUpdates: " + iceUpdateMessages.size()); - - sendMessage(context, SignalServiceCallMessage.forIceUpdates(iceUpdateMessages)); - } - - @Override - public void sendHangupMessage(Context context, long callId) - throws IOException, UntrustedIdentityException, IOException - { - Log.i(TAG, "MessageRecipient::sendHangupMessage(): callId: " + callId); - - HangupMessage hangupMessage = new HangupMessage(callId); - sendMessage(context, SignalServiceCallMessage.forHangup(hangupMessage)); - } - - @Override - public void sendBusyMessage(Context context, long callId) - throws IOException, UntrustedIdentityException, IOException - { - Log.i(TAG, "MessageRecipient::sendBusyMessage(): callId: " + callId); - - BusyMessage busyMessage = new BusyMessage(callId); - sendMessage(context, SignalServiceCallMessage.forBusy(busyMessage)); - } - -} diff --git a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java index 0eddc8e21..30140dbc3 100644 --- a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -22,11 +22,7 @@ import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Pair; -import org.signal.ringrtc.CallConnection; -import org.signal.ringrtc.CallConnection.CallError; -import org.signal.ringrtc.CallConnectionFactory; -import org.signal.ringrtc.CallException; -import org.signal.ringrtc.SignalMessageRecipient; +import com.google.protobuf.InvalidProtocolBufferException; import org.greenrobot.eventbus.EventBus; import org.thoughtcrime.securesms.ApplicationContext; @@ -42,9 +38,6 @@ import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.ringrtc.CameraState; -import org.thoughtcrime.securesms.ringrtc.MessageRecipient; -import org.thoughtcrime.securesms.ringrtc.CallConnectionWrapper; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -52,35 +45,53 @@ import org.thoughtcrime.securesms.util.TelephonyUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder; +import org.thoughtcrime.securesms.webrtc.CameraState; import org.thoughtcrime.securesms.webrtc.IncomingPstnCallReceiver; +import org.thoughtcrime.securesms.webrtc.PeerConnectionFactoryOptions; +import org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper; +import org.thoughtcrime.securesms.webrtc.PeerConnectionWrapper.PeerConnectionException; import org.thoughtcrime.securesms.webrtc.UncaughtExceptionHandlerManager; +import org.thoughtcrime.securesms.webrtc.WebRtcDataProtos; +import org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected; +import org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data; +import org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup; import org.thoughtcrime.securesms.webrtc.audio.BluetoothStateManager; import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger; import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager; import org.thoughtcrime.securesms.webrtc.locks.LockManager; import org.webrtc.AudioTrack; +import org.webrtc.DataChannel; import org.webrtc.DefaultVideoDecoderFactory; import org.webrtc.DefaultVideoEncoderFactory; import org.webrtc.EglBase; import org.webrtc.IceCandidate; +import org.webrtc.MediaConstraints; import org.webrtc.MediaStream; +import org.webrtc.PeerConnection; +import org.webrtc.PeerConnectionFactory; +import org.webrtc.RtpReceiver; +import org.webrtc.SessionDescription; import org.webrtc.SurfaceViewRenderer; import org.webrtc.VideoDecoderFactory; import org.webrtc.VideoEncoderFactory; import org.webrtc.VideoTrack; import org.whispersystems.libsignal.IdentityKey; -import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; +import org.whispersystems.signalservice.api.messages.calls.AnswerMessage; import org.whispersystems.signalservice.api.messages.calls.BusyMessage; +import org.whispersystems.signalservice.api.messages.calls.HangupMessage; +import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage; +import org.whispersystems.signalservice.api.messages.calls.OfferMessage; import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage; +import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; import org.whispersystems.signalservice.internal.util.concurrent.SettableFuture; -import java.lang.Thread; import java.io.IOException; +import java.nio.ByteBuffer; import java.security.SecureRandom; import java.util.LinkedList; import java.util.List; @@ -88,6 +99,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_ESTABLISHED; @@ -95,9 +107,10 @@ import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_INC import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_INCOMING_RINGING; import static org.thoughtcrime.securesms.webrtc.CallNotificationBuilder.TYPE_OUTGOING_RINGING; -public class WebRtcCallService extends Service implements CallConnection.Observer, +public class WebRtcCallService extends Service implements PeerConnection.Observer, + DataChannel.Observer, BluetoothStateManager.BluetoothStateListener, - CallConnectionWrapper.CameraEventListener + PeerConnectionWrapper.CameraEventListener { private static final String TAG = WebRtcCallService.class.getSimpleName(); @@ -118,8 +131,6 @@ public class WebRtcCallService extends Service implements CallConnection.Observe public static final String EXTRA_ICE_SDP_MID = "ice_sdp_mid"; public static final String EXTRA_ICE_SDP_LINE_INDEX = "ice_sdp_line_index"; public static final String EXTRA_RESULT_RECEIVER = "result_receiver"; - public static final String EXTRA_CALL_ERROR = "call_error"; - public static final String EXTRA_IDENTITY_KEY_BYTES = "identity_key_bytes"; public static final String ACTION_INCOMING_CALL = "CALL_INCOMING"; public static final String ACTION_OUTGOING_CALL = "CALL_OUTGOING"; @@ -137,12 +148,12 @@ public class WebRtcCallService extends Service implements CallConnection.Observe public static final String ACTION_RESPONSE_MESSAGE = "RESPONSE_MESSAGE"; public static final String ACTION_ICE_MESSAGE = "ICE_MESSAGE"; + public static final String ACTION_ICE_CANDIDATE = "ICE_CANDIDATE"; public static final String ACTION_CALL_CONNECTED = "CALL_CONNECTED"; public static final String ACTION_REMOTE_HANGUP = "REMOTE_HANGUP"; public static final String ACTION_REMOTE_BUSY = "REMOTE_BUSY"; public static final String ACTION_REMOTE_VIDEO_MUTE = "REMOTE_VIDEO_MUTE"; - public static final String ACTION_CALL_RINGING = "CALL_RINGING"; - public static final String ACTION_CALL_ERROR = "CALL_ERROR"; + public static final String ACTION_ICE_CONNECTED = "ICE_CONNECTED"; private CallState callState = CallState.STATE_IDLE; private CameraState localCameraState = CameraState.UNKNOWN; @@ -153,6 +164,7 @@ public class WebRtcCallService extends Service implements CallConnection.Observe private SignalServiceMessageSender messageSender; private SignalServiceAccountManager accountManager; + private PeerConnectionFactory peerConnectionFactory; private SignalAudioManager audioManager; private BluetoothStateManager bluetoothStateManager; private WiredHeadsetStateReceiver wiredHeadsetStateReceiver; @@ -164,10 +176,10 @@ public class WebRtcCallService extends Service implements CallConnection.Observe @Nullable private Long callId; @Nullable private Recipient recipient; - @Nullable private CallConnectionWrapper callConnection; - @Nullable private CallConnectionFactory callConnectionFactory; - @Nullable private MessageRecipient messageRecipient; - @Nullable private List pendingRemoteIceUpdates; + @Nullable private PeerConnectionWrapper peerConnection; + @Nullable private DataChannel dataChannel; + @Nullable private List pendingOutgoingIceUpdates; + @Nullable private List pendingIncomingIceUpdates; @Nullable private SurfaceViewRenderer localRenderer; @Nullable private SurfaceViewRenderer remoteRenderer; @@ -175,6 +187,7 @@ public class WebRtcCallService extends Service implements CallConnection.Observe private ExecutorService serviceExecutor = Executors.newSingleThreadExecutor(); private ExecutorService networkExecutor = Executors.newSingleThreadExecutor(); + private ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(1); private final PhoneStateListener hangUpRtcOnDeviceCallAnswered = new HangUpRtcOnPstnCallAnsweredListener(); @@ -209,18 +222,18 @@ public class WebRtcCallService extends Service implements CallConnection.Observe else if (intent.getAction().equals(ACTION_REMOTE_HANGUP)) handleRemoteHangup(intent); else if (intent.getAction().equals(ACTION_SET_MUTE_AUDIO)) handleSetMuteAudio(intent); else if (intent.getAction().equals(ACTION_SET_MUTE_VIDEO)) handleSetMuteVideo(intent); - else if (intent.getAction().equals(ACTION_FLIP_CAMERA)) handleSetCameraFlip(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_SCREEN_OFF))) handleScreenOffChange(intent); else if (intent.getAction().equals(ACTION_REMOTE_VIDEO_MUTE)) handleRemoteVideoMute(intent); else if (intent.getAction().equals(ACTION_RESPONSE_MESSAGE)) handleResponseMessage(intent); else if (intent.getAction().equals(ACTION_ICE_MESSAGE)) handleRemoteIceCandidate(intent); - else if (intent.getAction().equals(ACTION_CALL_RINGING)) handleCallRinging(intent); + else if (intent.getAction().equals(ACTION_ICE_CANDIDATE)) handleLocalIceCandidate(intent); + else if (intent.getAction().equals(ACTION_ICE_CONNECTED)) handleIceConnected(intent); else if (intent.getAction().equals(ACTION_CALL_CONNECTED)) handleCallConnected(intent); else if (intent.getAction().equals(ACTION_CHECK_TIMEOUT)) handleCheckTimeout(intent); else if (intent.getAction().equals(ACTION_IS_IN_CALL_QUERY)) handleIsInCallQuery(intent); - else if (intent.getAction().equals(ACTION_CALL_ERROR)) handleCallError(intent); }); return START_NOT_STICKY; @@ -334,17 +347,15 @@ public class WebRtcCallService extends Service implements CallConnection.Observe // Handlers private void handleIncomingCall(final Intent intent) { + Log.i(TAG, "handleIncomingCall()"); if (callState != CallState.STATE_IDLE) throw new IllegalStateException("Incoming on non-idle"); final String offer = intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION); - this.callState = CallState.STATE_ANSWERING; - this.callId = intent.getLongExtra(EXTRA_CALL_ID, -1); - this.pendingRemoteIceUpdates = new LinkedList<>(); - this.recipient = getRemoteRecipient(intent); - this.messageRecipient = new MessageRecipient(messageSender, recipient); - - Log.i(TAG, "handleIncomingCall(): callId: " + callId); + this.callState = CallState.STATE_ANSWERING; + this.callId = intent.getLongExtra(EXTRA_CALL_ID, -1); + this.pendingIncomingIceUpdates = new LinkedList<>(); + this.recipient = getRemoteRecipient(intent); if (isIncomingMessageExpired(intent)) { insertMissedCall(this.recipient, true); @@ -356,62 +367,65 @@ public class WebRtcCallService extends Service implements CallConnection.Observe setCallInProgressNotification(TYPE_INCOMING_CONNECTING, this.recipient); } + timeoutExecutor.schedule(new TimeoutRunnable(this.callId), 2, TimeUnit.MINUTES); + initializeVideo(); - try { - boolean isSystemContact = false; + retrieveTurnServers().addListener(new SuccessOnlyListener>(this.callState, this.callId) { + @Override + public void onSuccessContinue(List result) { + try { + boolean isSystemContact = false; - if (Permissions.hasAny(WebRtcCallService.this, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)) { - isSystemContact = ContactAccessor.getInstance().isSystemContact(WebRtcCallService.this, recipient.getAddress().serialize()); + if (Permissions.hasAny(WebRtcCallService.this, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS)) { + isSystemContact = ContactAccessor.getInstance().isSystemContact(WebRtcCallService.this, recipient.getAddress().serialize()); + } + + boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this); + + WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, WebRtcCallService.this, eglBase, !isSystemContact || isAlwaysTurn); + WebRtcCallService.this.localCameraState = WebRtcCallService.this.peerConnection.getCameraState(); + WebRtcCallService.this.peerConnection.setRemoteDescription(new SessionDescription(SessionDescription.Type.OFFER, offer)); + WebRtcCallService.this.lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING); + + SessionDescription sdp = WebRtcCallService.this.peerConnection.createAnswer(new MediaConstraints()); + Log.i(TAG, "Answer SDP: " + sdp.description); + WebRtcCallService.this.peerConnection.setLocalDescription(sdp); + + ListenableFutureTask listenableFutureTask = sendMessage(recipient, SignalServiceCallMessage.forAnswer(new AnswerMessage(WebRtcCallService.this.callId, sdp.description))); + + for (IceCandidate candidate : pendingIncomingIceUpdates) WebRtcCallService.this.peerConnection.addIceCandidate(candidate); + WebRtcCallService.this.pendingIncomingIceUpdates = null; + + listenableFutureTask.addListener(new FailureListener(WebRtcCallService.this.callState, WebRtcCallService.this.callId) { + @Override + public void onFailureContinue(Throwable error) { + Log.w(TAG, error); + insertMissedCall(recipient, true); + terminate(); + } + }); + + if (recipient != null) { + sendMessage(viewModelStateFor(callState), recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + } + } catch (PeerConnectionException e) { + Log.w(TAG, e); + terminate(); + } } - - boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this); - boolean hideIp = !isSystemContact || isAlwaysTurn; - - this.callConnection = new CallConnectionWrapper(WebRtcCallService.this, - callConnectionFactory, - WebRtcCallService.this, - localRenderer, - WebRtcCallService.this, - eglBase, - hideIp, - callId, - false, - messageRecipient, - accountManager); - - for (IceCandidate candidate : this.pendingRemoteIceUpdates) { - this.callConnection.addIceCandidate(candidate); - } - this.pendingRemoteIceUpdates = null; - - this.localCameraState = callConnection.getCameraState(); - this.lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING); - this.callConnection.acceptOffer(offer); - - sendMessage(viewModelStateFor(callState), recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - } catch (UnregisteredUserException e) { - sendMessage(WebRtcViewModel.State.NO_SUCH_USER, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } catch (IOException e) { - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } catch (CallException e) { - Log.w(TAG, e); - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } + }); } private void handleOutgoingCall(Intent intent) { + Log.i(TAG, "handleOutgoingCall..."); + if (callState != CallState.STATE_IDLE) throw new IllegalStateException("Dialing from non-idle?"); - this.callState = CallState.STATE_DIALING; - this.recipient = getRemoteRecipient(intent); - this.messageRecipient = new MessageRecipient(messageSender, recipient); - this.callId = new SecureRandom().nextLong(); - - Log.i(TAG, "handleOutgoingCall() callId: " + callId); + this.callState = CallState.STATE_DIALING; + this.recipient = getRemoteRecipient(intent); + this.callId = new SecureRandom().nextLong(); + this.pendingOutgoingIceUpdates = new LinkedList<>(); initializeVideo(); @@ -424,84 +438,137 @@ public class WebRtcCallService extends Service implements CallConnection.Observe setCallInProgressNotification(TYPE_OUTGOING_RINGING, recipient); DatabaseFactory.getSmsDatabase(this).insertOutgoingCall(recipient.getAddress()); - try { - this.callConnection = new CallConnectionWrapper(WebRtcCallService.this, - callConnectionFactory, - WebRtcCallService.this, - localRenderer, - WebRtcCallService.this, - eglBase, - TextSecurePreferences.isTurnOnly(WebRtcCallService.this), - callId, - true, - messageRecipient, - accountManager); + timeoutExecutor.schedule(new TimeoutRunnable(this.callId), 2, TimeUnit.MINUTES); - this.localCameraState = callConnection.getCameraState(); - this.callConnection.sendOffer(); - } catch (UnregisteredUserException e) { - sendMessage(WebRtcViewModel.State.NO_SUCH_USER, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } catch (IOException e) { - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } catch (CallException e) { - Log.w(TAG, e); - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } + retrieveTurnServers().addListener(new SuccessOnlyListener>(this.callState, this.callId) { + @Override + public void onSuccessContinue(List result) { + try { + boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this); + + WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, WebRtcCallService.this, eglBase, isAlwaysTurn); + WebRtcCallService.this.localCameraState = WebRtcCallService.this.peerConnection.getCameraState(); + WebRtcCallService.this.dataChannel = WebRtcCallService.this.peerConnection.createDataChannel(DATA_CHANNEL_NAME); + WebRtcCallService.this.dataChannel.registerObserver(WebRtcCallService.this); + + SessionDescription sdp = WebRtcCallService.this.peerConnection.createOffer(new MediaConstraints()); + WebRtcCallService.this.peerConnection.setLocalDescription(sdp); + + Log.i(TAG, "Sending offer: " + sdp.description); + + ListenableFutureTask listenableFutureTask = sendMessage(recipient, SignalServiceCallMessage.forOffer(new OfferMessage(WebRtcCallService.this.callId, sdp.description))); + + listenableFutureTask.addListener(new FailureListener(callState, callId) { + @Override + public void onFailureContinue(Throwable error) { + Log.w(TAG, error); + + if (error instanceof UntrustedIdentityException) { + sendMessage(WebRtcViewModel.State.UNTRUSTED_IDENTITY, recipient, ((UntrustedIdentityException)error).getIdentityKey(), localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + } else if (error instanceof UnregisteredUserException) { + sendMessage(WebRtcViewModel.State.NO_SUCH_USER, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + } else if (error instanceof IOException) { + sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + } + + terminate(); + } + }); + + if (recipient != null) { + sendMessage(viewModelStateFor(callState), recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + } + } catch (PeerConnectionException e) { + Log.w(TAG, e); + terminate(); + } + } + }); } private void handleResponseMessage(Intent intent) { - long callId = getCallId(intent); - try { - Log.i(TAG, "handleResponseMessage(): callId: " + callId + - " Got response: " + intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION)); + Log.i(TAG, "Got response: " + intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION)); - if (this.callConnection == null) { - Log.i(TAG, "Received stale answer while no call in progress"); + if (callState != CallState.STATE_DIALING || !getRemoteRecipient(intent).equals(recipient) || !Util.isEquals(this.callId, getCallId(intent))) { + Log.w(TAG, "Got answer for recipient and call id we're not currently dialing: " + getCallId(intent) + ", " + getRemoteRecipient(intent)); return; } - MessageRecipient messageRecipient = new MessageRecipient(messageSender, getRemoteRecipient(intent)); - if (!this.callConnection.validateResponse(messageRecipient, callId)) { - Log.w(TAG, "Received answer for recipient and call id for inactive call: callId: " + callId); - return; + if (peerConnection == null || pendingOutgoingIceUpdates == null) { + throw new AssertionError("assert"); } - this.callConnection.handleOfferAnswer(intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION)); + if (!pendingOutgoingIceUpdates.isEmpty()) { + ListenableFutureTask listenableFutureTask = sendMessage(recipient, SignalServiceCallMessage.forIceUpdates(pendingOutgoingIceUpdates)); - } catch (CallException e) { + listenableFutureTask.addListener(new FailureListener(callState, callId) { + @Override + public void onFailureContinue(Throwable error) { + Log.w(TAG, error); + sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + + terminate(); + } + }); + } + + this.peerConnection.setRemoteDescription(new SessionDescription(SessionDescription.Type.ANSWER, intent.getStringExtra(EXTRA_REMOTE_DESCRIPTION))); + this.pendingOutgoingIceUpdates = null; + } catch (PeerConnectionException e) { Log.w(TAG, e); - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); terminate(); } } private void handleRemoteIceCandidate(Intent intent) { - long callId = getCallId(intent); + Log.i(TAG, "handleRemoteIceCandidate..."); - Log.i(TAG, "handleRemoteIceCandidate(): callId: " + callId); - - if (Util.isEquals(this.callId, callId)) { + if (Util.isEquals(this.callId, getCallId(intent))) { IceCandidate candidate = new IceCandidate(intent.getStringExtra(EXTRA_ICE_SDP_MID), intent.getIntExtra(EXTRA_ICE_SDP_LINE_INDEX, 0), intent.getStringExtra(EXTRA_ICE_SDP)); - if (this.callConnection != null) { - this.callConnection.addIceCandidate(candidate); - } else if (this.pendingRemoteIceUpdates != null) { - this.pendingRemoteIceUpdates.add(candidate); - } - + if (peerConnection != null) peerConnection.addIceCandidate(candidate); + else if (pendingIncomingIceUpdates != null) pendingIncomingIceUpdates.add(candidate); } } - private void handleCallRinging(Intent intent) { - Log.i(TAG, "handleCallRinging(): state: " + callState.toString()); + private void handleLocalIceCandidate(Intent intent) { + if (callState == CallState.STATE_IDLE || !Util.isEquals(this.callId, getCallId(intent))) { + Log.w(TAG, "State is now idle, ignoring ice candidate..."); + return; + } + + if (recipient == null || callId == null) { + throw new AssertionError("assert: " + callState + ", " + callId); + } + + IceUpdateMessage iceUpdateMessage = new IceUpdateMessage(this.callId, intent.getStringExtra(EXTRA_ICE_SDP_MID), + intent.getIntExtra(EXTRA_ICE_SDP_LINE_INDEX, 0), + intent.getStringExtra(EXTRA_ICE_SDP)); + + if (pendingOutgoingIceUpdates != null) { + Log.i(TAG, "Adding to pending ice candidates..."); + this.pendingOutgoingIceUpdates.add(iceUpdateMessage); + return; + } + + ListenableFutureTask listenableFutureTask = sendMessage(recipient, SignalServiceCallMessage.forIceUpdate(iceUpdateMessage)); + + listenableFutureTask.addListener(new FailureListener(callState, callId) { + @Override + public void onFailureContinue(Throwable error) { + Log.w(TAG, error); + sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); + + terminate(); + } + }); + } + + private void handleIceConnected(Intent intent) { if (callState == CallState.STATE_ANSWERING) { - Log.i(TAG, "handleCallRinging(): STATE_ANSWERING"); if (this.recipient == null) throw new AssertionError("assert"); this.callState = CallState.STATE_LOCAL_RINGING; @@ -524,7 +591,6 @@ public class WebRtcCallService extends Service implements CallConnection.Observe setCallInProgressNotification(TYPE_INCOMING_RINGING, recipient); } else if (callState == CallState.STATE_DIALING) { - Log.i(TAG, "handleCallRinging(): STATE_DIALING"); if (this.recipient == null) throw new AssertionError("assert"); this.callState = CallState.STATE_REMOTE_RINGING; @@ -534,7 +600,6 @@ public class WebRtcCallService extends Service implements CallConnection.Observe } private void handleCallConnected(Intent intent) { - Log.i(TAG, "handleCallConnected()"); if (callState != CallState.STATE_REMOTE_RINGING && callState != CallState.STATE_LOCAL_RINGING) { Log.w(TAG, "Ignoring call connected for unknown state: " + callState); return; @@ -545,7 +610,7 @@ public class WebRtcCallService extends Service implements CallConnection.Observe return; } - if (recipient == null || this.callConnection == null) { + if (recipient == null || peerConnection == null || dataChannel == null) { throw new AssertionError("assert"); } @@ -563,24 +628,21 @@ public class WebRtcCallService extends Service implements CallConnection.Observe setCallInProgressNotification(TYPE_ESTABLISHED, recipient); - try { - this.callConnection.setCommunicationMode(); - this.callConnection.setAudioEnabled(microphoneEnabled); - this.callConnection.setVideoEnabled(localCameraState.isEnabled()); - } catch (CallException e) { - Log.w(TAG, e); - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } + this.peerConnection.setCommunicationMode(); + this.peerConnection.setAudioEnabled(microphoneEnabled); + this.peerConnection.setVideoEnabled(localCameraState.isEnabled()); + this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder() + .setVideoStreamingStatus(WebRtcDataProtos.VideoStreamingStatus.newBuilder() + .setId(this.callId) + .setEnabled(localCameraState.isEnabled())) + .build().toByteArray()), false)); } private void handleBusyCall(Intent intent) { Recipient recipient = getRemoteRecipient(intent); long callId = getCallId(intent); - Log.i(TAG, "handleBusyCall() callId: " + callId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { switch (callState) { case STATE_DIALING: @@ -602,11 +664,11 @@ public class WebRtcCallService extends Service implements CallConnection.Observe } private void handleBusyMessage(Intent intent) { + Log.i(TAG, "handleBusyMessage..."); + final Recipient recipient = getRemoteRecipient(intent); final long callId = getCallId(intent); - Log.i(TAG, "handleBusyMessage(): callId: " + callId); - if (callState != CallState.STATE_DIALING || !Util.isEquals(this.callId, callId) || !recipient.equals(this.recipient)) { Log.w(TAG, "Got busy message for inactive session..."); return; @@ -663,24 +725,19 @@ public class WebRtcCallService extends Service implements CallConnection.Observe return; } - if (this.callConnection == null || recipient == null || callId == null) { + if (peerConnection == null || dataChannel == null || recipient == null || callId == null) { throw new AssertionError("assert"); } DatabaseFactory.getSmsDatabase(this).insertReceivedCall(recipient.getAddress()); - try { - Log.i(TAG, "handleAnswerCall()"); - this.callConnection.answerCall(); - intent.putExtra(EXTRA_CALL_ID, callId); - intent.putExtra(EXTRA_REMOTE_ADDRESS, recipient.getAddress()); - handleCallConnected(intent); - } catch (CallException e) { - Log.w(TAG, e); - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } + this.peerConnection.setAudioEnabled(true); + this.peerConnection.setVideoEnabled(false); + this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder().setConnected(Connected.newBuilder().setId(this.callId)).build().toByteArray()), false)); + intent.putExtra(EXTRA_CALL_ID, callId); + intent.putExtra(EXTRA_REMOTE_ADDRESS, recipient.getAddress()); + handleCallConnected(intent); } private void handleDenyCall(Intent intent) { @@ -689,44 +746,33 @@ public class WebRtcCallService extends Service implements CallConnection.Observe return; } - if (recipient == null || callId == null) { + if (recipient == null || callId == null || dataChannel == null) { throw new AssertionError("assert"); } - try { - Log.i(TAG, "handleDenyCall()"); - this.callConnection.hangUp(); - DatabaseFactory.getSmsDatabase(this).insertMissedCall(recipient.getAddress()); - } catch (CallException e) { - Log.w(TAG, e); - } + this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder().setHangup(Hangup.newBuilder().setId(this.callId)).build().toByteArray()), false)); + sendMessage(this.recipient, SignalServiceCallMessage.forHangup(new HangupMessage(this.callId))); - terminate(); + DatabaseFactory.getSmsDatabase(this).insertMissedCall(recipient.getAddress()); + + this.terminate(); } private void handleLocalHangup(Intent intent) { - if (this.recipient != null && this.callId != null) { + if (this.dataChannel != null && this.recipient != null && this.callId != null) { this.accountManager.cancelInFlightRequests(); this.messageSender.cancelInFlightRequests(); - try { - Log.i(TAG, "handleLocalHangup()"); - this.callConnection.hangUp(); - sendMessage(WebRtcViewModel.State.CALL_DISCONNECTED, this.recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - } catch (CallException e) { - Log.w(TAG, e); - } + this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder().setHangup(Hangup.newBuilder().setId(this.callId)).build().toByteArray()), false)); + sendMessage(this.recipient, SignalServiceCallMessage.forHangup(new HangupMessage(this.callId))); + sendMessage(WebRtcViewModel.State.CALL_DISCONNECTED, this.recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); } terminate(); } private void handleRemoteHangup(Intent intent) { - - long callId = getCallId(intent); - Log.i(TAG, "handleRemoteHangup(): callId: " + callId); - - if (!Util.isEquals(this.callId, callId)) { + if (!Util.isEquals(this.callId, getCallId(intent))) { Log.w(TAG, "hangup for non-active call..."); return; } @@ -745,15 +791,15 @@ public class WebRtcCallService extends Service implements CallConnection.Observe insertMissedCall(this.recipient, true); } - terminate(); + this.terminate(); } private void handleSetMuteAudio(Intent intent) { boolean muted = intent.getBooleanExtra(EXTRA_MUTE, false); this.microphoneEnabled = !muted; - if (this.callConnection != null) { - this.callConnection.setAudioEnabled(this.microphoneEnabled); + if (this.peerConnection != null) { + this.peerConnection.setAudioEnabled(this.microphoneEnabled); } if (recipient != null) { @@ -765,15 +811,17 @@ public class WebRtcCallService extends Service implements CallConnection.Observe AudioManager audioManager = ServiceUtil.getAudioManager(this); boolean muted = intent.getBooleanExtra(EXTRA_MUTE, false); - if (this.callConnection != null) { - try { - this.callConnection.setVideoEnabled(!muted); - this.localCameraState = this.callConnection.getCameraState(); - } catch (CallException e) { - Log.w(TAG, e); - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - terminate(); - } + if (this.peerConnection != null) { + this.peerConnection.setVideoEnabled(!muted); + this.localCameraState = this.peerConnection.getCameraState(); + } + + if (this.callId != null && this.dataChannel != null) { + this.dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(Data.newBuilder() + .setVideoStreamingStatus(WebRtcDataProtos.VideoStreamingStatus.newBuilder() + .setId(this.callId) + .setEnabled(!muted)) + .build().toByteArray()), false)); } if (callState == CallState.STATE_CONNECTED) { @@ -795,9 +843,9 @@ public class WebRtcCallService extends Service implements CallConnection.Observe private void handleSetCameraFlip(Intent intent) { Log.i(TAG, "handleSetCameraFlip()..."); - if (localCameraState.isEnabled() && this.callConnection != null) { - this.callConnection.flipCamera(); - localCameraState = this.callConnection.getCameraState(); + if (localCameraState.isEnabled() && peerConnection != null) { + peerConnection.flipCamera(); + localCameraState = peerConnection.getCameraState(); if (recipient != null) { sendMessage(viewModelStateFor(callState), recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); } @@ -845,7 +893,6 @@ public class WebRtcCallService extends Service implements CallConnection.Observe } private void handleRemoteVideoMute(Intent intent) { - Log.i(TAG, "handleRemoteVideoMute()"); boolean muted = intent.getBooleanExtra(EXTRA_MUTE, false); long callId = intent.getLongExtra(EXTRA_CALL_ID, -1); @@ -858,44 +905,6 @@ public class WebRtcCallService extends Service implements CallConnection.Observe sendMessage(WebRtcViewModel.State.CALL_CONNECTED, this.recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); } - private void handleCallError(Intent intent) { - Recipient recipient = getRemoteRecipient(intent); - long callId = getCallId(intent); - int error_num = intent.getIntExtra(EXTRA_CALL_ERROR, -1); - CallError error = CallError.fromNativeIndex(error_num); - - if (this.recipient == null || !Util.isEquals(this.callId, callId)) { - Log.w(TAG, "Got call error for inactive call, ignoring..."); - return; - } - - if (this.callState == CallState.STATE_ANSWERING || this.callState == CallState.STATE_LOCAL_RINGING) { - insertMissedCall(this.recipient, true); - } - - switch (error) { - case UNREGISTERED_USER: - sendMessage(WebRtcViewModel.State.NO_SUCH_USER, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - break; - case UNTRUSTED_IDENTITY: - try { - byte[] identityKeyBytes = intent.getByteArrayExtra(EXTRA_IDENTITY_KEY_BYTES); - IdentityKey key = new IdentityKey(identityKeyBytes, 0); - sendMessage(WebRtcViewModel.State.UNTRUSTED_IDENTITY, recipient, key, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - } catch (InvalidKeyException e) { - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - } - break; - case NETWORK_FAILURE: - case INTERNAL_FAILURE: - case FAILURE: - sendMessage(WebRtcViewModel.State.NETWORK_FAILURE, recipient, localCameraState, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled); - break; - } - terminate(); - - } - /// Helper Methods private boolean isBusy() { @@ -912,7 +921,6 @@ public class WebRtcCallService extends Service implements CallConnection.Observe private void initializeVideo() { Util.runOnMainSync(() -> { - eglBase = EglBase.create(); localRenderer = new SurfaceViewRenderer(WebRtcCallService.this); remoteRenderer = new SurfaceViewRenderer(WebRtcCallService.this); @@ -920,14 +928,14 @@ public class WebRtcCallService extends Service implements CallConnection.Observe localRenderer.init(eglBase.getEglBaseContext(), null); remoteRenderer.init(eglBase.getEglBaseContext(), null); - VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), - true, true); + VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), true, true); VideoDecoderFactory decoderFactory = new DefaultVideoDecoderFactory(eglBase.getEglBaseContext()); - callConnectionFactory = CallConnectionFactory.createCallConnectionFactory(WebRtcCallService.this, - encoderFactory, - decoderFactory); - + peerConnectionFactory = PeerConnectionFactory.builder() + .setOptions(new PeerConnectionFactoryOptions()) + .setVideoEncoderFactory(encoderFactory) + .setVideoDecoderFactory(decoderFactory) + .createPeerConnectionFactory(); }); } @@ -937,22 +945,15 @@ public class WebRtcCallService extends Service implements CallConnection.Observe } private synchronized void terminate() { - Log.i(TAG, "terminate()"); - lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING); stopForeground(true); audioManager.stop(callState == CallState.STATE_DIALING || callState == CallState.STATE_REMOTE_RINGING || callState == CallState.STATE_CONNECTED); bluetoothStateManager.setWantsConnection(false); - if (callConnection != null) { - callConnection.dispose(); - callConnection = null; - } - - if (callConnectionFactory != null) { - callConnectionFactory.dispose(); - callConnectionFactory = null; + if (peerConnection != null) { + peerConnection.dispose(); + peerConnection = null; } if (eglBase != null && localRenderer != null && remoteRenderer != null) { @@ -971,7 +972,8 @@ public class WebRtcCallService extends Service implements CallConnection.Observe this.callId = null; this.microphoneEnabled = true; this.remoteVideoEnabled = false; - this.pendingRemoteIceUpdates = null; + this.pendingOutgoingIceUpdates = null; + this.pendingIncomingIceUpdates = null; lockManager.updatePhoneState(LockManager.PhoneState.IDLE); } @@ -983,14 +985,7 @@ public class WebRtcCallService extends Service implements CallConnection.Observe boolean bluetoothAvailable, boolean microphoneEnabled) { - EventBus.getDefault().postSticky(new WebRtcViewModel(state, - recipient, - localCameraState, - localRenderer, - remoteRenderer, - remoteVideoEnabled, - bluetoothAvailable, - microphoneEnabled)); + EventBus.getDefault().postSticky(new WebRtcViewModel(state, recipient, localCameraState, localRenderer, remoteRenderer, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled)); } private void sendMessage(@NonNull WebRtcViewModel.State state, @@ -1001,15 +996,7 @@ public class WebRtcCallService extends Service implements CallConnection.Observe boolean bluetoothAvailable, boolean microphoneEnabled) { - EventBus.getDefault().postSticky(new WebRtcViewModel(state, - recipient, - identityKey, - localCameraState, - localRenderer, - remoteRenderer, - remoteVideoEnabled, - bluetoothAvailable, - microphoneEnabled)); + EventBus.getDefault().postSticky(new WebRtcViewModel(state, recipient, identityKey, localCameraState, localRenderer, remoteRenderer, remoteVideoEnabled, bluetoothAvailable, microphoneEnabled)); } private ListenableFutureTask sendMessage(@NonNull final Recipient recipient, @@ -1055,12 +1042,185 @@ public class WebRtcCallService extends Service implements CallConnection.Observe return intent.getLongExtra(EXTRA_CALL_ID, -1); } + @Nullable @Override public IBinder onBind(Intent intent) { return null; } + /// PeerConnection Observer + @Override + public void onSignalingChange(PeerConnection.SignalingState newState) { + Log.i(TAG, "onSignalingChange: " + newState); + } + + @Override + public void onIceConnectionChange(PeerConnection.IceConnectionState newState) { + Log.i(TAG, "onIceConnectionChange:" + newState); + + if (newState == PeerConnection.IceConnectionState.CONNECTED || + newState == PeerConnection.IceConnectionState.COMPLETED) + { + Intent intent = new Intent(this, WebRtcCallService.class); + intent.setAction(ACTION_ICE_CONNECTED); + + startService(intent); + } else if (newState == PeerConnection.IceConnectionState.FAILED) { + Intent intent = new Intent(this, WebRtcCallService.class); + intent.setAction(ACTION_REMOTE_HANGUP); + intent.putExtra(EXTRA_CALL_ID, this.callId); + + startService(intent); + } + } + + @Override + public void onIceConnectionReceivingChange(boolean receiving) { + Log.i(TAG, "onIceConnectionReceivingChange:" + receiving); + } + + @Override + public void onIceGatheringChange(PeerConnection.IceGatheringState newState) { + Log.i(TAG, "onIceGatheringChange:" + newState); + + } + + @Override + public void onIceCandidate(IceCandidate candidate) { + Log.i(TAG, "onIceCandidate:" + candidate); + Intent intent = new Intent(this, WebRtcCallService.class); + + intent.setAction(ACTION_ICE_CANDIDATE); + intent.putExtra(EXTRA_ICE_SDP_MID, candidate.sdpMid); + intent.putExtra(EXTRA_ICE_SDP_LINE_INDEX, candidate.sdpMLineIndex); + intent.putExtra(EXTRA_ICE_SDP, candidate.sdp); + intent.putExtra(EXTRA_CALL_ID, callId); + + startService(intent); + } + + @Override + public void onIceCandidatesRemoved(IceCandidate[] candidates) { + Log.i(TAG, "onIceCandidatesRemoved:" + (candidates != null ? candidates.length : null)); + } + + @Override + public void onAddStream(MediaStream stream) { + Log.i(TAG, "onAddStream:" + stream); + + for (AudioTrack audioTrack : stream.audioTracks) { + audioTrack.setEnabled(true); + } + + if (stream.videoTracks != null && stream.videoTracks.size() == 1) { + VideoTrack videoTrack = stream.videoTracks.get(0); + videoTrack.setEnabled(true); + videoTrack.addSink(remoteRenderer); + } + } + + @Override + public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) { + Log.i(TAG, "onAddTrack: " + mediaStreams); + } + + @Override + public void onRemoveStream(MediaStream stream) { + Log.i(TAG, "onRemoveStream:" + stream); + } + + @Override + public void onDataChannel(DataChannel dataChannel) { + Log.i(TAG, "onDataChannel:" + dataChannel.label()); + + if (dataChannel.label().equals(DATA_CHANNEL_NAME)) { + this.dataChannel = dataChannel; + this.dataChannel.registerObserver(this); + } + } + + @Override + public void onRenegotiationNeeded() { + Log.i(TAG, "onRenegotiationNeeded"); + // TODO renegotiate + } + + @Override + public void onBufferedAmountChange(long l) { + Log.i(TAG, "onBufferedAmountChange: " + l); + } + + @Override + public void onStateChange() { + Log.i(TAG, "onStateChange"); + } + + @Override + public void onMessage(DataChannel.Buffer buffer) { + Log.i(TAG, "onMessage..."); + + try { + byte[] data = new byte[buffer.data.remaining()]; + buffer.data.get(data); + + Data dataMessage = Data.parseFrom(data); + + if (dataMessage.hasConnected()) { + Log.i(TAG, "hasConnected..."); + Intent intent = new Intent(this, WebRtcCallService.class); + intent.setAction(ACTION_CALL_CONNECTED); + intent.putExtra(EXTRA_CALL_ID, dataMessage.getConnected().getId()); + startService(intent); + } else if (dataMessage.hasHangup()) { + Log.i(TAG, "hasHangup..."); + Intent intent = new Intent(this, WebRtcCallService.class); + intent.setAction(ACTION_REMOTE_HANGUP); + intent.putExtra(EXTRA_CALL_ID, dataMessage.getHangup().getId()); + startService(intent); + } else if (dataMessage.hasVideoStreamingStatus()) { + Log.i(TAG, "hasVideoStreamingStatus..."); + Intent intent = new Intent(this, WebRtcCallService.class); + intent.setAction(ACTION_REMOTE_VIDEO_MUTE); + intent.putExtra(EXTRA_CALL_ID, dataMessage.getVideoStreamingStatus().getId()); + intent.putExtra(EXTRA_MUTE, !dataMessage.getVideoStreamingStatus().getEnabled()); + startService(intent); + } + } catch (InvalidProtocolBufferException e) { + Log.w(TAG, e); + } + } + + private ListenableFutureTask> retrieveTurnServers() { + Callable> callable = () -> { + LinkedList results = new LinkedList<>(); + + try { + TurnServerInfo turnServerInfo = accountManager.getTurnServerInfo(); + + for (String url : turnServerInfo.getUrls()) { + if (url.startsWith("turn")) { + results.add(new PeerConnection.IceServer(url, turnServerInfo.getUsername(), turnServerInfo.getPassword())); + } else { + results.add(new PeerConnection.IceServer(url)); + } + } + + } catch (IOException e) { + Log.w(TAG, e); + } + + return results; + }; + + ListenableFutureTask> futureTask = new ListenableFutureTask<>(callable, null, serviceExecutor); + networkExecutor.execute(futureTask); + + return futureTask; + } + + //// + private WebRtcViewModel.State viewModelStateFor(CallState state) { switch (state) { case STATE_CONNECTED: return WebRtcViewModel.State.CALL_CONNECTED; @@ -1099,6 +1259,22 @@ public class WebRtcCallService extends Service implements CallConnection.Observe } } + private class TimeoutRunnable implements Runnable { + + private final long callId; + + private TimeoutRunnable(long callId) { + this.callId = callId; + } + + public void run() { + Intent intent = new Intent(WebRtcCallService.this, WebRtcCallService.class); + intent.setAction(WebRtcCallService.ACTION_CHECK_TIMEOUT); + intent.putExtra(EXTRA_CALL_ID, callId); + startService(intent); + } + } + private static class ProximityLockRelease implements Thread.UncaughtExceptionHandler { private final LockManager lockManager; @@ -1233,100 +1409,4 @@ public class WebRtcCallService extends Service implements CallConnection.Observe startService(intent); } } - - @Override - public void onCallEvent(SignalMessageRecipient eventRecipient, - long callId, - CallConnection.CallEvent event) { - Log.i(TAG, "handling onCallEvent(): " + callId + ", event: " + event.toString()); - if (eventRecipient instanceof MessageRecipient) { - MessageRecipient recipient = (MessageRecipient)eventRecipient; - - Intent intent = new Intent(this, WebRtcCallService.class); - intent.putExtra(EXTRA_CALL_ID, callId); - - switch (event) { - case RINGING: - intent.setAction(ACTION_CALL_RINGING); - break; - case REMOTE_CONNECTED: - intent.setAction(ACTION_CALL_CONNECTED); - break; - case REMOTE_VIDEO_ENABLE: - intent.setAction(ACTION_REMOTE_VIDEO_MUTE); - intent.putExtra(EXTRA_MUTE, false); - break; - case REMOTE_VIDEO_DISABLE: - intent.setAction(ACTION_REMOTE_VIDEO_MUTE); - intent.putExtra(EXTRA_MUTE, true); - break; - case REMOTE_HANGUP: - case CALL_DISCONNECTED: - intent.setAction(ACTION_REMOTE_HANGUP); - break; - case CALL_TIMEOUT: - intent.setAction(ACTION_CHECK_TIMEOUT); - break; - default: - Log.e(TAG, "handling onCallEvent(): Unexpected event type" + event.toString()); - return; - } - startService(intent); - } else { - Log.e(TAG, "handling onCallEvent(): Unexpected recipient type"); - } - } - - @Override - public void onCallError(SignalMessageRecipient eventRecipient, - long callId, - Exception error) { - Log.i(TAG, "handling onCallError(): " + callId + ", error: " + error.toString()); - if (eventRecipient instanceof SignalMessageRecipient) { - MessageRecipient recipient = (MessageRecipient)eventRecipient; - - Intent intent = new Intent(this, WebRtcCallService.class); - intent.setAction(ACTION_CALL_ERROR); - intent.putExtra(EXTRA_CALL_ID, callId); - intent.putExtra(EXTRA_REMOTE_ADDRESS, recipient.getAddress()); - - if (error instanceof UntrustedIdentityException) { - intent.putExtra(EXTRA_CALL_ERROR, CallError.UNTRUSTED_IDENTITY.ordinal()); - byte[] identityKeyBytes = ((UntrustedIdentityException)error).getIdentityKey().serialize(); - intent.putExtra(EXTRA_IDENTITY_KEY_BYTES, identityKeyBytes); - } else if (error instanceof UnregisteredUserException) { - intent.putExtra(EXTRA_CALL_ERROR, CallError.UNREGISTERED_USER.ordinal()); - } else if (error instanceof IOException) { - intent.putExtra(EXTRA_CALL_ERROR, CallError.NETWORK_FAILURE.ordinal()); - } else if (error instanceof CallException) { - intent.putExtra(EXTRA_CALL_ERROR, CallError.INTERNAL_FAILURE.ordinal()); - } else { - intent.putExtra(EXTRA_CALL_ERROR, CallError.FAILURE.ordinal()); - } - startService(intent); - - } else { - Log.e(TAG, "handling onCallError(): Unexpected recipient type"); - } - } - - @Override - public void onAddStream(SignalMessageRecipient eventRecipient, - long callId, - MediaStream stream) { - Log.i(TAG, "onAddStream: callId: " + callId + ", stream: " + stream); - - for (AudioTrack audioTrack : stream.audioTracks) { - Log.i(TAG, "onAddStream: enabling audioTrack"); - audioTrack.setEnabled(true); - } - - if (stream.videoTracks != null && stream.videoTracks.size() == 1) { - Log.i(TAG, "onAddStream: enabling videoTrack"); - VideoTrack videoTrack = stream.videoTracks.get(0); - videoTrack.setEnabled(true); - videoTrack.addSink(remoteRenderer); - } - } - } diff --git a/src/org/thoughtcrime/securesms/ringrtc/CameraState.java b/src/org/thoughtcrime/securesms/webrtc/CameraState.java similarity index 93% rename from src/org/thoughtcrime/securesms/ringrtc/CameraState.java rename to src/org/thoughtcrime/securesms/webrtc/CameraState.java index ee7e1717e..b2f5d1ee0 100644 --- a/src/org/thoughtcrime/securesms/ringrtc/CameraState.java +++ b/src/org/thoughtcrime/securesms/webrtc/CameraState.java @@ -1,4 +1,4 @@ -package org.thoughtcrime.securesms.ringrtc; +package org.thoughtcrime.securesms.webrtc; import androidx.annotation.NonNull; diff --git a/src/org/thoughtcrime/securesms/webrtc/PeerConnectionFactoryOptions.java b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionFactoryOptions.java new file mode 100644 index 000000000..10fdb39e5 --- /dev/null +++ b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionFactoryOptions.java @@ -0,0 +1,11 @@ +package org.thoughtcrime.securesms.webrtc; + + +import org.webrtc.PeerConnectionFactory; + +public class PeerConnectionFactoryOptions extends PeerConnectionFactory.Options { + + public PeerConnectionFactoryOptions() { + this.networkIgnoreMask = 1 << 4; + } +} diff --git a/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java new file mode 100644 index 000000000..d4e0fdb65 --- /dev/null +++ b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java @@ -0,0 +1,424 @@ +package org.thoughtcrime.securesms.webrtc; + + +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import org.thoughtcrime.securesms.logging.Log; + +import org.thoughtcrime.securesms.util.concurrent.SettableFuture; +import org.webrtc.AudioSource; +import org.webrtc.AudioTrack; +import org.webrtc.Camera1Enumerator; +import org.webrtc.Camera2Enumerator; +import org.webrtc.CameraEnumerator; +import org.webrtc.CameraVideoCapturer; +import org.webrtc.DataChannel; +import org.webrtc.EglBase; +import org.webrtc.IceCandidate; +import org.webrtc.MediaConstraints; +import org.webrtc.MediaStream; +import org.webrtc.PeerConnection; +import org.webrtc.PeerConnectionFactory; +import org.webrtc.SdpObserver; +import org.webrtc.SessionDescription; +import org.webrtc.SurfaceTextureHelper; +import org.webrtc.VideoSink; +import org.webrtc.VideoSource; +import org.webrtc.VideoTrack; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.thoughtcrime.securesms.webrtc.CameraState.Direction.BACK; +import static org.thoughtcrime.securesms.webrtc.CameraState.Direction.FRONT; +import static org.thoughtcrime.securesms.webrtc.CameraState.Direction.NONE; +import static org.thoughtcrime.securesms.webrtc.CameraState.Direction.PENDING; + +public class PeerConnectionWrapper { + private static final String TAG = PeerConnectionWrapper.class.getSimpleName(); + + private static final PeerConnection.IceServer STUN_SERVER = new PeerConnection.IceServer("stun:stun1.l.google.com:19302"); + + @NonNull private final PeerConnection peerConnection; + @NonNull private final AudioTrack audioTrack; + @NonNull private final AudioSource audioSource; + @NonNull private final Camera camera; + @Nullable private final VideoSource videoSource; + @Nullable private final VideoTrack videoTrack; + + public PeerConnectionWrapper(@NonNull Context context, + @NonNull PeerConnectionFactory factory, + @NonNull PeerConnection.Observer observer, + @NonNull VideoSink localRenderer, + @NonNull List turnServers, + @NonNull CameraEventListener cameraEventListener, + @NonNull EglBase eglBase, + boolean hideIp) + { + List iceServers = new LinkedList<>(); + iceServers.add(STUN_SERVER); + iceServers.addAll(turnServers); + + MediaConstraints constraints = new MediaConstraints(); + MediaConstraints audioConstraints = new MediaConstraints(); + PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServers); + + configuration.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE; + configuration.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE; + + if (hideIp) { + configuration.iceTransportsType = PeerConnection.IceTransportsType.RELAY; + } + + constraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); + audioConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); + + this.peerConnection = factory.createPeerConnection(configuration, constraints, observer); + this.peerConnection.setAudioPlayout(false); + this.peerConnection.setAudioRecording(false); + + MediaStream mediaStream = factory.createLocalMediaStream("ARDAMS"); + this.audioSource = factory.createAudioSource(audioConstraints); + this.audioTrack = factory.createAudioTrack("ARDAMSa0", audioSource); + this.audioTrack.setEnabled(false); + mediaStream.addTrack(audioTrack); + + this.camera = new Camera(context, cameraEventListener); + + if (camera.capturer != null) { + this.videoSource = factory.createVideoSource(false); + this.videoTrack = factory.createVideoTrack("ARDAMSv0", videoSource); + + camera.capturer.initialize(SurfaceTextureHelper.create("WebRTC-SurfaceTextureHelper", eglBase.getEglBaseContext()), context, videoSource.getCapturerObserver()); + + this.videoTrack.addSink(localRenderer); + this.videoTrack.setEnabled(false); + mediaStream.addTrack(videoTrack); + } else { + this.videoSource = null; + this.videoTrack = null; + } + + this.peerConnection.addStream(mediaStream); + } + + public void setVideoEnabled(boolean enabled) { + if (this.videoTrack != null) { + this.videoTrack.setEnabled(enabled); + } + camera.setEnabled(enabled); + } + + public void flipCamera() { + camera.flip(); + } + + public CameraState getCameraState() { + return new CameraState(camera.getActiveDirection(), camera.getCount()); + } + + public void setCommunicationMode() { + this.peerConnection.setAudioPlayout(true); + this.peerConnection.setAudioRecording(true); + } + + public void setAudioEnabled(boolean enabled) { + this.audioTrack.setEnabled(enabled); + } + + public DataChannel createDataChannel(String name) { + DataChannel.Init dataChannelConfiguration = new DataChannel.Init(); + dataChannelConfiguration.ordered = true; + + return this.peerConnection.createDataChannel(name, dataChannelConfiguration); + } + + public SessionDescription createOffer(MediaConstraints mediaConstraints) throws PeerConnectionException { + final SettableFuture future = new SettableFuture<>(); + + peerConnection.createOffer(new SdpObserver() { + @Override + public void onCreateSuccess(SessionDescription sdp) { + future.set(sdp); + } + + @Override + public void onCreateFailure(String error) { + future.setException(new PeerConnectionException(error)); + } + + @Override + public void onSetSuccess() { + throw new AssertionError(); + } + + @Override + public void onSetFailure(String error) { + throw new AssertionError(); + } + }, mediaConstraints); + + try { + return correctSessionDescription(future.get()); + } catch (InterruptedException e) { + throw new AssertionError(e); + } catch (ExecutionException e) { + throw new PeerConnectionException(e); + } + } + + public SessionDescription createAnswer(MediaConstraints mediaConstraints) throws PeerConnectionException { + final SettableFuture future = new SettableFuture<>(); + + peerConnection.createAnswer(new SdpObserver() { + @Override + public void onCreateSuccess(SessionDescription sdp) { + future.set(sdp); + } + + @Override + public void onCreateFailure(String error) { + future.setException(new PeerConnectionException(error)); + } + + @Override + public void onSetSuccess() { + throw new AssertionError(); + } + + @Override + public void onSetFailure(String error) { + throw new AssertionError(); + } + }, mediaConstraints); + + try { + return correctSessionDescription(future.get()); + } catch (InterruptedException e) { + throw new AssertionError(e); + } catch (ExecutionException e) { + throw new PeerConnectionException(e); + } + } + + public void setRemoteDescription(SessionDescription sdp) throws PeerConnectionException { + final SettableFuture future = new SettableFuture<>(); + + peerConnection.setRemoteDescription(new SdpObserver() { + @Override + public void onCreateSuccess(SessionDescription sdp) {} + + @Override + public void onCreateFailure(String error) {} + + @Override + public void onSetSuccess() { + future.set(true); + } + + @Override + public void onSetFailure(String error) { + future.setException(new PeerConnectionException(error)); + } + }, sdp); + + try { + future.get(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } catch (ExecutionException e) { + throw new PeerConnectionException(e); + } + } + + public void setLocalDescription(SessionDescription sdp) throws PeerConnectionException { + final SettableFuture future = new SettableFuture<>(); + + peerConnection.setLocalDescription(new SdpObserver() { + @Override + public void onCreateSuccess(SessionDescription sdp) { + throw new AssertionError(); + } + + @Override + public void onCreateFailure(String error) { + throw new AssertionError(); + } + + @Override + public void onSetSuccess() { + future.set(true); + } + + @Override + public void onSetFailure(String error) { + future.setException(new PeerConnectionException(error)); + } + }, sdp); + + try { + future.get(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } catch (ExecutionException e) { + throw new PeerConnectionException(e); + } + } + + public void dispose() { + this.camera.dispose(); + + if (this.videoSource != null) { + this.videoSource.dispose(); + } + + this.audioSource.dispose(); + this.peerConnection.close(); + this.peerConnection.dispose(); + } + + public boolean addIceCandidate(IceCandidate candidate) { + return this.peerConnection.addIceCandidate(candidate); + } + + + private SessionDescription correctSessionDescription(SessionDescription sessionDescription) { + String updatedSdp = sessionDescription.description.replaceAll("(a=fmtp:111 ((?!cbr=).)*)\r?\n", "$1;cbr=1\r\n"); + updatedSdp = updatedSdp.replaceAll(".+urn:ietf:params:rtp-hdrext:ssrc-audio-level.*\r?\n", ""); + + return new SessionDescription(sessionDescription.type, updatedSdp); + } + + public static class PeerConnectionException extends Exception { + public PeerConnectionException(String error) { + super(error); + } + + public PeerConnectionException(Throwable throwable) { + super(throwable); + } + } + + private static class Camera implements CameraVideoCapturer.CameraSwitchHandler { + + @Nullable + private final CameraVideoCapturer capturer; + private final CameraEventListener cameraEventListener; + private final int cameraCount; + + private CameraState.Direction activeDirection; + private boolean enabled; + + Camera(@NonNull Context context, @NonNull CameraEventListener cameraEventListener) + { + this.cameraEventListener = cameraEventListener; + CameraEnumerator enumerator = getCameraEnumerator(context); + cameraCount = enumerator.getDeviceNames().length; + + CameraVideoCapturer capturerCandidate = createVideoCapturer(enumerator, FRONT); + if (capturerCandidate != null) { + activeDirection = FRONT; + } else { + capturerCandidate = createVideoCapturer(enumerator, BACK); + if (capturerCandidate != null) { + activeDirection = BACK; + } else { + activeDirection = NONE; + } + } + capturer = capturerCandidate; + } + + void flip() { + if (capturer == null || cameraCount < 2) { + Log.w(TAG, "Tried to flip the camera, but we only have " + cameraCount + " of them."); + return; + } + activeDirection = PENDING; + capturer.switchCamera(this); + } + + void setEnabled(boolean enabled) { + this.enabled = enabled; + + if (capturer == null) { + return; + } + + try { + if (enabled) { + capturer.startCapture(1280, 720, 30); + } else { + capturer.stopCapture(); + } + } catch (InterruptedException e) { + Log.w(TAG, "Got interrupted while trying to stop video capture", e); + } + } + + void dispose() { + if (capturer != null) { + capturer.dispose(); + } + } + + int getCount() { + return cameraCount; + } + + @NonNull CameraState.Direction getActiveDirection() { + return enabled ? activeDirection : NONE; + } + + @Nullable CameraVideoCapturer getCapturer() { + return capturer; + } + + private @Nullable CameraVideoCapturer createVideoCapturer(@NonNull CameraEnumerator enumerator, + @NonNull CameraState.Direction direction) + { + String[] deviceNames = enumerator.getDeviceNames(); + for (String deviceName : deviceNames) { + if ((direction == FRONT && enumerator.isFrontFacing(deviceName)) || + (direction == BACK && enumerator.isBackFacing(deviceName))) + { + return enumerator.createCapturer(deviceName, null); + } + } + + return null; + } + + private @NonNull CameraEnumerator getCameraEnumerator(@NonNull Context context) { + boolean camera2EnumeratorIsSupported = false; + try { + camera2EnumeratorIsSupported = Camera2Enumerator.isSupported(context); + } catch (final Throwable throwable) { + Log.w(TAG, "Camera2Enumator.isSupport() threw.", throwable); + } + + Log.i(TAG, "Camera2 enumerator supported: " + camera2EnumeratorIsSupported); + + return camera2EnumeratorIsSupported ? new Camera2Enumerator(context) + : new Camera1Enumerator(true); + } + + @Override + public void onCameraSwitchDone(boolean isFrontFacing) { + activeDirection = isFrontFacing ? FRONT : BACK; + cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount())); + } + + @Override + public void onCameraSwitchError(String errorMessage) { + Log.e(TAG, "onCameraSwitchError: " + errorMessage); + cameraEventListener.onCameraSwitchCompleted(new CameraState(getActiveDirection(), getCount())); + } + } + + public interface CameraEventListener { + void onCameraSwitchCompleted(@NonNull CameraState newCameraState); + } +} diff --git a/src/org/thoughtcrime/securesms/webrtc/WebRtcDataProtos.java b/src/org/thoughtcrime/securesms/webrtc/WebRtcDataProtos.java new file mode 100644 index 000000000..9f6dd85e7 --- /dev/null +++ b/src/org/thoughtcrime/securesms/webrtc/WebRtcDataProtos.java @@ -0,0 +1,2248 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: WebRtcData.proto + +package org.thoughtcrime.securesms.webrtc; + +public final class WebRtcDataProtos { + private WebRtcDataProtos() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public interface ConnectedOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional uint64 id = 1; + /** + * optional uint64 id = 1; + */ + boolean hasId(); + /** + * optional uint64 id = 1; + */ + long getId(); + } + /** + * Protobuf type {@code signal.Connected} + */ + public static final class Connected extends + com.google.protobuf.GeneratedMessage + implements ConnectedOrBuilder { + // Use Connected.newBuilder() to construct. + private Connected(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Connected(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Connected defaultInstance; + public static Connected getDefaultInstance() { + return defaultInstance; + } + + public Connected getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Connected( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + id_ = input.readUInt64(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Connected_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Connected_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Connected parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Connected(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional uint64 id = 1; + public static final int ID_FIELD_NUMBER = 1; + private long id_; + /** + * optional uint64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1; + */ + public long getId() { + return id_; + } + + private void initFields() { + id_ = 0L; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt64(1, id_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(1, id_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signal.Connected} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Connected_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Connected_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder.class); + } + + // Construct using org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + id_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Connected_descriptor; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected getDefaultInstanceForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance(); + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected build() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected buildPartial() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected result = new org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.id_ = id_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected) { + return mergeFrom((org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected other) { + if (other == org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance()) return this; + if (other.hasId()) { + setId(other.getId()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional uint64 id = 1; + private long id_ ; + /** + * optional uint64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1; + */ + public long getId() { + return id_; + } + /** + * optional uint64 id = 1; + */ + public Builder setId(long value) { + bitField0_ |= 0x00000001; + id_ = value; + onChanged(); + return this; + } + /** + * optional uint64 id = 1; + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0L; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signal.Connected) + } + + static { + defaultInstance = new Connected(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signal.Connected) + } + + public interface HangupOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional uint64 id = 1; + /** + * optional uint64 id = 1; + */ + boolean hasId(); + /** + * optional uint64 id = 1; + */ + long getId(); + } + /** + * Protobuf type {@code signal.Hangup} + */ + public static final class Hangup extends + com.google.protobuf.GeneratedMessage + implements HangupOrBuilder { + // Use Hangup.newBuilder() to construct. + private Hangup(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Hangup(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Hangup defaultInstance; + public static Hangup getDefaultInstance() { + return defaultInstance; + } + + public Hangup getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Hangup( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + id_ = input.readUInt64(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Hangup_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Hangup_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Hangup parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Hangup(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional uint64 id = 1; + public static final int ID_FIELD_NUMBER = 1; + private long id_; + /** + * optional uint64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1; + */ + public long getId() { + return id_; + } + + private void initFields() { + id_ = 0L; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt64(1, id_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(1, id_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signal.Hangup} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Hangup_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Hangup_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder.class); + } + + // Construct using org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + id_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Hangup_descriptor; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup getDefaultInstanceForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance(); + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup build() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup buildPartial() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup result = new org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.id_ = id_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup) { + return mergeFrom((org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup other) { + if (other == org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance()) return this; + if (other.hasId()) { + setId(other.getId()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional uint64 id = 1; + private long id_ ; + /** + * optional uint64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1; + */ + public long getId() { + return id_; + } + /** + * optional uint64 id = 1; + */ + public Builder setId(long value) { + bitField0_ |= 0x00000001; + id_ = value; + onChanged(); + return this; + } + /** + * optional uint64 id = 1; + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0L; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signal.Hangup) + } + + static { + defaultInstance = new Hangup(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signal.Hangup) + } + + public interface VideoStreamingStatusOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional uint64 id = 1; + /** + * optional uint64 id = 1; + */ + boolean hasId(); + /** + * optional uint64 id = 1; + */ + long getId(); + + // optional bool enabled = 2; + /** + * optional bool enabled = 2; + */ + boolean hasEnabled(); + /** + * optional bool enabled = 2; + */ + boolean getEnabled(); + } + /** + * Protobuf type {@code signal.VideoStreamingStatus} + */ + public static final class VideoStreamingStatus extends + com.google.protobuf.GeneratedMessage + implements VideoStreamingStatusOrBuilder { + // Use VideoStreamingStatus.newBuilder() to construct. + private VideoStreamingStatus(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private VideoStreamingStatus(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final VideoStreamingStatus defaultInstance; + public static VideoStreamingStatus getDefaultInstance() { + return defaultInstance; + } + + public VideoStreamingStatus getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private VideoStreamingStatus( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + id_ = input.readUInt64(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + enabled_ = input.readBool(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_VideoStreamingStatus_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_VideoStreamingStatus_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public VideoStreamingStatus parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new VideoStreamingStatus(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional uint64 id = 1; + public static final int ID_FIELD_NUMBER = 1; + private long id_; + /** + * optional uint64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1; + */ + public long getId() { + return id_; + } + + // optional bool enabled = 2; + public static final int ENABLED_FIELD_NUMBER = 2; + private boolean enabled_; + /** + * optional bool enabled = 2; + */ + public boolean hasEnabled() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bool enabled = 2; + */ + public boolean getEnabled() { + return enabled_; + } + + private void initFields() { + id_ = 0L; + enabled_ = false; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt64(1, id_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBool(2, enabled_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(1, id_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(2, enabled_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signal.VideoStreamingStatus} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_VideoStreamingStatus_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_VideoStreamingStatus_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder.class); + } + + // Construct using org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + id_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + enabled_ = false; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_VideoStreamingStatus_descriptor; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus getDefaultInstanceForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance(); + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus build() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus buildPartial() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus result = new org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.id_ = id_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.enabled_ = enabled_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus) { + return mergeFrom((org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus other) { + if (other == org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance()) return this; + if (other.hasId()) { + setId(other.getId()); + } + if (other.hasEnabled()) { + setEnabled(other.getEnabled()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional uint64 id = 1; + private long id_ ; + /** + * optional uint64 id = 1; + */ + public boolean hasId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional uint64 id = 1; + */ + public long getId() { + return id_; + } + /** + * optional uint64 id = 1; + */ + public Builder setId(long value) { + bitField0_ |= 0x00000001; + id_ = value; + onChanged(); + return this; + } + /** + * optional uint64 id = 1; + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0L; + onChanged(); + return this; + } + + // optional bool enabled = 2; + private boolean enabled_ ; + /** + * optional bool enabled = 2; + */ + public boolean hasEnabled() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bool enabled = 2; + */ + public boolean getEnabled() { + return enabled_; + } + /** + * optional bool enabled = 2; + */ + public Builder setEnabled(boolean value) { + bitField0_ |= 0x00000002; + enabled_ = value; + onChanged(); + return this; + } + /** + * optional bool enabled = 2; + */ + public Builder clearEnabled() { + bitField0_ = (bitField0_ & ~0x00000002); + enabled_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signal.VideoStreamingStatus) + } + + static { + defaultInstance = new VideoStreamingStatus(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signal.VideoStreamingStatus) + } + + public interface DataOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional .signal.Connected connected = 1; + /** + * optional .signal.Connected connected = 1; + */ + boolean hasConnected(); + /** + * optional .signal.Connected connected = 1; + */ + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected getConnected(); + /** + * optional .signal.Connected connected = 1; + */ + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder getConnectedOrBuilder(); + + // optional .signal.Hangup hangup = 2; + /** + * optional .signal.Hangup hangup = 2; + */ + boolean hasHangup(); + /** + * optional .signal.Hangup hangup = 2; + */ + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup getHangup(); + /** + * optional .signal.Hangup hangup = 2; + */ + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder getHangupOrBuilder(); + + // optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + boolean hasVideoStreamingStatus(); + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus getVideoStreamingStatus(); + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder getVideoStreamingStatusOrBuilder(); + } + /** + * Protobuf type {@code signal.Data} + */ + public static final class Data extends + com.google.protobuf.GeneratedMessage + implements DataOrBuilder { + // Use Data.newBuilder() to construct. + private Data(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Data(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Data defaultInstance; + public static Data getDefaultInstance() { + return defaultInstance; + } + + public Data getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Data( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder subBuilder = null; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + subBuilder = connected_.toBuilder(); + } + connected_ = input.readMessage(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(connected_); + connected_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000001; + break; + } + case 18: { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder subBuilder = null; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + subBuilder = hangup_.toBuilder(); + } + hangup_ = input.readMessage(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(hangup_); + hangup_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000002; + break; + } + case 26: { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder subBuilder = null; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + subBuilder = videoStreamingStatus_.toBuilder(); + } + videoStreamingStatus_ = input.readMessage(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(videoStreamingStatus_); + videoStreamingStatus_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000004; + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Data_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Data_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Data parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Data(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // optional .signal.Connected connected = 1; + public static final int CONNECTED_FIELD_NUMBER = 1; + private org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected connected_; + /** + * optional .signal.Connected connected = 1; + */ + public boolean hasConnected() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional .signal.Connected connected = 1; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected getConnected() { + return connected_; + } + /** + * optional .signal.Connected connected = 1; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder getConnectedOrBuilder() { + return connected_; + } + + // optional .signal.Hangup hangup = 2; + public static final int HANGUP_FIELD_NUMBER = 2; + private org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup hangup_; + /** + * optional .signal.Hangup hangup = 2; + */ + public boolean hasHangup() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional .signal.Hangup hangup = 2; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup getHangup() { + return hangup_; + } + /** + * optional .signal.Hangup hangup = 2; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder getHangupOrBuilder() { + return hangup_; + } + + // optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + public static final int VIDEOSTREAMINGSTATUS_FIELD_NUMBER = 3; + private org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus videoStreamingStatus_; + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public boolean hasVideoStreamingStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus getVideoStreamingStatus() { + return videoStreamingStatus_; + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder getVideoStreamingStatusOrBuilder() { + return videoStreamingStatus_; + } + + private void initFields() { + connected_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance(); + hangup_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance(); + videoStreamingStatus_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeMessage(1, connected_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeMessage(2, hangup_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeMessage(3, videoStreamingStatus_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, connected_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, hangup_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, videoStreamingStatus_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signal.Data} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.DataOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Data_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Data_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.class, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.Builder.class); + } + + // Construct using org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getConnectedFieldBuilder(); + getHangupFieldBuilder(); + getVideoStreamingStatusFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + if (connectedBuilder_ == null) { + connected_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance(); + } else { + connectedBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + if (hangupBuilder_ == null) { + hangup_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance(); + } else { + hangupBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + if (videoStreamingStatusBuilder_ == null) { + videoStreamingStatus_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance(); + } else { + videoStreamingStatusBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.internal_static_signal_Data_descriptor; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data getDefaultInstanceForType() { + return org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.getDefaultInstance(); + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data build() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data buildPartial() { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data result = new org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + if (connectedBuilder_ == null) { + result.connected_ = connected_; + } else { + result.connected_ = connectedBuilder_.build(); + } + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + if (hangupBuilder_ == null) { + result.hangup_ = hangup_; + } else { + result.hangup_ = hangupBuilder_.build(); + } + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + if (videoStreamingStatusBuilder_ == null) { + result.videoStreamingStatus_ = videoStreamingStatus_; + } else { + result.videoStreamingStatus_ = videoStreamingStatusBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data) { + return mergeFrom((org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data other) { + if (other == org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data.getDefaultInstance()) return this; + if (other.hasConnected()) { + mergeConnected(other.getConnected()); + } + if (other.hasHangup()) { + mergeHangup(other.getHangup()); + } + if (other.hasVideoStreamingStatus()) { + mergeVideoStreamingStatus(other.getVideoStreamingStatus()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Data) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // optional .signal.Connected connected = 1; + private org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected connected_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder> connectedBuilder_; + /** + * optional .signal.Connected connected = 1; + */ + public boolean hasConnected() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * optional .signal.Connected connected = 1; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected getConnected() { + if (connectedBuilder_ == null) { + return connected_; + } else { + return connectedBuilder_.getMessage(); + } + } + /** + * optional .signal.Connected connected = 1; + */ + public Builder setConnected(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected value) { + if (connectedBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + connected_ = value; + onChanged(); + } else { + connectedBuilder_.setMessage(value); + } + bitField0_ |= 0x00000001; + return this; + } + /** + * optional .signal.Connected connected = 1; + */ + public Builder setConnected( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder builderForValue) { + if (connectedBuilder_ == null) { + connected_ = builderForValue.build(); + onChanged(); + } else { + connectedBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000001; + return this; + } + /** + * optional .signal.Connected connected = 1; + */ + public Builder mergeConnected(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected value) { + if (connectedBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001) && + connected_ != org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance()) { + connected_ = + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.newBuilder(connected_).mergeFrom(value).buildPartial(); + } else { + connected_ = value; + } + onChanged(); + } else { + connectedBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000001; + return this; + } + /** + * optional .signal.Connected connected = 1; + */ + public Builder clearConnected() { + if (connectedBuilder_ == null) { + connected_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.getDefaultInstance(); + onChanged(); + } else { + connectedBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + /** + * optional .signal.Connected connected = 1; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder getConnectedBuilder() { + bitField0_ |= 0x00000001; + onChanged(); + return getConnectedFieldBuilder().getBuilder(); + } + /** + * optional .signal.Connected connected = 1; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder getConnectedOrBuilder() { + if (connectedBuilder_ != null) { + return connectedBuilder_.getMessageOrBuilder(); + } else { + return connected_; + } + } + /** + * optional .signal.Connected connected = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder> + getConnectedFieldBuilder() { + if (connectedBuilder_ == null) { + connectedBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Connected.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.ConnectedOrBuilder>( + connected_, + getParentForChildren(), + isClean()); + connected_ = null; + } + return connectedBuilder_; + } + + // optional .signal.Hangup hangup = 2; + private org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup hangup_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder> hangupBuilder_; + /** + * optional .signal.Hangup hangup = 2; + */ + public boolean hasHangup() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional .signal.Hangup hangup = 2; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup getHangup() { + if (hangupBuilder_ == null) { + return hangup_; + } else { + return hangupBuilder_.getMessage(); + } + } + /** + * optional .signal.Hangup hangup = 2; + */ + public Builder setHangup(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup value) { + if (hangupBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + hangup_ = value; + onChanged(); + } else { + hangupBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * optional .signal.Hangup hangup = 2; + */ + public Builder setHangup( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder builderForValue) { + if (hangupBuilder_ == null) { + hangup_ = builderForValue.build(); + onChanged(); + } else { + hangupBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * optional .signal.Hangup hangup = 2; + */ + public Builder mergeHangup(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup value) { + if (hangupBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002) && + hangup_ != org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance()) { + hangup_ = + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.newBuilder(hangup_).mergeFrom(value).buildPartial(); + } else { + hangup_ = value; + } + onChanged(); + } else { + hangupBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000002; + return this; + } + /** + * optional .signal.Hangup hangup = 2; + */ + public Builder clearHangup() { + if (hangupBuilder_ == null) { + hangup_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.getDefaultInstance(); + onChanged(); + } else { + hangupBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + /** + * optional .signal.Hangup hangup = 2; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder getHangupBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getHangupFieldBuilder().getBuilder(); + } + /** + * optional .signal.Hangup hangup = 2; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder getHangupOrBuilder() { + if (hangupBuilder_ != null) { + return hangupBuilder_.getMessageOrBuilder(); + } else { + return hangup_; + } + } + /** + * optional .signal.Hangup hangup = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder> + getHangupFieldBuilder() { + if (hangupBuilder_ == null) { + hangupBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.Hangup.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.HangupOrBuilder>( + hangup_, + getParentForChildren(), + isClean()); + hangup_ = null; + } + return hangupBuilder_; + } + + // optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + private org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus videoStreamingStatus_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder> videoStreamingStatusBuilder_; + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public boolean hasVideoStreamingStatus() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus getVideoStreamingStatus() { + if (videoStreamingStatusBuilder_ == null) { + return videoStreamingStatus_; + } else { + return videoStreamingStatusBuilder_.getMessage(); + } + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public Builder setVideoStreamingStatus(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus value) { + if (videoStreamingStatusBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + videoStreamingStatus_ = value; + onChanged(); + } else { + videoStreamingStatusBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public Builder setVideoStreamingStatus( + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder builderForValue) { + if (videoStreamingStatusBuilder_ == null) { + videoStreamingStatus_ = builderForValue.build(); + onChanged(); + } else { + videoStreamingStatusBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public Builder mergeVideoStreamingStatus(org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus value) { + if (videoStreamingStatusBuilder_ == null) { + if (((bitField0_ & 0x00000004) == 0x00000004) && + videoStreamingStatus_ != org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance()) { + videoStreamingStatus_ = + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.newBuilder(videoStreamingStatus_).mergeFrom(value).buildPartial(); + } else { + videoStreamingStatus_ = value; + } + onChanged(); + } else { + videoStreamingStatusBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public Builder clearVideoStreamingStatus() { + if (videoStreamingStatusBuilder_ == null) { + videoStreamingStatus_ = org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.getDefaultInstance(); + onChanged(); + } else { + videoStreamingStatusBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder getVideoStreamingStatusBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return getVideoStreamingStatusFieldBuilder().getBuilder(); + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + public org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder getVideoStreamingStatusOrBuilder() { + if (videoStreamingStatusBuilder_ != null) { + return videoStreamingStatusBuilder_.getMessageOrBuilder(); + } else { + return videoStreamingStatus_; + } + } + /** + * optional .signal.VideoStreamingStatus videoStreamingStatus = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder> + getVideoStreamingStatusFieldBuilder() { + if (videoStreamingStatusBuilder_ == null) { + videoStreamingStatusBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatus.Builder, org.thoughtcrime.securesms.webrtc.WebRtcDataProtos.VideoStreamingStatusOrBuilder>( + videoStreamingStatus_, + getParentForChildren(), + isClean()); + videoStreamingStatus_ = null; + } + return videoStreamingStatusBuilder_; + } + + // @@protoc_insertion_point(builder_scope:signal.Data) + } + + static { + defaultInstance = new Data(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signal.Data) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signal_Connected_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signal_Connected_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signal_Hangup_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signal_Hangup_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signal_VideoStreamingStatus_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signal_VideoStreamingStatus_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signal_Data_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signal_Data_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\020WebRtcData.proto\022\006signal\"\027\n\tConnected\022" + + "\n\n\002id\030\001 \001(\004\"\024\n\006Hangup\022\n\n\002id\030\001 \001(\004\"3\n\024Vid" + + "eoStreamingStatus\022\n\n\002id\030\001 \001(\004\022\017\n\007enabled" + + "\030\002 \001(\010\"\210\001\n\004Data\022$\n\tconnected\030\001 \001(\0132\021.sig" + + "nal.Connected\022\036\n\006hangup\030\002 \001(\0132\016.signal.H" + + "angup\022:\n\024videoStreamingStatus\030\003 \001(\0132\034.si" + + "gnal.VideoStreamingStatusB5\n!org.thought" + + "crime.securesms.webrtcB\020WebRtcDataProtos" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_signal_Connected_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_signal_Connected_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signal_Connected_descriptor, + new java.lang.String[] { "Id", }); + internal_static_signal_Hangup_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_signal_Hangup_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signal_Hangup_descriptor, + new java.lang.String[] { "Id", }); + internal_static_signal_VideoStreamingStatus_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_signal_VideoStreamingStatus_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signal_VideoStreamingStatus_descriptor, + new java.lang.String[] { "Id", "Enabled", }); + internal_static_signal_Data_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_signal_Data_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signal_Data_descriptor, + new java.lang.String[] { "Connected", "Hangup", "VideoStreamingStatus", }); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + // @@protoc_insertion_point(outer_class_scope) +}