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

Side by Side Diff: talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java

Issue 1350863002: VideoCapturerAndroid: Fix threading issues (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 3 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
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2015 Google Inc. 3 * Copyright 2015 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 20 matching lines...) Expand all
31 import android.test.suitebuilder.annotation.SmallTest; 31 import android.test.suitebuilder.annotation.SmallTest;
32 import android.util.Size; 32 import android.util.Size;
33 33
34 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; 34 import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
35 import org.webrtc.VideoRenderer.I420Frame; 35 import org.webrtc.VideoRenderer.I420Frame;
36 36
37 import java.util.ArrayList; 37 import java.util.ArrayList;
38 import java.util.HashSet; 38 import java.util.HashSet;
39 import java.util.List; 39 import java.util.List;
40 import java.util.Set; 40 import java.util.Set;
41 import java.util.concurrent.CountDownLatch;
41 42
42 @SuppressWarnings("deprecation") 43 @SuppressWarnings("deprecation")
43 public class VideoCapturerAndroidTest extends ActivityTestCase { 44 public class VideoCapturerAndroidTest extends ActivityTestCase {
44 static class RendererCallbacks implements VideoRenderer.Callbacks { 45 static class RendererCallbacks implements VideoRenderer.Callbacks {
45 private int framesRendered = 0; 46 private int framesRendered = 0;
46 private Object frameLock = 0; 47 private Object frameLock = 0;
47 48
48 @Override 49 @Override
49 public void renderFrame(I420Frame frame) { 50 public void renderFrame(I420Frame frame) {
50 synchronized (frameLock) { 51 synchronized (frameLock) {
51 ++framesRendered; 52 ++framesRendered;
52 frameLock.notify(); 53 frameLock.notify();
53 } 54 }
54 VideoRenderer.renderFrameDone(frame); 55 VideoRenderer.renderFrameDone(frame);
55 } 56 }
56 57
57 public int WaitForNextFrameToRender() throws InterruptedException { 58 public int WaitForNextFrameToRender() throws InterruptedException {
58 synchronized (frameLock) { 59 synchronized (frameLock) {
59 frameLock.wait(); 60 frameLock.wait();
60 return framesRendered; 61 return framesRendered;
61 } 62 }
62 } 63 }
63 } 64 }
64 65
65 static class AsyncRenderer implements VideoRenderer.Callbacks {
66 private final List<I420Frame> pendingFrames = new ArrayList<I420Frame>();
67
68 @Override
69 public void renderFrame(I420Frame frame) {
70 synchronized (pendingFrames) {
71 pendingFrames.add(frame);
72 pendingFrames.notifyAll();
73 }
74 }
75
76 // Wait until at least one frame have been received, before returning them.
77 public List<I420Frame> WaitForFrames() {
78 synchronized (pendingFrames) {
79 while (pendingFrames.isEmpty()) {
80 try {
81 pendingFrames.wait();
82 } catch (InterruptedException e) {
83 // Ignore.
84 }
85 }
86 final List<I420Frame> frames = new ArrayList<I420Frame>(pendingFrames);
87 pendingFrames.clear();
88 return frames;
89 }
90 }
91 }
92
93 static class FakeCapturerObserver implements 66 static class FakeCapturerObserver implements
94 VideoCapturerAndroid.CapturerObserver { 67 VideoCapturerAndroid.CapturerObserver {
95 private int framesCaptured = 0; 68 private int framesCaptured = 0;
96 private int frameSize = 0; 69 private int frameSize = 0;
97 private Object frameLock = 0; 70 private Object frameLock = 0;
98 private Object capturerStartLock = 0; 71 private Object capturerStartLock = 0;
99 private boolean captureStartResult = false; 72 private boolean captureStartResult = false;
100 private List<Long> timestamps = new ArrayList<Long>(); 73 private List<Long> timestamps = new ArrayList<Long>();
101 74
102 @Override 75 @Override
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 // to a Java video renderer using the back facing video capturer. 216 // to a Java video renderer using the back facing video capturer.
244 // It tests both the Java and the C++ layer. 217 // It tests both the Java and the C++ layer.
245 public void testStartBackFacingVideoCapturer() throws Exception { 218 public void testStartBackFacingVideoCapturer() throws Exception {
246 if (!HaveTwoCameras()) { 219 if (!HaveTwoCameras()) {
247 return; 220 return;
248 } 221 }
249 startCapturerAndRender(CameraEnumerationAndroid.getNameOfBackFacingDevice()) ; 222 startCapturerAndRender(CameraEnumerationAndroid.getNameOfBackFacingDevice()) ;
250 } 223 }
251 224
252 @SmallTest 225 @SmallTest
253 // This test that the default camera can be started and but the camera can 226 // This test that the default camera can be started and that the camera can
254 // later be switched to another camera. 227 // later be switched to another camera.
255 // It tests both the Java and the C++ layer. 228 // It tests both the Java and the C++ layer.
256 public void testSwitchVideoCapturer() throws Exception { 229 public void testSwitchVideoCapturer() throws Exception {
257 PeerConnectionFactory factory = new PeerConnectionFactory(); 230 PeerConnectionFactory factory = new PeerConnectionFactory();
258 VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null); 231 VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null);
259 VideoSource source = 232 VideoSource source =
260 factory.createVideoSource(capturer, new MediaConstraints()); 233 factory.createVideoSource(capturer, new MediaConstraints());
261 VideoTrack track = factory.createVideoTrack("dummy", source); 234 VideoTrack track = factory.createVideoTrack("dummy", source);
262 235
263 if (HaveTwoCameras()) 236 // Array with one element to avoid final problem in nested classes.
264 assertTrue(capturer.switchCamera(null)); 237 final boolean[] cameraSwitchSuccessful = new boolean[1];
265 else 238 final CountDownLatch barrier = new CountDownLatch(1);
266 assertFalse(capturer.switchCamera(null)); 239 capturer.switchCamera(new VideoCapturerAndroid.CameraSwitchHandler() {
240 @Override
241 public void onCameraSwitchDone(boolean isFrontCamera) {
242 cameraSwitchSuccessful[0] = true;
243 barrier.countDown();
244 }
245 @Override
246 public void onCameraSwitchError(String errorDescription) {
247 cameraSwitchSuccessful[0] = false;
248 barrier.countDown();
249 }
250 });
251 // Wait until the camera has been switched.
252 barrier.await();
267 253
268 // Wait until the camera have been switched. 254 // Check result.
269 capturer.runCameraThreadUntilIdle(); 255 if (HaveTwoCameras()) {
270 256 assertTrue(cameraSwitchSuccessful[0]);
257 } else {
258 assertFalse(cameraSwitchSuccessful[0]);
259 }
271 // Ensure that frames are received. 260 // Ensure that frames are received.
272 RendererCallbacks callbacks = new RendererCallbacks(); 261 RendererCallbacks callbacks = new RendererCallbacks();
273 track.addRenderer(new VideoRenderer(callbacks)); 262 track.addRenderer(new VideoRenderer(callbacks));
274 assertTrue(callbacks.WaitForNextFrameToRender() > 0); 263 assertTrue(callbacks.WaitForNextFrameToRender() > 0);
275 track.dispose(); 264 track.dispose();
276 source.dispose(); 265 source.dispose();
277 factory.dispose(); 266 factory.dispose();
278 } 267 }
279 268
280 @SmallTest 269 @SmallTest
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 348
360 observer.WaitForNextCapturedFrame(); 349 observer.WaitForNextCapturedFrame();
361 capturer.stopCapture(); 350 capturer.stopCapture();
362 351
363 listOftimestamps = observer.getCopyAndResetListOftimeStamps(); 352 listOftimestamps = observer.getCopyAndResetListOftimeStamps();
364 assertTrue(listOftimestamps.size() >= 2); 353 assertTrue(listOftimestamps.size() >= 2);
365 for (Long timeStamp : listOftimestamps) { 354 for (Long timeStamp : listOftimestamps) {
366 capturer.returnBuffer(timeStamp); 355 capturer.returnBuffer(timeStamp);
367 } 356 }
368 } 357 }
369
370 @SmallTest
371 // This test that we can capture frames, stop capturing, keep the frames for r endering, and then
372 // return the frames. It tests both the Java and the C++ layer.
373 public void testCaptureAndAsyncRender() {
374 final VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null);
375 // Helper class that sets everything up, captures at least one frame, and th en shuts
376 // everything down.
377 class CaptureFramesRunnable implements Runnable {
378 public List<I420Frame> frames;
379
380 @Override
381 public void run() {
382 PeerConnectionFactory factory = new PeerConnectionFactory();
383 VideoSource source = factory.createVideoSource(capturer, new MediaConstr aints());
384 VideoTrack track = factory.createVideoTrack("dummy", source);
385 AsyncRenderer renderer = new AsyncRenderer();
386 track.addRenderer(new VideoRenderer(renderer));
387
388 // Wait until we get at least one frame.
389 frames = renderer.WaitForFrames();
390
391 // Stop everything.
392 track.dispose();
393 source.dispose();
394 factory.dispose();
395 }
396 }
397
398 // Capture frames on a separate thread.
399 CaptureFramesRunnable captureFramesRunnable = new CaptureFramesRunnable();
400 Thread captureThread = new Thread(captureFramesRunnable);
401 captureThread.start();
402
403 // Wait until frames are captured, and then kill the thread.
404 try {
405 captureThread.join();
406 } catch (InterruptedException e) {
407 fail("Capture thread was interrupted");
408 }
409 captureThread = null;
410
411 // Assert that we have frames that have not been returned.
412 assertTrue(!captureFramesRunnable.frames.isEmpty());
413 // Return the frame(s).
414 for (I420Frame frame : captureFramesRunnable.frames) {
415 VideoRenderer.renderFrameDone(frame);
416 }
417 assertEquals(capturer.pendingFramesTimeStamps(), "[]");
418 }
hbos 2015/09/18 11:10:52 I'm thinking it might be worth to tweak this test
magjed_webrtc 2015/09/21 08:19:57 Probably true. We have a similar test in testRetur
419 } 358 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698