OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2013 Google Inc. | 3 * Copyright 2013 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 13 matching lines...) Expand all Loading... |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 package org.webrtc; | 28 package org.webrtc; |
29 | 29 |
30 import org.webrtc.PeerConnection.IceConnectionState; | 30 import org.webrtc.PeerConnection.IceConnectionState; |
31 import org.webrtc.PeerConnection.IceGatheringState; | 31 import org.webrtc.PeerConnection.IceGatheringState; |
32 import org.webrtc.PeerConnection.SignalingState; | 32 import org.webrtc.PeerConnection.SignalingState; |
33 | 33 |
| 34 import android.test.suitebuilder.annotation.MediumTest; |
| 35 |
34 import java.io.File; | 36 import java.io.File; |
35 import java.lang.ref.WeakReference; | 37 import java.lang.ref.WeakReference; |
36 import java.nio.ByteBuffer; | 38 import java.nio.ByteBuffer; |
37 import java.nio.charset.Charset; | 39 import java.nio.charset.Charset; |
38 import java.util.Arrays; | 40 import java.util.Arrays; |
39 import java.util.IdentityHashMap; | 41 import java.util.IdentityHashMap; |
40 import java.util.LinkedList; | 42 import java.util.LinkedList; |
41 import java.util.List; | 43 import java.util.List; |
42 import java.util.Map; | 44 import java.util.Map; |
43 import java.util.TreeSet; | 45 import java.util.TreeSet; |
44 import java.util.concurrent.CountDownLatch; | 46 import java.util.concurrent.CountDownLatch; |
45 import java.util.concurrent.TimeUnit; | 47 import java.util.concurrent.TimeUnit; |
46 | 48 |
47 import static junit.framework.Assert.*; | 49 /** End-to-end tests for PeerConnection.java. */ |
| 50 import android.test.ActivityTestCase; |
48 | 51 |
49 /** End-to-end tests for PeerConnection.java. */ | 52 public class PeerConnectionTest extends ActivityTestCase { |
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; | 53 private static final int TIMEOUT_SECONDS = 20; |
54 private TreeSet<String> threadsBeforeTest = null; | 54 private TreeSet<String> threadsBeforeTest = null; |
55 | 55 |
| 56 @Override |
| 57 protected void setUp() { |
| 58 assertTrue(PeerConnectionFactory.initializeAndroidGlobals( |
| 59 getInstrumentation().getContext(), true, true, true)); |
| 60 } |
| 61 |
56 private static class ObserverExpectations implements PeerConnection.Observer, | 62 private static class ObserverExpectations implements PeerConnection.Observer, |
57 VideoRenderer.Callbacks, | 63 VideoRenderer.Callbacks, |
58 DataChannel.Observer, | 64 DataChannel.Observer, |
59 StatsObserver { | 65 StatsObserver { |
60 private final String name; | 66 private final String name; |
61 private int expectedIceCandidates = 0; | 67 private int expectedIceCandidates = 0; |
62 private int expectedErrors = 0; | 68 private int expectedErrors = 0; |
63 private int expectedRenegotiations = 0; | 69 private int expectedRenegotiations = 0; |
64 private int previouslySeenWidth = 0; | 70 private int previouslySeenWidth = 0; |
65 private int previouslySeenHeight = 0; | 71 private int previouslySeenHeight = 0; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 // We don't assert expectedIceCandidates >= 0 because it's hard to know | 117 // We don't assert expectedIceCandidates >= 0 because it's hard to know |
112 // how many to expect, in general. We only use expectIceCandidates to | 118 // how many to expect, in general. We only use expectIceCandidates to |
113 // assert a minimal count. | 119 // assert a minimal count. |
114 synchronized (gotIceCandidates) { | 120 synchronized (gotIceCandidates) { |
115 gotIceCandidates.add(candidate); | 121 gotIceCandidates.add(candidate); |
116 gotIceCandidates.notifyAll(); | 122 gotIceCandidates.notifyAll(); |
117 } | 123 } |
118 } | 124 } |
119 | 125 |
120 private synchronized void setSize(int width, int height) { | 126 private synchronized void setSize(int width, int height) { |
121 assertFalse(RENDER_TO_GUI); | |
122 // Because different camera devices (fake & physical) produce different | 127 // Because different camera devices (fake & physical) produce different |
123 // resolutions, we only sanity-check the set sizes, | 128 // resolutions, we only sanity-check the set sizes, |
124 assertTrue(width > 0); | 129 assertTrue(width > 0); |
125 assertTrue(height > 0); | 130 assertTrue(height > 0); |
126 if (previouslySeenWidth > 0) { | 131 if (previouslySeenWidth > 0) { |
127 assertEquals(previouslySeenWidth, width); | 132 assertEquals(previouslySeenWidth, width); |
128 assertEquals(previouslySeenHeight, height); | 133 assertEquals(previouslySeenHeight, height); |
129 } else { | 134 } else { |
130 previouslySeenWidth = width; | 135 previouslySeenWidth = width; |
131 previouslySeenHeight = height; | 136 previouslySeenHeight = height; |
132 } | 137 } |
133 } | 138 } |
134 | 139 |
135 public synchronized void expectFramesDelivered(int count) { | 140 public synchronized void expectFramesDelivered(int count) { |
136 assertFalse(RENDER_TO_GUI); | |
137 expectedFramesDelivered += count; | 141 expectedFramesDelivered += count; |
138 } | 142 } |
139 | 143 |
140 @Override | 144 @Override |
141 public synchronized void renderFrame(VideoRenderer.I420Frame frame) { | 145 public synchronized void renderFrame(VideoRenderer.I420Frame frame) { |
142 setSize(frame.rotatedWidth(), frame.rotatedHeight()); | 146 setSize(frame.rotatedWidth(), frame.rotatedHeight()); |
143 --expectedFramesDelivered; | 147 --expectedFramesDelivered; |
144 VideoRenderer.renderFrameDone(frame); | 148 VideoRenderer.renderFrameDone(frame); |
145 } | 149 } |
146 | 150 |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 | 455 |
452 public String getError() { | 456 public String getError() { |
453 return error; | 457 return error; |
454 } | 458 } |
455 } | 459 } |
456 | 460 |
457 static int videoWindowsMapped = -1; | 461 static int videoWindowsMapped = -1; |
458 | 462 |
459 private static VideoRenderer createVideoRenderer( | 463 private static VideoRenderer createVideoRenderer( |
460 VideoRenderer.Callbacks videoCallbacks) { | 464 VideoRenderer.Callbacks videoCallbacks) { |
461 if (!RENDER_TO_GUI) { | 465 return new VideoRenderer(videoCallbacks); |
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 } | 466 } |
470 | 467 |
471 // Return a weak reference to test that ownership is correctly held by | 468 // Return a weak reference to test that ownership is correctly held by |
472 // PeerConnection, not by test code. | 469 // PeerConnection, not by test code. |
473 private static WeakReference<MediaStream> addTracksToPC( | 470 private static WeakReference<MediaStream> addTracksToPC( |
474 PeerConnectionFactory factory, PeerConnection pc, | 471 PeerConnectionFactory factory, PeerConnection pc, |
475 VideoSource videoSource, | 472 VideoSource videoSource, |
476 String streamLabel, String videoTrackId, String audioTrackId, | 473 String streamLabel, String videoTrackId, String audioTrackId, |
477 VideoRenderer.Callbacks videoCallbacks) { | 474 VideoRenderer.Callbacks videoCallbacks) { |
478 MediaStream lMS = factory.createLocalMediaStream(streamLabel); | 475 MediaStream lMS = factory.createLocalMediaStream(streamLabel); |
(...skipping 30 matching lines...) Expand all Loading... |
509 // 2. before contains 3 threads that do not exist in after. | 506 // 2. before contains 3 threads that do not exist in after. |
510 // 3. after contains 3 threads that do not exist in before. | 507 // 3. after contains 3 threads that do not exist in before. |
511 // | 508 // |
512 // Maybe it would be better to do the thread enumeration from C++ and get | 509 // 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. | 510 // the thread names as well, in order to determine what these 3 threads are. |
514 | 511 |
515 // assertEquals(threadsBeforeTest, threadsAfterTest); | 512 // assertEquals(threadsBeforeTest, threadsAfterTest); |
516 // Thread.sleep(100); | 513 // Thread.sleep(100); |
517 } | 514 } |
518 | 515 |
519 void doTest() throws Exception { | 516 @MediumTest |
| 517 public void testCompleteSession() throws Exception { |
520 // Allow loopback interfaces too since our Android devices often don't | 518 // Allow loopback interfaces too since our Android devices often don't |
521 // have those. | 519 // have those. |
522 PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); | 520 PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); |
523 options.networkIgnoreMask = 0; | 521 options.networkIgnoreMask = 0; |
524 PeerConnectionFactory factory = new PeerConnectionFactory(options); | 522 PeerConnectionFactory factory = new PeerConnectionFactory(options); |
525 // Uncomment to get ALL WebRTC tracing and SENSITIVE libjingle logging. | 523 // Uncomment to get ALL WebRTC tracing and SENSITIVE libjingle logging. |
526 // NOTE: this _must_ happen while |factory| is alive! | 524 // NOTE: this _must_ happen while |factory| is alive! |
527 // Logging.enableTracing( | 525 // Logging.enableTracing( |
528 // "/tmp/PeerConnectionTest-log.txt", | 526 // "/tmp/PeerConnectionTest-log.txt", |
529 // EnumSet.of(Logging.TraceLevel.TRACE_ALL), | 527 // EnumSet.of(Logging.TraceLevel.TRACE_ALL), |
(...skipping 17 matching lines...) Expand all Loading... |
547 | 545 |
548 ObserverExpectations answeringExpectations = | 546 ObserverExpectations answeringExpectations = |
549 new ObserverExpectations("PCTest:answerer"); | 547 new ObserverExpectations("PCTest:answerer"); |
550 PeerConnection answeringPC = factory.createPeerConnection( | 548 PeerConnection answeringPC = factory.createPeerConnection( |
551 iceServers, pcConstraints, answeringExpectations); | 549 iceServers, pcConstraints, answeringExpectations); |
552 assertNotNull(answeringPC); | 550 assertNotNull(answeringPC); |
553 | 551 |
554 // We want to use the same camera for offerer & answerer, so create it here | 552 // We want to use the same camera for offerer & answerer, so create it here |
555 // instead of in addTracksToPC. | 553 // instead of in addTracksToPC. |
556 VideoSource videoSource = factory.createVideoSource( | 554 VideoSource videoSource = factory.createVideoSource( |
557 VideoCapturer.create(""), new MediaConstraints()); | 555 VideoCapturerAndroid.create("", null), new MediaConstraints()); |
558 | 556 |
559 offeringExpectations.expectRenegotiationNeeded(); | 557 offeringExpectations.expectRenegotiationNeeded(); |
560 WeakReference<MediaStream> oLMS = addTracksToPC( | 558 WeakReference<MediaStream> oLMS = addTracksToPC( |
561 factory, offeringPC, videoSource, "offeredMediaStream", | 559 factory, offeringPC, videoSource, "offeredMediaStream", |
562 "offeredVideoTrack", "offeredAudioTrack", offeringExpectations); | 560 "offeredVideoTrack", "offeredAudioTrack", offeringExpectations); |
563 | 561 |
564 offeringExpectations.expectRenegotiationNeeded(); | 562 offeringExpectations.expectRenegotiationNeeded(); |
565 DataChannel offeringDC = offeringPC.createDataChannel( | 563 DataChannel offeringDC = offeringPC.createDataChannel( |
566 "offeringDC", new DataChannel.Init()); | 564 "offeringDC", new DataChannel.Init()); |
567 assertEquals("offeringDC", offeringDC.label()); | 565 assertEquals("offeringDC", offeringDC.label()); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 assertEquals(offeringPC.getLocalDescription().type, offerSdp.type); | 639 assertEquals(offeringPC.getLocalDescription().type, offerSdp.type); |
642 assertEquals(offeringPC.getRemoteDescription().type, answerSdp.type); | 640 assertEquals(offeringPC.getRemoteDescription().type, answerSdp.type); |
643 assertEquals(answeringPC.getLocalDescription().type, answerSdp.type); | 641 assertEquals(answeringPC.getLocalDescription().type, answerSdp.type); |
644 assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type); | 642 assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type); |
645 | 643 |
646 assertEquals(offeringPC.getSenders().size(), 2); | 644 assertEquals(offeringPC.getSenders().size(), 2); |
647 assertEquals(offeringPC.getReceivers().size(), 2); | 645 assertEquals(offeringPC.getReceivers().size(), 2); |
648 assertEquals(answeringPC.getSenders().size(), 2); | 646 assertEquals(answeringPC.getSenders().size(), 2); |
649 assertEquals(answeringPC.getReceivers().size(), 2); | 647 assertEquals(answeringPC.getReceivers().size(), 2); |
650 | 648 |
651 if (!RENDER_TO_GUI) { | 649 |
652 // Wait for at least some frames to be delivered at each end (number | 650 // Wait for at least some frames to be delivered at each end (number |
653 // chosen arbitrarily). | 651 // chosen arbitrarily). |
654 offeringExpectations.expectFramesDelivered(10); | 652 offeringExpectations.expectFramesDelivered(10); |
655 answeringExpectations.expectFramesDelivered(10); | 653 answeringExpectations.expectFramesDelivered(10); |
656 } | |
657 | 654 |
658 offeringExpectations.expectStateChange(DataChannel.State.OPEN); | 655 offeringExpectations.expectStateChange(DataChannel.State.OPEN); |
659 // See commentary about SCTP DataChannels above for why this is here. | 656 // See commentary about SCTP DataChannels above for why this is here. |
660 answeringExpectations.expectDataChannel("offeringDC"); | 657 answeringExpectations.expectDataChannel("offeringDC"); |
661 answeringExpectations.expectStateChange(DataChannel.State.OPEN); | 658 answeringExpectations.expectStateChange(DataChannel.State.OPEN); |
662 | 659 |
663 // Wait for at least one ice candidate from the offering PC and forward them
to the answering | 660 // Wait for at least one ice candidate from the offering PC and forward them
to the answering |
664 // PC. | 661 // PC. |
665 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate
()) { | 662 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate
()) { |
666 answeringPC.addIceCandidate(candidate); | 663 answeringPC.addIceCandidate(candidate); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
701 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true))); | 698 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true))); |
702 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_
SECONDS)); | 699 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_
SECONDS)); |
703 | 700 |
704 offeringExpectations.expectStateChange(DataChannel.State.CLOSING); | 701 offeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
705 answeringExpectations.expectStateChange(DataChannel.State.CLOSING); | 702 answeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
706 offeringExpectations.expectStateChange(DataChannel.State.CLOSED); | 703 offeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
707 answeringExpectations.expectStateChange(DataChannel.State.CLOSED); | 704 answeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
708 answeringExpectations.dataChannel.close(); | 705 answeringExpectations.dataChannel.close(); |
709 offeringExpectations.dataChannel.close(); | 706 offeringExpectations.dataChannel.close(); |
710 | 707 |
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: | 708 // TODO(fischman) MOAR test ideas: |
720 // - Test that PC.removeStream() works; requires a second | 709 // - Test that PC.removeStream() works; requires a second |
721 // createOffer/createAnswer dance. | 710 // createOffer/createAnswer dance. |
722 // - audit each place that uses |constraints| for specifying non-trivial | 711 // - audit each place that uses |constraints| for specifying non-trivial |
723 // constraints (and ensure they're honored). | 712 // constraints (and ensure they're honored). |
724 // - test error cases | 713 // - test error cases |
725 // - ensure reasonable coverage of _jni.cc is achieved. Coverage is | 714 // - ensure reasonable coverage of _jni.cc is achieved. Coverage is |
726 // extra-important because of all the free-text (class/method names, etc) | 715 // extra-important because of all the free-text (class/method names, etc) |
727 // in JNI-style programming; make sure no typos! | 716 // in JNI-style programming; make sure no typos! |
728 // - Test that shutdown mid-interaction is crash-free. | 717 // - Test that shutdown mid-interaction is crash-free. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 TreeSet<String> threads = new TreeSet<String>(); | 762 TreeSet<String> threads = new TreeSet<String>(); |
774 // This pokes at /proc instead of using the Java APIs because we're also | 763 // 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 | 764 // looking for libjingle/webrtc native threads, most of which won't have |
776 // attached to the JVM. | 765 // attached to the JVM. |
777 for (String threadId : (new File("/proc/self/task")).list()) { | 766 for (String threadId : (new File("/proc/self/task")).list()) { |
778 threads.add(threadId); | 767 threads.add(threadId); |
779 } | 768 } |
780 return threads; | 769 return threads; |
781 } | 770 } |
782 } | 771 } |
OLD | NEW |