diff --git a/examples/androidapp/src/org/appspot/apprtc/CallActivity.java b/examples/androidapp/src/org/appspot/apprtc/CallActivity.java index ccc2c3bd93..43961506ab 100644 --- a/examples/androidapp/src/org/appspot/apprtc/CallActivity.java +++ b/examples/androidapp/src/org/appspot/apprtc/CallActivity.java @@ -171,7 +171,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven private RoomConnectionParameters roomConnectionParameters; @Nullable private PeerConnectionParameters peerConnectionParameters; - private boolean iceConnected; + private boolean connected; private boolean isError; private boolean callControlFragmentVisible = true; private long callStartedTimeMs; @@ -203,7 +203,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven getWindow().getDecorView().setSystemUiVisibility(getSystemUiVisibility()); setContentView(R.layout.activity_call); - iceConnected = false; + connected = false; signalingParameters = null; // Create UI controls. @@ -553,7 +553,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven // Helper functions. private void toggleCallControlFragmentVisibility() { - if (!iceConnected || !callFragment.isAdded()) { + if (!connected || !callFragment.isAdded()) { return; } // Show/hide call control fragment @@ -649,7 +649,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven audioManager.stop(); audioManager = null; } - if (iceConnected && !isError) { + if (connected && !isError) { setResult(RESULT_OK); } else { setResult(RESULT_CANCELED); @@ -911,8 +911,6 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven @Override public void run() { logAndToast("ICE connected, delay=" + delta + "ms"); - iceConnected = true; - callConnected(); } }); } @@ -923,7 +921,30 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven @Override public void run() { logAndToast("ICE disconnected"); - iceConnected = false; + } + }); + } + + @Override + public void onConnected() { + final long delta = System.currentTimeMillis() - callStartedTimeMs; + runOnUiThread(new Runnable() { + @Override + public void run() { + logAndToast("DTLS connected, delay=" + delta + "ms"); + connected = true; + callConnected(); + } + }); + } + + @Override + public void onDisconnected() { + runOnUiThread(new Runnable() { + @Override + public void run() { + logAndToast("DTLS disconnected"); + connected = false; disconnect(); } }); @@ -937,7 +958,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven runOnUiThread(new Runnable() { @Override public void run() { - if (!isError && iceConnected) { + if (!isError && connected) { hudFragment.updateEncoderStatistics(reports); } } diff --git a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java index 94135ded4d..f85a788f3d 100644 --- a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java +++ b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java @@ -52,6 +52,7 @@ import org.webrtc.MediaStreamTrack; import org.webrtc.MediaStreamTrack.MediaType; import org.webrtc.PeerConnection; import org.webrtc.PeerConnection.IceConnectionState; +import org.webrtc.PeerConnection.PeerConnectionState; import org.webrtc.PeerConnectionFactory; import org.webrtc.RtpParameters; import org.webrtc.RtpReceiver; @@ -293,11 +294,23 @@ public class PeerConnectionClient { void onIceConnected(); /** - * Callback fired once connection is closed (IceConnectionState is + * Callback fired once connection is disconnected (IceConnectionState is * DISCONNECTED). */ void onIceDisconnected(); + /** + * Callback fired once DTLS connection is established (PeerConnectionState + * is CONNECTED). + */ + void onConnected(); + + /** + * Callback fired once DTLS connection is disconnected (PeerConnectionState + * is DISCONNECTED). + */ + void onDisconnected(); + /** * Callback fired once peer connection is closed. */ @@ -1263,6 +1276,20 @@ public class PeerConnectionClient { }); } + @Override + public void onConnectionChange(final PeerConnection.PeerConnectionState newState) { + executor.execute(() -> { + Log.d(TAG, "PeerConnectionState: " + newState); + if (newState == PeerConnectionState.CONNECTED) { + events.onConnected(); + } else if (newState == PeerConnectionState.DISCONNECTED) { + events.onDisconnected(); + } else if (newState == PeerConnectionState.FAILED) { + reportError("DTLS connection failed."); + } + }); + } + @Override public void onIceGatheringChange(PeerConnection.IceGatheringState newState) { Log.d(TAG, "IceGatheringState: " + newState); diff --git a/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java b/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java index e2674017e4..c165f59b03 100644 --- a/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java +++ b/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java @@ -183,6 +183,16 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { } } + @Override + public void onConnected() { + Log.d(TAG, "DTLS Connected"); + } + + @Override + public void onDisconnected() { + Log.d(TAG, "DTLS Disconnected"); + } + @Override public void onPeerConnectionClosed() { Log.d(TAG, "PeerConnection closed"); diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index dac32c86f9..23c9ae864a 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -50,6 +50,21 @@ public class PeerConnection { } } + /** Tracks PeerConnectionInterface::PeerConnectionState */ + public enum PeerConnectionState { + NEW, + CONNECTING, + CONNECTED, + DISCONNECTED, + FAILED, + CLOSED; + + @CalledByNative("PeerConnectionState") + static PeerConnectionState fromNativeIndex(int nativeIndex) { + return values()[nativeIndex]; + } + } + /** Tracks PeerConnectionInterface::TlsCertPolicy */ public enum TlsCertPolicy { TLS_CERT_POLICY_SECURE, @@ -79,6 +94,10 @@ public class PeerConnection { /** Triggered when the IceConnectionState changes. */ @CalledByNative("Observer") void onIceConnectionChange(IceConnectionState newState); + /** Triggered when the PeerConnectionState changes. */ + @CalledByNative("Observer") + default void onConnectionChange(PeerConnectionState newState) {} + /** Triggered when the ICE connection receiving status changes. */ @CalledByNative("Observer") void onIceConnectionReceivingChange(boolean receiving); @@ -1093,6 +1112,10 @@ public class PeerConnection { return nativeIceConnectionState(); } + public PeerConnectionState connectionState() { + return nativeConnectionState(); + } + public IceGatheringState iceGatheringState() { return nativeIceGatheringState(); } @@ -1167,6 +1190,7 @@ public class PeerConnection { private native boolean nativeSetBitrate(Integer min, Integer current, Integer max); private native SignalingState nativeSignalingState(); private native IceConnectionState nativeIceConnectionState(); + private native PeerConnectionState nativeConnectionState(); private native IceGatheringState nativeIceGatheringState(); private native void nativeClose(); private static native long nativeCreatePeerConnectionObserver(Observer observer); diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java index cd24037daf..2063199e72 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java @@ -45,6 +45,7 @@ import org.junit.runner.RunWith; import org.webrtc.Metrics.HistogramInfo; import org.webrtc.PeerConnection.IceConnectionState; import org.webrtc.PeerConnection.IceGatheringState; +import org.webrtc.PeerConnection.PeerConnectionState; import org.webrtc.PeerConnection.SignalingState; /** End-to-end tests for PeerConnection.java. */ @@ -74,6 +75,7 @@ public class PeerConnectionTest { private int expectedTracksAdded; private Queue expectedSignalingChanges = new ArrayDeque<>(); private Queue expectedIceConnectionChanges = new ArrayDeque<>(); + private Queue expectedConnectionChanges = new ArrayDeque<>(); private Queue expectedIceGatheringChanges = new ArrayDeque<>(); private Queue expectedAddStreamLabels = new ArrayDeque<>(); private Queue expectedRemoveStreamLabels = new ArrayDeque<>(); @@ -188,11 +190,29 @@ public class PeerConnectionTest { assertEquals(expectedIceConnectionChanges.remove(), newState); } + // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. + @SuppressWarnings("NoSynchronizedMethodCheck") + public synchronized void expectConnectionChange(PeerConnectionState newState) { + expectedConnectionChanges.add(newState); + } + + @Override + // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. + @SuppressWarnings("NoSynchronizedMethodCheck") + public synchronized void onConnectionChange(PeerConnectionState newState) { + if (expectedConnectionChanges.isEmpty()) { + System.out.println(name + " got an unexpected DTLS connection change " + newState); + return; + } + + assertEquals(expectedConnectionChanges.remove(), newState); + } + @Override // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. @SuppressWarnings("NoSynchronizedMethodCheck") public synchronized void onIceConnectionReceivingChange(boolean receiving) { - System.out.println(name + "Got an ICE connection receiving change " + receiving); + System.out.println(name + " got an ICE connection receiving change " + receiving); } // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. @@ -799,12 +819,14 @@ public class PeerConnectionTest { sdpLatch = new SdpObserverLatch(); answeringExpectations.expectSignalingChange(SignalingState.STABLE); + answeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); answeringPC.setLocalDescription(sdpLatch, answerSdp); assertTrue(sdpLatch.await()); assertNull(sdpLatch.getSdp()); sdpLatch = new SdpObserverLatch(); offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); offeringPC.setLocalDescription(sdpLatch, offerSdp); assertTrue(sdpLatch.await()); assertNull(sdpLatch.getSdp()); @@ -814,6 +836,9 @@ public class PeerConnectionTest { offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + offeringExpectations.expectConnectionChange(PeerConnectionState.NEW); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED); // TODO(bemasc): uncomment once delivery of ICECompleted is reliable // (https://code.google.com/p/webrtc/issues/detail?id=3021). // @@ -821,6 +846,7 @@ public class PeerConnectionTest { // IceConnectionState.COMPLETED); answeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); answeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + answeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED); offeringPC.setRemoteDescription(sdpLatch, answerSdp); assertTrue(sdpLatch.await()); @@ -1029,12 +1055,14 @@ public class PeerConnectionTest { sdpLatch = new SdpObserverLatch(); answeringExpectations.expectSignalingChange(SignalingState.STABLE); + answeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); answeringPC.setLocalDescription(sdpLatch, answerSdp); assertTrue(sdpLatch.await()); assertNull(sdpLatch.getSdp()); sdpLatch = new SdpObserverLatch(); offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); offeringPC.setLocalDescription(sdpLatch, offerSdp); assertTrue(sdpLatch.await()); assertNull(sdpLatch.getSdp()); @@ -1043,10 +1071,14 @@ public class PeerConnectionTest { offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + offeringExpectations.expectConnectionChange(PeerConnectionState.NEW); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED); // TODO(bemasc): uncomment once delivery of ICECompleted is reliable // (https://code.google.com/p/webrtc/issues/detail?id=3021). answeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); answeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + answeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED); offeringPC.setRemoteDescription(sdpLatch, answerSdp); assertTrue(sdpLatch.await()); @@ -1179,6 +1211,7 @@ public class PeerConnectionTest { offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER); offeringExpectations.expectIceCandidates(2); offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); offeringPC.setLocalDescription(sdpLatch, offerSdp); assertTrue(sdpLatch.await()); assertNull(sdpLatch.getSdp()); @@ -1210,6 +1243,7 @@ public class PeerConnectionTest { answeringExpectations.expectSignalingChange(SignalingState.STABLE); answeringExpectations.expectIceCandidates(2); answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE); + answeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); answeringPC.setLocalDescription(sdpLatch, answerSdp); assertTrue(sdpLatch.await()); assertNull(sdpLatch.getSdp()); @@ -1221,6 +1255,9 @@ public class PeerConnectionTest { offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + offeringExpectations.expectConnectionChange(PeerConnectionState.NEW); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTING); + offeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED); // TODO(bemasc): uncomment once delivery of ICECompleted is reliable // (https://code.google.com/p/webrtc/issues/detail?id=3021). // @@ -1228,6 +1265,7 @@ public class PeerConnectionTest { // IceConnectionState.COMPLETED); answeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); answeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + answeringExpectations.expectConnectionChange(PeerConnectionState.CONNECTED); offeringPC.setRemoteDescription(sdpLatch, answerSdp); assertTrue(sdpLatch.await()); @@ -1613,6 +1651,7 @@ public class PeerConnectionTest { assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); expectations.expectIceConnectionChange(IceConnectionState.CLOSED); + expectations.expectConnectionChange(PeerConnectionState.CLOSED); expectations.expectSignalingChange(SignalingState.CLOSED); pc.close(); assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); diff --git a/sdk/android/src/jni/pc/peerconnection.cc b/sdk/android/src/jni/pc/peerconnection.cc index 162f809e6e..0515ce264e 100644 --- a/sdk/android/src/jni/pc/peerconnection.cc +++ b/sdk/android/src/jni/pc/peerconnection.cc @@ -299,6 +299,14 @@ void PeerConnectionObserverJni::OnIceConnectionChange( Java_IceConnectionState_fromNativeIndex(env, new_state)); } +void PeerConnectionObserverJni::OnConnectionChange( + PeerConnectionInterface::PeerConnectionState new_state) { + JNIEnv* env = AttachCurrentThreadIfNeeded(); + Java_Observer_onConnectionChange(env, j_observer_global_, + Java_PeerConnectionState_fromNativeIndex( + env, static_cast(new_state))); +} + void PeerConnectionObserverJni::OnIceConnectionReceivingChange(bool receiving) { JNIEnv* env = AttachCurrentThreadIfNeeded(); Java_Observer_onIceConnectionReceivingChange(env, j_observer_global_, @@ -752,6 +760,14 @@ static ScopedJavaLocalRef JNI_PeerConnection_IceConnectionState( env, ExtractNativePC(env, j_pc)->ice_connection_state()); } +static ScopedJavaLocalRef JNI_PeerConnection_ConnectionState( + JNIEnv* env, + const JavaParamRef& j_pc) { + return Java_PeerConnectionState_fromNativeIndex( + env, + static_cast(ExtractNativePC(env, j_pc)->peer_connection_state())); +} + static ScopedJavaLocalRef JNI_PeerConnection_IceGatheringState( JNIEnv* env, const JavaParamRef& j_pc) { diff --git a/sdk/android/src/jni/pc/peerconnection.h b/sdk/android/src/jni/pc/peerconnection.h index f20166727e..a9d7b39c3d 100644 --- a/sdk/android/src/jni/pc/peerconnection.h +++ b/sdk/android/src/jni/pc/peerconnection.h @@ -51,6 +51,8 @@ class PeerConnectionObserverJni : public PeerConnectionObserver { PeerConnectionInterface::SignalingState new_state) override; void OnIceConnectionChange( PeerConnectionInterface::IceConnectionState new_state) override; + void OnConnectionChange( + PeerConnectionInterface::PeerConnectionState new_state) override; void OnIceConnectionReceivingChange(bool receiving) override; void OnIceGatheringChange( PeerConnectionInterface::IceGatheringState new_state) override;