Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java

Issue 1652123002: Remove Java PC support. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: rebased Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * libjingle
3 * Copyright 2013 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 package org.webrtc;
29
30 import org.webrtc.PeerConnection.IceConnectionState;
31 import org.webrtc.PeerConnection.IceGatheringState;
32 import org.webrtc.PeerConnection.SignalingState;
33
34 import java.io.File;
35 import java.lang.ref.WeakReference;
36 import java.nio.ByteBuffer;
37 import java.nio.charset.Charset;
38 import java.util.Arrays;
39 import java.util.IdentityHashMap;
40 import java.util.LinkedList;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.TreeSet;
44 import java.util.concurrent.CountDownLatch;
45 import java.util.concurrent.TimeUnit;
46
47 import static junit.framework.Assert.*;
48
49 /** End-to-end tests for PeerConnection.java. */
50 public class PeerConnectionTest {
51 // Set to true to render video.
52 private static final boolean RENDER_TO_GUI = false;
53 private static final int TIMEOUT_SECONDS = 20;
54 private TreeSet<String> threadsBeforeTest = null;
55
56 private static class ObserverExpectations implements PeerConnection.Observer,
57 VideoRenderer.Callbacks,
58 DataChannel.Observer,
59 StatsObserver {
60 private final String name;
61 private int expectedIceCandidates = 0;
62 private int expectedErrors = 0;
63 private int expectedRenegotiations = 0;
64 private int previouslySeenWidth = 0;
65 private int previouslySeenHeight = 0;
66 private int expectedFramesDelivered = 0;
67 private LinkedList<SignalingState> expectedSignalingChanges =
68 new LinkedList<SignalingState>();
69 private LinkedList<IceConnectionState> expectedIceConnectionChanges =
70 new LinkedList<IceConnectionState>();
71 private LinkedList<IceGatheringState> expectedIceGatheringChanges =
72 new LinkedList<IceGatheringState>();
73 private LinkedList<String> expectedAddStreamLabels =
74 new LinkedList<String>();
75 private LinkedList<String> expectedRemoveStreamLabels =
76 new LinkedList<String>();
77 private final LinkedList<IceCandidate> gotIceCandidates =
78 new LinkedList<IceCandidate>();
79 private Map<MediaStream, WeakReference<VideoRenderer>> renderers =
80 new IdentityHashMap<MediaStream, WeakReference<VideoRenderer>>();
81 private DataChannel dataChannel;
82 private LinkedList<DataChannel.Buffer> expectedBuffers =
83 new LinkedList<DataChannel.Buffer>();
84 private LinkedList<DataChannel.State> expectedStateChanges =
85 new LinkedList<DataChannel.State>();
86 private LinkedList<String> expectedRemoteDataChannelLabels =
87 new LinkedList<String>();
88 private int expectedStatsCallbacks = 0;
89 private LinkedList<StatsReport[]> gotStatsReports =
90 new LinkedList<StatsReport[]>();
91
92 public ObserverExpectations(String name) {
93 this.name = name;
94 }
95
96 public synchronized void setDataChannel(DataChannel dataChannel) {
97 assertNull(this.dataChannel);
98 this.dataChannel = dataChannel;
99 this.dataChannel.registerObserver(this);
100 assertNotNull(this.dataChannel);
101 }
102
103 public synchronized void expectIceCandidates(int count) {
104 expectedIceCandidates += count;
105 }
106
107 @Override
108 public synchronized void onIceCandidate(IceCandidate candidate) {
109 --expectedIceCandidates;
110
111 // We don't assert expectedIceCandidates >= 0 because it's hard to know
112 // how many to expect, in general. We only use expectIceCandidates to
113 // assert a minimal count.
114 synchronized (gotIceCandidates) {
115 gotIceCandidates.add(candidate);
116 gotIceCandidates.notifyAll();
117 }
118 }
119
120 private synchronized void setSize(int width, int height) {
121 assertFalse(RENDER_TO_GUI);
122 // Because different camera devices (fake & physical) produce different
123 // resolutions, we only sanity-check the set sizes,
124 assertTrue(width > 0);
125 assertTrue(height > 0);
126 if (previouslySeenWidth > 0) {
127 assertEquals(previouslySeenWidth, width);
128 assertEquals(previouslySeenHeight, height);
129 } else {
130 previouslySeenWidth = width;
131 previouslySeenHeight = height;
132 }
133 }
134
135 public synchronized void expectFramesDelivered(int count) {
136 assertFalse(RENDER_TO_GUI);
137 expectedFramesDelivered += count;
138 }
139
140 @Override
141 public synchronized void renderFrame(VideoRenderer.I420Frame frame) {
142 setSize(frame.rotatedWidth(), frame.rotatedHeight());
143 --expectedFramesDelivered;
144 VideoRenderer.renderFrameDone(frame);
145 }
146
147 public synchronized void expectSignalingChange(SignalingState newState) {
148 expectedSignalingChanges.add(newState);
149 }
150
151 @Override
152 public synchronized void onSignalingChange(SignalingState newState) {
153 assertEquals(expectedSignalingChanges.removeFirst(), newState);
154 }
155
156 public synchronized void expectIceConnectionChange(
157 IceConnectionState newState) {
158 expectedIceConnectionChanges.add(newState);
159 }
160
161 @Override
162 public synchronized void onIceConnectionChange(
163 IceConnectionState newState) {
164 // TODO(bemasc): remove once delivery of ICECompleted is reliable
165 // (https://code.google.com/p/webrtc/issues/detail?id=3021).
166 if (newState.equals(IceConnectionState.COMPLETED)) {
167 return;
168 }
169
170 if (expectedIceConnectionChanges.isEmpty()) {
171 System.out.println(name + "Got an unexpected ice connection change " + n ewState);
172 return;
173 }
174
175 assertEquals(expectedIceConnectionChanges.removeFirst(), newState);
176 }
177
178 @Override
179 public synchronized void onIceConnectionReceivingChange(boolean receiving) {
180 System.out.println(name + "Got an ice connection receiving change " + rece iving);
181 }
182
183 public synchronized void expectIceGatheringChange(
184 IceGatheringState newState) {
185 expectedIceGatheringChanges.add(newState);
186 }
187
188 @Override
189 public synchronized void onIceGatheringChange(IceGatheringState newState) {
190 // It's fine to get a variable number of GATHERING messages before
191 // COMPLETE fires (depending on how long the test runs) so we don't assert
192 // any particular count.
193 if (newState == IceGatheringState.GATHERING) {
194 return;
195 }
196 assertEquals(expectedIceGatheringChanges.removeFirst(), newState);
197 }
198
199 public synchronized void expectAddStream(String label) {
200 expectedAddStreamLabels.add(label);
201 }
202
203 @Override
204 public synchronized void onAddStream(MediaStream stream) {
205 assertEquals(expectedAddStreamLabels.removeFirst(), stream.label());
206 assertEquals(1, stream.videoTracks.size());
207 assertEquals(1, stream.audioTracks.size());
208 assertTrue(stream.videoTracks.get(0).id().endsWith("VideoTrack"));
209 assertTrue(stream.audioTracks.get(0).id().endsWith("AudioTrack"));
210 assertEquals("video", stream.videoTracks.get(0).kind());
211 assertEquals("audio", stream.audioTracks.get(0).kind());
212 VideoRenderer renderer = createVideoRenderer(this);
213 stream.videoTracks.get(0).addRenderer(renderer);
214 assertNull(renderers.put(
215 stream, new WeakReference<VideoRenderer>(renderer)));
216 }
217
218 public synchronized void expectRemoveStream(String label) {
219 expectedRemoveStreamLabels.add(label);
220 }
221
222 @Override
223 public synchronized void onRemoveStream(MediaStream stream) {
224 assertEquals(expectedRemoveStreamLabels.removeFirst(), stream.label());
225 WeakReference<VideoRenderer> renderer = renderers.remove(stream);
226 assertNotNull(renderer);
227 assertNotNull(renderer.get());
228 assertEquals(1, stream.videoTracks.size());
229 stream.videoTracks.get(0).removeRenderer(renderer.get());
230 }
231
232 public synchronized void expectDataChannel(String label) {
233 expectedRemoteDataChannelLabels.add(label);
234 }
235
236 @Override
237 public synchronized void onDataChannel(DataChannel remoteDataChannel) {
238 assertEquals(expectedRemoteDataChannelLabels.removeFirst(),
239 remoteDataChannel.label());
240 setDataChannel(remoteDataChannel);
241 assertEquals(DataChannel.State.CONNECTING, dataChannel.state());
242 }
243
244 public synchronized void expectRenegotiationNeeded() {
245 ++expectedRenegotiations;
246 }
247
248 @Override
249 public synchronized void onRenegotiationNeeded() {
250 assertTrue(--expectedRenegotiations >= 0);
251 }
252
253 public synchronized void expectMessage(ByteBuffer expectedBuffer,
254 boolean expectedBinary) {
255 expectedBuffers.add(
256 new DataChannel.Buffer(expectedBuffer, expectedBinary));
257 }
258
259 @Override
260 public synchronized void onMessage(DataChannel.Buffer buffer) {
261 DataChannel.Buffer expected = expectedBuffers.removeFirst();
262 assertEquals(expected.binary, buffer.binary);
263 assertTrue(expected.data.equals(buffer.data));
264 }
265
266 @Override
267 public synchronized void onBufferedAmountChange(long previousAmount) {
268 assertFalse(previousAmount == dataChannel.bufferedAmount());
269 }
270
271 @Override
272 public synchronized void onStateChange() {
273 assertEquals(expectedStateChanges.removeFirst(), dataChannel.state());
274 }
275
276 public synchronized void expectStateChange(DataChannel.State state) {
277 expectedStateChanges.add(state);
278 }
279
280 @Override
281 public synchronized void onComplete(StatsReport[] reports) {
282 if (--expectedStatsCallbacks < 0) {
283 throw new RuntimeException("Unexpected stats report: " + reports);
284 }
285 gotStatsReports.add(reports);
286 }
287
288 public synchronized void expectStatsCallback() {
289 ++expectedStatsCallbacks;
290 }
291
292 public synchronized LinkedList<StatsReport[]> takeStatsReports() {
293 LinkedList<StatsReport[]> got = gotStatsReports;
294 gotStatsReports = new LinkedList<StatsReport[]>();
295 return got;
296 }
297
298 // Return a set of expectations that haven't been satisfied yet, possibly
299 // empty if no such expectations exist.
300 public synchronized TreeSet<String> unsatisfiedExpectations() {
301 TreeSet<String> stillWaitingForExpectations = new TreeSet<String>();
302 if (expectedIceCandidates > 0) { // See comment in onIceCandidate.
303 stillWaitingForExpectations.add("expectedIceCandidates");
304 }
305 if (expectedErrors != 0) {
306 stillWaitingForExpectations.add("expectedErrors: " + expectedErrors);
307 }
308 if (expectedSignalingChanges.size() != 0) {
309 stillWaitingForExpectations.add(
310 "expectedSignalingChanges: " + expectedSignalingChanges.size());
311 }
312 if (expectedIceConnectionChanges.size() != 0) {
313 stillWaitingForExpectations.add("expectedIceConnectionChanges: " +
314 expectedIceConnectionChanges.size());
315 }
316 if (expectedIceGatheringChanges.size() != 0) {
317 stillWaitingForExpectations.add("expectedIceGatheringChanges: " +
318 expectedIceGatheringChanges.size());
319 }
320 if (expectedAddStreamLabels.size() != 0) {
321 stillWaitingForExpectations.add(
322 "expectedAddStreamLabels: " + expectedAddStreamLabels.size());
323 }
324 if (expectedRemoveStreamLabels.size() != 0) {
325 stillWaitingForExpectations.add(
326 "expectedRemoveStreamLabels: " + expectedRemoveStreamLabels.size());
327 }
328 if (expectedFramesDelivered > 0) {
329 stillWaitingForExpectations.add(
330 "expectedFramesDelivered: " + expectedFramesDelivered);
331 }
332 if (!expectedBuffers.isEmpty()) {
333 stillWaitingForExpectations.add(
334 "expectedBuffers: " + expectedBuffers.size());
335 }
336 if (!expectedStateChanges.isEmpty()) {
337 stillWaitingForExpectations.add(
338 "expectedStateChanges: " + expectedStateChanges.size());
339 }
340 if (!expectedRemoteDataChannelLabels.isEmpty()) {
341 stillWaitingForExpectations.add("expectedRemoteDataChannelLabels: " +
342 expectedRemoteDataChannelLabels.size());
343 }
344 if (expectedStatsCallbacks != 0) {
345 stillWaitingForExpectations.add(
346 "expectedStatsCallbacks: " + expectedStatsCallbacks);
347 }
348 return stillWaitingForExpectations;
349 }
350
351 public boolean waitForAllExpectationsToBeSatisfied(int timeoutSeconds) {
352 // TODO(fischman): problems with this approach:
353 // - come up with something better than a poll loop
354 // - avoid serializing expectations explicitly; the test is not as robust
355 // as it could be because it must place expectations between wait
356 // statements very precisely (e.g. frame must not arrive before its
357 // expectation, and expectation must not be registered so early as to
358 // stall a wait). Use callbacks to fire off dependent steps instead of
359 // explicitly waiting, so there can be just a single wait at the end of
360 // the test.
361 long endTime = System.currentTimeMillis() + 1000 * timeoutSeconds;
362 TreeSet<String> prev = null;
363 TreeSet<String> stillWaitingForExpectations = unsatisfiedExpectations();
364 while (!stillWaitingForExpectations.isEmpty()) {
365 if (!stillWaitingForExpectations.equals(prev)) {
366 System.out.println(
367 name + " still waiting at\n " +
368 (new Throwable()).getStackTrace()[1] +
369 "\n for: " +
370 Arrays.toString(stillWaitingForExpectations.toArray()));
371 }
372 if (endTime < System.currentTimeMillis()) {
373 System.out.println(name + " timed out waiting for: "
374 + Arrays.toString(stillWaitingForExpectations.toArray()));
375 return false;
376 }
377 try {
378 Thread.sleep(10);
379 } catch (InterruptedException e) {
380 throw new RuntimeException(e);
381 }
382 prev = stillWaitingForExpectations;
383 stillWaitingForExpectations = unsatisfiedExpectations();
384 }
385 if (prev == null) {
386 System.out.println(name + " didn't need to wait at\n " +
387 (new Throwable()).getStackTrace()[1]);
388 }
389 return true;
390 }
391
392 // This methods return a list of all currently gathered ice candidates or wa its until
393 // 1 candidate have been gathered.
394 public List<IceCandidate> getAtLeastOneIceCandidate() throws InterruptedExce ption {
395 synchronized (gotIceCandidates) {
396 while (gotIceCandidates.isEmpty()) {
397 gotIceCandidates.wait();
398 }
399 return new LinkedList<IceCandidate>(gotIceCandidates);
400 }
401 }
402 }
403
404 private static class SdpObserverLatch implements SdpObserver {
405 private boolean success = false;
406 private SessionDescription sdp = null;
407 private String error = null;
408 private CountDownLatch latch = new CountDownLatch(1);
409
410 public SdpObserverLatch() {}
411
412 @Override
413 public void onCreateSuccess(SessionDescription sdp) {
414 this.sdp = sdp;
415 onSetSuccess();
416 }
417
418 @Override
419 public void onSetSuccess() {
420 success = true;
421 latch.countDown();
422 }
423
424 @Override
425 public void onCreateFailure(String error) {
426 onSetFailure(error);
427 }
428
429 @Override
430 public void onSetFailure(String error) {
431 this.error = error;
432 latch.countDown();
433 }
434
435 public boolean await() {
436 try {
437 assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));
438 return getSuccess();
439 } catch (Exception e) {
440 throw new RuntimeException(e);
441 }
442 }
443
444 public boolean getSuccess() {
445 return success;
446 }
447
448 public SessionDescription getSdp() {
449 return sdp;
450 }
451
452 public String getError() {
453 return error;
454 }
455 }
456
457 static int videoWindowsMapped = -1;
458
459 private static VideoRenderer createVideoRenderer(
460 VideoRenderer.Callbacks videoCallbacks) {
461 if (!RENDER_TO_GUI) {
462 return new VideoRenderer(videoCallbacks);
463 }
464 ++videoWindowsMapped;
465 assertTrue(videoWindowsMapped < 4);
466 int x = videoWindowsMapped % 2 != 0 ? 700 : 0;
467 int y = videoWindowsMapped >= 2 ? 0 : 500;
468 return VideoRenderer.createGui(x, y);
469 }
470
471 // Return a weak reference to test that ownership is correctly held by
472 // PeerConnection, not by test code.
473 private static WeakReference<MediaStream> addTracksToPC(
474 PeerConnectionFactory factory, PeerConnection pc,
475 VideoSource videoSource,
476 String streamLabel, String videoTrackId, String audioTrackId,
477 VideoRenderer.Callbacks videoCallbacks) {
478 MediaStream lMS = factory.createLocalMediaStream(streamLabel);
479 VideoTrack videoTrack =
480 factory.createVideoTrack(videoTrackId, videoSource);
481 assertNotNull(videoTrack);
482 VideoRenderer videoRenderer = createVideoRenderer(videoCallbacks);
483 assertNotNull(videoRenderer);
484 videoTrack.addRenderer(videoRenderer);
485 lMS.addTrack(videoTrack);
486 // Just for fun, let's remove and re-add the track.
487 lMS.removeTrack(videoTrack);
488 lMS.addTrack(videoTrack);
489 lMS.addTrack(factory.createAudioTrack(
490 audioTrackId, factory.createAudioSource(new MediaConstraints())));
491 pc.addStream(lMS);
492 return new WeakReference<MediaStream>(lMS);
493 }
494
495 // Used for making sure thread handles are not leaked.
496 // Call initializeThreadCheck before a test and finalizeThreadCheck after
497 // a test.
498 void initializeThreadCheck() {
499 System.gc(); // Encourage any GC-related threads to start up.
500 threadsBeforeTest = allThreads();
501 }
502
503 void finalizeThreadCheck() throws Exception {
504 // TreeSet<String> threadsAfterTest = allThreads();
505
506 // TODO(tommi): Figure out a more reliable way to do this test. As is
507 // we're seeing three possible 'normal' situations:
508 // 1. before and after sets are equal.
509 // 2. before contains 3 threads that do not exist in after.
510 // 3. after contains 3 threads that do not exist in before.
511 //
512 // Maybe it would be better to do the thread enumeration from C++ and get
513 // the thread names as well, in order to determine what these 3 threads are.
514
515 // assertEquals(threadsBeforeTest, threadsAfterTest);
516 // Thread.sleep(100);
517 }
518
519 void doTest() throws Exception {
520 // Allow loopback interfaces too since our Android devices often don't
521 // have those.
522 PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
523 options.networkIgnoreMask = 0;
524 PeerConnectionFactory factory = new PeerConnectionFactory(options);
525 // Uncomment to get ALL WebRTC tracing and SENSITIVE libjingle logging.
526 // NOTE: this _must_ happen while |factory| is alive!
527 // Logging.enableTracing(
528 // "/tmp/PeerConnectionTest-log.txt",
529 // EnumSet.of(Logging.TraceLevel.TRACE_ALL),
530 // Logging.Severity.LS_SENSITIVE);
531
532 MediaConstraints pcConstraints = new MediaConstraints();
533 pcConstraints.mandatory.add(
534 new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
535
536 LinkedList<PeerConnection.IceServer> iceServers =
537 new LinkedList<PeerConnection.IceServer>();
538 iceServers.add(new PeerConnection.IceServer(
539 "stun:stun.l.google.com:19302"));
540 iceServers.add(new PeerConnection.IceServer(
541 "turn:fake.example.com", "fakeUsername", "fakePassword"));
542 ObserverExpectations offeringExpectations =
543 new ObserverExpectations("PCTest:offerer");
544 PeerConnection offeringPC = factory.createPeerConnection(
545 iceServers, pcConstraints, offeringExpectations);
546 assertNotNull(offeringPC);
547
548 ObserverExpectations answeringExpectations =
549 new ObserverExpectations("PCTest:answerer");
550 PeerConnection answeringPC = factory.createPeerConnection(
551 iceServers, pcConstraints, answeringExpectations);
552 assertNotNull(answeringPC);
553
554 // We want to use the same camera for offerer & answerer, so create it here
555 // instead of in addTracksToPC.
556 VideoSource videoSource = factory.createVideoSource(
557 VideoCapturer.create(""), new MediaConstraints());
558
559 offeringExpectations.expectRenegotiationNeeded();
560 WeakReference<MediaStream> oLMS = addTracksToPC(
561 factory, offeringPC, videoSource, "offeredMediaStream",
562 "offeredVideoTrack", "offeredAudioTrack", offeringExpectations);
563
564 offeringExpectations.expectRenegotiationNeeded();
565 DataChannel offeringDC = offeringPC.createDataChannel(
566 "offeringDC", new DataChannel.Init());
567 assertEquals("offeringDC", offeringDC.label());
568
569 offeringExpectations.setDataChannel(offeringDC);
570 SdpObserverLatch sdpLatch = new SdpObserverLatch();
571 offeringPC.createOffer(sdpLatch, new MediaConstraints());
572 assertTrue(sdpLatch.await());
573 SessionDescription offerSdp = sdpLatch.getSdp();
574 assertEquals(offerSdp.type, SessionDescription.Type.OFFER);
575 assertFalse(offerSdp.description.isEmpty());
576
577 sdpLatch = new SdpObserverLatch();
578 answeringExpectations.expectSignalingChange(
579 SignalingState.HAVE_REMOTE_OFFER);
580 answeringExpectations.expectAddStream("offeredMediaStream");
581 // SCTP DataChannels are announced via OPEN messages over the established
582 // connection (not via SDP), so answeringExpectations can only register
583 // expecting the channel during ICE, below.
584 answeringPC.setRemoteDescription(sdpLatch, offerSdp);
585 assertEquals(
586 PeerConnection.SignalingState.STABLE, offeringPC.signalingState());
587 assertTrue(sdpLatch.await());
588 assertNull(sdpLatch.getSdp());
589
590 answeringExpectations.expectRenegotiationNeeded();
591 WeakReference<MediaStream> aLMS = addTracksToPC(
592 factory, answeringPC, videoSource, "answeredMediaStream",
593 "answeredVideoTrack", "answeredAudioTrack", answeringExpectations);
594
595 sdpLatch = new SdpObserverLatch();
596 answeringPC.createAnswer(sdpLatch, new MediaConstraints());
597 assertTrue(sdpLatch.await());
598 SessionDescription answerSdp = sdpLatch.getSdp();
599 assertEquals(answerSdp.type, SessionDescription.Type.ANSWER);
600 assertFalse(answerSdp.description.isEmpty());
601
602 offeringExpectations.expectIceCandidates(2);
603 answeringExpectations.expectIceCandidates(2);
604
605 offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
606 answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
607
608 sdpLatch = new SdpObserverLatch();
609 answeringExpectations.expectSignalingChange(SignalingState.STABLE);
610 answeringPC.setLocalDescription(sdpLatch, answerSdp);
611 assertTrue(sdpLatch.await());
612 assertNull(sdpLatch.getSdp());
613
614 sdpLatch = new SdpObserverLatch();
615 offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER);
616 offeringPC.setLocalDescription(sdpLatch, offerSdp);
617 assertTrue(sdpLatch.await());
618 assertNull(sdpLatch.getSdp());
619 sdpLatch = new SdpObserverLatch();
620 offeringExpectations.expectSignalingChange(SignalingState.STABLE);
621 offeringExpectations.expectAddStream("answeredMediaStream");
622
623 offeringExpectations.expectIceConnectionChange(
624 IceConnectionState.CHECKING);
625 offeringExpectations.expectIceConnectionChange(
626 IceConnectionState.CONNECTED);
627 // TODO(bemasc): uncomment once delivery of ICECompleted is reliable
628 // (https://code.google.com/p/webrtc/issues/detail?id=3021).
629 //
630 // offeringExpectations.expectIceConnectionChange(
631 // IceConnectionState.COMPLETED);
632 answeringExpectations.expectIceConnectionChange(
633 IceConnectionState.CHECKING);
634 answeringExpectations.expectIceConnectionChange(
635 IceConnectionState.CONNECTED);
636
637 offeringPC.setRemoteDescription(sdpLatch, answerSdp);
638 assertTrue(sdpLatch.await());
639 assertNull(sdpLatch.getSdp());
640
641 assertEquals(offeringPC.getLocalDescription().type, offerSdp.type);
642 assertEquals(offeringPC.getRemoteDescription().type, answerSdp.type);
643 assertEquals(answeringPC.getLocalDescription().type, answerSdp.type);
644 assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type);
645
646 assertEquals(offeringPC.getSenders().size(), 2);
647 assertEquals(offeringPC.getReceivers().size(), 2);
648 assertEquals(answeringPC.getSenders().size(), 2);
649 assertEquals(answeringPC.getReceivers().size(), 2);
650
651 if (!RENDER_TO_GUI) {
652 // Wait for at least some frames to be delivered at each end (number
653 // chosen arbitrarily).
654 offeringExpectations.expectFramesDelivered(10);
655 answeringExpectations.expectFramesDelivered(10);
656 }
657
658 offeringExpectations.expectStateChange(DataChannel.State.OPEN);
659 // See commentary about SCTP DataChannels above for why this is here.
660 answeringExpectations.expectDataChannel("offeringDC");
661 answeringExpectations.expectStateChange(DataChannel.State.OPEN);
662
663 // Wait for at least one ice candidate from the offering PC and forward them to the answering
664 // PC.
665 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate ()) {
666 answeringPC.addIceCandidate(candidate);
667 }
668
669 // Wait for at least one ice candidate from the answering PC and forward the m to the offering
670 // PC.
671 for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidat e()) {
672 offeringPC.addIceCandidate(candidate);
673 }
674
675 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_ SECONDS));
676 assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT _SECONDS));
677
678 assertEquals(
679 PeerConnection.SignalingState.STABLE, offeringPC.signalingState());
680 assertEquals(
681 PeerConnection.SignalingState.STABLE, answeringPC.signalingState());
682
683 // Test send & receive UTF-8 text.
684 answeringExpectations.expectMessage(
685 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
686 DataChannel.Buffer buffer = new DataChannel.Buffer(
687 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
688 assertTrue(offeringExpectations.dataChannel.send(buffer));
689 assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT _SECONDS));
690
691 // Construct this binary message two different ways to ensure no
692 // shortcuts are taken.
693 ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5);
694 for (byte i = 1; i < 6; ++i) {
695 expectedBinaryMessage.put(i);
696 }
697 expectedBinaryMessage.flip();
698 offeringExpectations.expectMessage(expectedBinaryMessage, true);
699 assertTrue(answeringExpectations.dataChannel.send(
700 new DataChannel.Buffer(
701 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true)));
702 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_ SECONDS));
703
704 offeringExpectations.expectStateChange(DataChannel.State.CLOSING);
705 answeringExpectations.expectStateChange(DataChannel.State.CLOSING);
706 offeringExpectations.expectStateChange(DataChannel.State.CLOSED);
707 answeringExpectations.expectStateChange(DataChannel.State.CLOSED);
708 answeringExpectations.dataChannel.close();
709 offeringExpectations.dataChannel.close();
710
711 if (RENDER_TO_GUI) {
712 try {
713 Thread.sleep(3000);
714 } catch (Throwable t) {
715 throw new RuntimeException(t);
716 }
717 }
718
719 // TODO(fischman) MOAR test ideas:
720 // - Test that PC.removeStream() works; requires a second
721 // createOffer/createAnswer dance.
722 // - audit each place that uses |constraints| for specifying non-trivial
723 // constraints (and ensure they're honored).
724 // - test error cases
725 // - ensure reasonable coverage of _jni.cc is achieved. Coverage is
726 // extra-important because of all the free-text (class/method names, etc)
727 // in JNI-style programming; make sure no typos!
728 // - Test that shutdown mid-interaction is crash-free.
729
730 // Free the Java-land objects, collect them, and sleep a bit to make sure we
731 // don't get late-arrival crashes after the Java-land objects have been
732 // freed.
733 shutdownPC(offeringPC, offeringExpectations);
734 offeringPC = null;
735 shutdownPC(answeringPC, answeringExpectations);
736 answeringPC = null;
737 videoSource.dispose();
738 factory.dispose();
739 System.gc();
740 }
741
742 private static void shutdownPC(
743 PeerConnection pc, ObserverExpectations expectations) {
744 expectations.dataChannel.unregisterObserver();
745 expectations.dataChannel.dispose();
746 expectations.expectStatsCallback();
747 assertTrue(pc.getStats(expectations, null));
748 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS) );
749 expectations.expectIceConnectionChange(IceConnectionState.CLOSED);
750 expectations.expectSignalingChange(SignalingState.CLOSED);
751 pc.close();
752 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS) );
753 expectations.expectStatsCallback();
754 assertTrue(pc.getStats(expectations, null));
755 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS) );
756
757 System.out.println("FYI stats: ");
758 int reportIndex = -1;
759 for (StatsReport[] reports : expectations.takeStatsReports()) {
760 System.out.println(" Report #" + (++reportIndex));
761 for (int i = 0; i < reports.length; ++i) {
762 System.out.println(" " + reports[i].toString());
763 }
764 }
765 assertEquals(1, reportIndex);
766 System.out.println("End stats.");
767
768 pc.dispose();
769 }
770
771 // Returns a set of thread IDs belonging to this process, as Strings.
772 private static TreeSet<String> allThreads() {
773 TreeSet<String> threads = new TreeSet<String>();
774 // This pokes at /proc instead of using the Java APIs because we're also
775 // looking for libjingle/webrtc native threads, most of which won't have
776 // attached to the JVM.
777 for (String threadId : (new File("/proc/self/task")).list()) {
778 threads.add(threadId);
779 }
780 return threads;
781 }
782 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698