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

Side by Side Diff: talk/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java

Issue 1235563006: Move talk/examples/* to webrtc/examples. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: 201508051337 Created 5 years, 4 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 2014 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.appspot.apprtc.test;
29
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.concurrent.CountDownLatch;
33 import java.util.concurrent.TimeUnit;
34
35 import org.appspot.apprtc.AppRTCClient.SignalingParameters;
36 import org.appspot.apprtc.PeerConnectionClient;
37 import org.appspot.apprtc.PeerConnectionClient.PeerConnectionEvents;
38 import org.appspot.apprtc.PeerConnectionClient.PeerConnectionParameters;
39 import org.appspot.apprtc.util.LooperExecutor;
40 import org.webrtc.IceCandidate;
41 import org.webrtc.MediaConstraints;
42 import org.webrtc.PeerConnection;
43 import org.webrtc.PeerConnectionFactory;
44 import org.webrtc.SessionDescription;
45 import org.webrtc.StatsReport;
46 import org.webrtc.VideoRenderer;
47
48 import android.test.InstrumentationTestCase;
49 import android.util.Log;
50
51 public class PeerConnectionClientTest extends InstrumentationTestCase
52 implements PeerConnectionEvents {
53 private static final String TAG = "RTCClientTest";
54 private static final int ICE_CONNECTION_WAIT_TIMEOUT = 10000;
55 private static final int WAIT_TIMEOUT = 7000;
56 private static final int CAMERA_SWITCH_ATTEMPTS = 3;
57 private static final int VIDEO_RESTART_ATTEMPTS = 3;
58 private static final int VIDEO_RESTART_TIMEOUT = 500;
59 private static final int EXPECTED_VIDEO_FRAMES = 10;
60 private static final String VIDEO_CODEC_VP8 = "VP8";
61 private static final String VIDEO_CODEC_VP9 = "VP9";
62 private static final String VIDEO_CODEC_H264 = "H264";
63 private static final int AUDIO_RUN_TIMEOUT = 1000;
64 private static final String LOCAL_RENDERER_NAME = "Local renderer";
65 private static final String REMOTE_RENDERER_NAME = "Remote renderer";
66
67 // The peer connection client is assumed to be thread safe in itself; the
68 // reference is written by the test thread and read by worker threads.
69 private volatile PeerConnectionClient pcClient;
70 private volatile boolean loopback;
71
72 // These are protected by their respective event objects.
73 private LooperExecutor signalingExecutor;
74 private boolean isClosed;
75 private boolean isIceConnected;
76 private SessionDescription localSdp;
77 private List<IceCandidate> iceCandidates = new LinkedList<IceCandidate>();
78 private final Object localSdpEvent = new Object();
79 private final Object iceCandidateEvent = new Object();
80 private final Object iceConnectedEvent = new Object();
81 private final Object closeEvent = new Object();
82
83 // Mock renderer implementation.
84 private static class MockRenderer implements VideoRenderer.Callbacks {
85 // These are protected by 'this' since we gets called from worker threads.
86 private String rendererName;
87 private boolean renderFrameCalled = false;
88
89 // Thread-safe in itself.
90 private CountDownLatch doneRendering;
91
92 public MockRenderer(int expectedFrames, String rendererName) {
93 this.rendererName = rendererName;
94 reset(expectedFrames);
95 }
96
97 // Resets render to wait for new amount of video frames.
98 public synchronized void reset(int expectedFrames) {
99 renderFrameCalled = false;
100 doneRendering = new CountDownLatch(expectedFrames);
101 }
102
103 // TODO(guoweis): Remove this once chrome code base is updated.
104 @Override
105 public boolean canApplyRotation() {
106 return false;
107 }
108
109 @Override
110 public synchronized void renderFrame(VideoRenderer.I420Frame frame) {
111 if (!renderFrameCalled) {
112 if (rendererName != null) {
113 Log.d(TAG, rendererName + " render frame: " + frame.width + " x " + fr ame.height);
114 } else {
115 Log.d(TAG, "Render frame: " + frame.width + " x " + frame.height);
116 }
117 }
118 renderFrameCalled = true;
119 doneRendering.countDown();
120 }
121
122
123 // This method shouldn't hold any locks or touch member variables since it
124 // blocks.
125 public boolean waitForFramesRendered(int timeoutMs)
126 throws InterruptedException {
127 doneRendering.await(timeoutMs, TimeUnit.MILLISECONDS);
128 return (doneRendering.getCount() <= 0);
129 }
130 }
131
132 // Peer connection events implementation.
133 @Override
134 public void onLocalDescription(SessionDescription sdp) {
135 Log.d(TAG, "LocalSDP type: " + sdp.type);
136 synchronized (localSdpEvent) {
137 localSdp = sdp;
138 localSdpEvent.notifyAll();
139 }
140 }
141
142 @Override
143 public void onIceCandidate(final IceCandidate candidate) {
144 synchronized(iceCandidateEvent) {
145 Log.d(TAG, "IceCandidate #" + iceCandidates.size() + " : " + candidate.toS tring());
146 if (loopback) {
147 // Loopback local ICE candidate in a separate thread to avoid adding
148 // remote ICE candidate in a local ICE candidate callback.
149 signalingExecutor.execute(new Runnable() {
150 @Override
151 public void run() {
152 pcClient.addRemoteIceCandidate(candidate);
153 }
154 });
155 }
156 iceCandidates.add(candidate);
157 iceCandidateEvent.notifyAll();
158 }
159 }
160
161 @Override
162 public void onIceConnected() {
163 Log.d(TAG, "ICE Connected");
164 synchronized(iceConnectedEvent) {
165 isIceConnected = true;
166 iceConnectedEvent.notifyAll();
167 }
168 }
169
170 @Override
171 public void onIceDisconnected() {
172 Log.d(TAG, "ICE Disconnected");
173 synchronized(iceConnectedEvent) {
174 isIceConnected = false;
175 iceConnectedEvent.notifyAll();
176 }
177 }
178
179 @Override
180 public void onPeerConnectionClosed() {
181 Log.d(TAG, "PeerConnection closed");
182 synchronized(closeEvent) {
183 isClosed = true;
184 closeEvent.notifyAll();
185 }
186 }
187
188 @Override
189 public void onPeerConnectionError(String description) {
190 fail("PC Error: " + description);
191 }
192
193 @Override
194 public void onPeerConnectionStatsReady(StatsReport[] reports) {
195 }
196
197 // Helper wait functions.
198 private boolean waitForLocalSDP(int timeoutMs)
199 throws InterruptedException {
200 synchronized(localSdpEvent) {
201 if (localSdp == null) {
202 localSdpEvent.wait(timeoutMs);
203 }
204 return (localSdp != null);
205 }
206 }
207
208 private boolean waitForIceCandidates(int timeoutMs)
209 throws InterruptedException {
210 synchronized(iceCandidateEvent) {
211 if (iceCandidates.size() == 0) {
212 iceCandidateEvent.wait(timeoutMs);
213 }
214 return (iceCandidates.size() > 0);
215 }
216 }
217
218 private boolean waitForIceConnected(int timeoutMs)
219 throws InterruptedException {
220 synchronized(iceConnectedEvent) {
221 if (!isIceConnected) {
222 iceConnectedEvent.wait(timeoutMs);
223 }
224 if (!isIceConnected) {
225 Log.e(TAG, "ICE connection failure");
226 }
227
228 return isIceConnected;
229 }
230 }
231
232 private boolean waitForPeerConnectionClosed(int timeoutMs)
233 throws InterruptedException {
234 synchronized(closeEvent) {
235 if (!isClosed) {
236 closeEvent.wait(timeoutMs);
237 }
238 return isClosed;
239 }
240 }
241
242 PeerConnectionClient createPeerConnectionClient(
243 MockRenderer localRenderer, MockRenderer remoteRenderer,
244 boolean enableVideo, String videoCodec) {
245 List<PeerConnection.IceServer> iceServers =
246 new LinkedList<PeerConnection.IceServer>();
247 SignalingParameters signalingParameters = new SignalingParameters(
248 iceServers, true, // iceServers, initiator.
249 null, null, null, // clientId, wssUrl, wssPostUrl.
250 null, null); // offerSdp, iceCandidates.
251 PeerConnectionParameters peerConnectionParameters =
252 new PeerConnectionParameters(
253 enableVideo, true, // videoCallEnabled, loopback.
254 0, 0, 0, 0, videoCodec, true, // video codec parameters.
255 0, "OPUS", false, true); // audio codec parameters.
256
257 PeerConnectionClient client = PeerConnectionClient.getInstance();
258 PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
259 options.networkIgnoreMask = 0;
260 client.setPeerConnectionFactoryOptions(options);
261 client.createPeerConnectionFactory(
262 getInstrumentation().getContext(), null,
263 peerConnectionParameters, this);
264 client.createPeerConnection(
265 localRenderer, remoteRenderer, signalingParameters);
266 client.createOffer();
267 return client;
268 }
269
270 @Override
271 public void setUp() {
272 signalingExecutor = new LooperExecutor();
273 signalingExecutor.requestStart();
274 }
275
276 @Override
277 public void tearDown() {
278 signalingExecutor.requestStop();
279 }
280
281 public void testSetLocalOfferMakesVideoFlowLocally()
282 throws InterruptedException {
283 Log.d(TAG, "testSetLocalOfferMakesVideoFlowLocally");
284 MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_R ENDERER_NAME);
285 pcClient = createPeerConnectionClient(
286 localRenderer, new MockRenderer(0, null), true, VIDEO_CODEC_VP8);
287
288 // Wait for local SDP and ice candidates set events.
289 assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
290 assertTrue("ICE candidates were not generated.",
291 waitForIceCandidates(WAIT_TIMEOUT));
292
293 // Check that local video frames were rendered.
294 assertTrue("Local video frames were not rendered.",
295 localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
296
297 pcClient.close();
298 assertTrue("PeerConnection close event was not received.",
299 waitForPeerConnectionClosed(WAIT_TIMEOUT));
300 Log.d(TAG, "testSetLocalOfferMakesVideoFlowLocally Done.");
301 }
302
303 private void doLoopbackTest(boolean enableVideo, String videoCodec)
304 throws InterruptedException {
305 loopback = true;
306 MockRenderer localRenderer = null;
307 MockRenderer remoteRenderer = null;
308 if (enableVideo) {
309 Log.d(TAG, "testLoopback for video " + videoCodec);
310 localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAM E);
311 remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_N AME);
312 } else {
313 Log.d(TAG, "testLoopback for audio.");
314 }
315 pcClient = createPeerConnectionClient(
316 localRenderer, remoteRenderer, enableVideo, videoCodec);
317
318 // Wait for local SDP, rename it to answer and set as remote SDP.
319 assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
320 SessionDescription remoteSdp = new SessionDescription(
321 SessionDescription.Type.fromCanonicalForm("answer"),
322 localSdp.description);
323 pcClient.setRemoteDescription(remoteSdp);
324
325 // Wait for ICE connection.
326 assertTrue("ICE connection failure.", waitForIceConnected(ICE_CONNECTION_WAI T_TIMEOUT));
327
328 if (enableVideo) {
329 // Check that local and remote video frames were rendered.
330 assertTrue("Local video frames were not rendered.",
331 localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
332 assertTrue("Remote video frames were not rendered.",
333 remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
334 } else {
335 // For audio just sleep for 1 sec.
336 // TODO(glaznev): check how we can detect that remote audio was rendered.
337 Thread.sleep(AUDIO_RUN_TIMEOUT);
338 }
339
340 pcClient.close();
341 assertTrue(waitForPeerConnectionClosed(WAIT_TIMEOUT));
342 Log.d(TAG, "testLoopback done.");
343 }
344
345 public void testLoopbackAudio() throws InterruptedException {
346 doLoopbackTest(false, VIDEO_CODEC_VP8);
347 }
348
349 public void testLoopbackVp8() throws InterruptedException {
350 doLoopbackTest(true, VIDEO_CODEC_VP8);
351 }
352
353 public void DISABLED_testLoopbackVp9() throws InterruptedException {
354 doLoopbackTest(true, VIDEO_CODEC_VP9);
355 }
356
357 public void testLoopbackH264() throws InterruptedException {
358 doLoopbackTest(true, VIDEO_CODEC_H264);
359 }
360
361 // Checks if default front camera can be switched to back camera and then
362 // again to front camera.
363 public void testCameraSwitch() throws InterruptedException {
364 Log.d(TAG, "testCameraSwitch");
365 loopback = true;
366
367 MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_R ENDERER_NAME);
368 MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE _RENDERER_NAME);
369
370 pcClient = createPeerConnectionClient(
371 localRenderer, remoteRenderer, true, VIDEO_CODEC_VP8);
372
373 // Wait for local SDP, rename it to answer and set as remote SDP.
374 assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
375 SessionDescription remoteSdp = new SessionDescription(
376 SessionDescription.Type.fromCanonicalForm("answer"),
377 localSdp.description);
378 pcClient.setRemoteDescription(remoteSdp);
379
380 // Wait for ICE connection.
381 assertTrue("ICE connection failure.", waitForIceConnected(ICE_CONNECTION_WAI T_TIMEOUT));
382
383 // Check that local and remote video frames were rendered.
384 assertTrue("Local video frames were not rendered before camera switch.",
385 localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
386 assertTrue("Remote video frames were not rendered before camera switch.",
387 remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
388
389 for (int i = 0; i < CAMERA_SWITCH_ATTEMPTS; i++) {
390 // Try to switch camera
391 pcClient.switchCamera();
392
393 // Reset video renders and check that local and remote video frames
394 // were rendered after camera switch.
395 localRenderer.reset(EXPECTED_VIDEO_FRAMES);
396 remoteRenderer.reset(EXPECTED_VIDEO_FRAMES);
397 assertTrue("Local video frames were not rendered after camera switch.",
398 localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
399 assertTrue("Remote video frames were not rendered after camera switch.",
400 remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
401 }
402 pcClient.close();
403 assertTrue(waitForPeerConnectionClosed(WAIT_TIMEOUT));
404 Log.d(TAG, "testCameraSwitch done.");
405 }
406
407 // Checks if video source can be restarted - simulate app goes to
408 // background and back to foreground.
409 public void testVideoSourceRestart() throws InterruptedException {
410 Log.d(TAG, "testVideoSourceRestart");
411 loopback = true;
412
413 MockRenderer localRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, LOCAL_R ENDERER_NAME);
414 MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE _RENDERER_NAME);
415
416 pcClient = createPeerConnectionClient(
417 localRenderer, remoteRenderer, true, VIDEO_CODEC_VP8);
418
419 // Wait for local SDP, rename it to answer and set as remote SDP.
420 assertTrue("Local SDP was not set.", waitForLocalSDP(WAIT_TIMEOUT));
421 SessionDescription remoteSdp = new SessionDescription(
422 SessionDescription.Type.fromCanonicalForm("answer"),
423 localSdp.description);
424 pcClient.setRemoteDescription(remoteSdp);
425
426 // Wait for ICE connection.
427 assertTrue("ICE connection failure.", waitForIceConnected(ICE_CONNECTION_WAI T_TIMEOUT));
428
429 // Check that local and remote video frames were rendered.
430 assertTrue("Local video frames were not rendered before video restart.",
431 localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
432 assertTrue("Remote video frames were not rendered before video restart.",
433 remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
434
435 // Stop and then start video source a few times.
436 for (int i = 0; i < VIDEO_RESTART_ATTEMPTS; i++) {
437 pcClient.stopVideoSource();
438 Thread.sleep(VIDEO_RESTART_TIMEOUT);
439 pcClient.startVideoSource();
440
441 // Reset video renders and check that local and remote video frames
442 // were rendered after video restart.
443 localRenderer.reset(EXPECTED_VIDEO_FRAMES);
444 remoteRenderer.reset(EXPECTED_VIDEO_FRAMES);
445 assertTrue("Local video frames were not rendered after video restart.",
446 localRenderer.waitForFramesRendered(WAIT_TIMEOUT));
447 assertTrue("Remote video frames were not rendered after video restart.",
448 remoteRenderer.waitForFramesRendered(WAIT_TIMEOUT));
449 }
450 pcClient.close();
451 assertTrue(waitForPeerConnectionClosed(WAIT_TIMEOUT));
452 Log.d(TAG, "testVideoSourceRestart done.");
453 }
454
455 }
OLDNEW
« no previous file with comments | « talk/examples/androidtests/src/org/appspot/apprtc/test/LooperExecutorTest.java ('k') | talk/examples/objc/.clang-format » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698