Index: webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java |
diff --git a/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java |
index 30595a391e797e779f86250e5a31829bc0f0ed6b..af6f9884fbfdb7f1eedafaf1b5e7a4741a77dfbb 100644 |
--- a/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java |
+++ b/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java |
@@ -805,6 +805,156 @@ public class PeerConnectionTest { |
System.gc(); |
} |
+ @Test |
+ @MediumTest |
+ public void testDataChannelOnlySession() throws Exception { |
+ // Allow loopback interfaces too since our Android devices often don't |
+ // have those. |
+ PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); |
+ options.networkIgnoreMask = 0; |
+ PeerConnectionFactory factory = new PeerConnectionFactory(options); |
+ |
+ MediaConstraints pcConstraints = new MediaConstraints(); |
+ pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); |
+ |
+ LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>(); |
+ iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302")); |
+ iceServers.add( |
+ new PeerConnection.IceServer("turn:fake.example.com", "fakeUsername", "fakePassword")); |
+ ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer"); |
+ PeerConnection offeringPC = |
+ factory.createPeerConnection(iceServers, pcConstraints, offeringExpectations); |
+ assertNotNull(offeringPC); |
+ |
+ ObserverExpectations answeringExpectations = new ObserverExpectations("PCTest:answerer"); |
+ PeerConnection answeringPC = |
+ factory.createPeerConnection(iceServers, pcConstraints, answeringExpectations); |
+ assertNotNull(answeringPC); |
+ |
+ offeringExpectations.expectRenegotiationNeeded(); |
+ DataChannel offeringDC = offeringPC.createDataChannel("offeringDC", new DataChannel.Init()); |
+ assertEquals("offeringDC", offeringDC.label()); |
+ |
+ offeringExpectations.setDataChannel(offeringDC); |
+ SdpObserverLatch sdpLatch = new SdpObserverLatch(); |
+ offeringPC.createOffer(sdpLatch, new MediaConstraints()); |
+ assertTrue(sdpLatch.await()); |
+ SessionDescription offerSdp = sdpLatch.getSdp(); |
+ assertEquals(offerSdp.type, SessionDescription.Type.OFFER); |
+ assertFalse(offerSdp.description.isEmpty()); |
+ |
+ sdpLatch = new SdpObserverLatch(); |
+ answeringExpectations.expectSignalingChange(SignalingState.HAVE_REMOTE_OFFER); |
+ // SCTP DataChannels are announced via OPEN messages over the established |
+ // connection (not via SDP), so answeringExpectations can only register |
+ // expecting the channel during ICE, below. |
+ answeringPC.setRemoteDescription(sdpLatch, offerSdp); |
+ assertEquals(PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); |
+ assertTrue(sdpLatch.await()); |
+ assertNull(sdpLatch.getSdp()); |
+ |
+ sdpLatch = new SdpObserverLatch(); |
+ answeringPC.createAnswer(sdpLatch, new MediaConstraints()); |
+ assertTrue(sdpLatch.await()); |
+ SessionDescription answerSdp = sdpLatch.getSdp(); |
+ assertEquals(answerSdp.type, SessionDescription.Type.ANSWER); |
+ assertFalse(answerSdp.description.isEmpty()); |
+ |
+ offeringExpectations.expectIceCandidates(2); |
+ answeringExpectations.expectIceCandidates(2); |
+ |
+ offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE); |
+ answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE); |
+ |
+ sdpLatch = new SdpObserverLatch(); |
+ answeringExpectations.expectSignalingChange(SignalingState.STABLE); |
+ answeringPC.setLocalDescription(sdpLatch, answerSdp); |
+ assertTrue(sdpLatch.await()); |
+ assertNull(sdpLatch.getSdp()); |
+ |
+ sdpLatch = new SdpObserverLatch(); |
+ offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER); |
+ offeringPC.setLocalDescription(sdpLatch, offerSdp); |
+ assertTrue(sdpLatch.await()); |
+ assertNull(sdpLatch.getSdp()); |
+ sdpLatch = new SdpObserverLatch(); |
+ offeringExpectations.expectSignalingChange(SignalingState.STABLE); |
+ |
+ offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); |
+ offeringExpectations.expectIceConnectionChange(IceConnectionState.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); |
+ |
+ offeringPC.setRemoteDescription(sdpLatch, answerSdp); |
+ assertTrue(sdpLatch.await()); |
+ assertNull(sdpLatch.getSdp()); |
+ |
+ assertEquals(offeringPC.getLocalDescription().type, offerSdp.type); |
+ assertEquals(offeringPC.getRemoteDescription().type, answerSdp.type); |
+ assertEquals(answeringPC.getLocalDescription().type, answerSdp.type); |
+ assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type); |
+ |
+ offeringExpectations.expectStateChange(DataChannel.State.OPEN); |
+ // See commentary about SCTP DataChannels above for why this is here. |
+ answeringExpectations.expectDataChannel("offeringDC"); |
+ answeringExpectations.expectStateChange(DataChannel.State.OPEN); |
+ |
+ // Wait for at least one ice candidate from the offering PC and forward them to the answering |
+ // PC. |
+ for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate()) { |
+ answeringPC.addIceCandidate(candidate); |
+ } |
+ |
+ // Wait for at least one ice candidate from the answering PC and forward them to the offering |
+ // PC. |
+ for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidate()) { |
+ offeringPC.addIceCandidate(candidate); |
+ } |
+ |
+ assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); |
+ assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); |
+ |
+ assertEquals(PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); |
+ assertEquals(PeerConnection.SignalingState.STABLE, answeringPC.signalingState()); |
+ |
+ // Test send & receive UTF-8 text. |
+ answeringExpectations.expectMessage( |
+ ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); |
+ DataChannel.Buffer buffer = |
+ new DataChannel.Buffer(ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); |
+ assertTrue(offeringExpectations.dataChannel.send(buffer)); |
+ assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); |
+ |
+ // Construct this binary message two different ways to ensure no |
+ // shortcuts are taken. |
+ ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5); |
+ for (byte i = 1; i < 6; ++i) { |
+ expectedBinaryMessage.put(i); |
+ } |
+ expectedBinaryMessage.flip(); |
+ offeringExpectations.expectMessage(expectedBinaryMessage, true); |
+ assertTrue(answeringExpectations.dataChannel.send( |
+ new DataChannel.Buffer(ByteBuffer.wrap(new byte[] {1, 2, 3, 4, 5}), true))); |
+ assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); |
+ |
+ offeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
+ answeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
+ offeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
+ answeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
+ answeringExpectations.dataChannel.close(); |
+ offeringExpectations.dataChannel.close(); |
+ |
+ // Free the Java-land objects and collect them. |
+ shutdownPC(offeringPC, offeringExpectations); |
+ offeringPC = null; |
+ shutdownPC(answeringPC, answeringExpectations); |
+ answeringPC = null; |
+ factory.dispose(); |
+ System.gc(); |
+ } |
+ |
// Flaky on Android. See webrtc:7761 |
@DisabledTest |
@Test |