| Index: talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java
|
| diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java
|
| index 8e195ac937c9db19f5a9ce658c8bc483bdb1e460..40e2fdb6008e650e792dc493ec52e3c50b5e83f6 100644
|
| --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java
|
| +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java
|
| @@ -29,6 +29,7 @@ package org.webrtc;
|
| import android.hardware.Camera;
|
| import android.test.ActivityTestCase;
|
| import android.test.suitebuilder.annotation.SmallTest;
|
| +import android.test.suitebuilder.annotation.MediumTest;
|
| import android.util.Size;
|
|
|
| import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
|
| @@ -38,6 +39,7 @@ import java.util.ArrayList;
|
| import java.util.HashSet;
|
| import java.util.List;
|
| import java.util.Set;
|
| +import java.util.concurrent.CountDownLatch;
|
|
|
| @SuppressWarnings("deprecation")
|
| public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| @@ -62,7 +64,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| }
|
| }
|
|
|
| - static class AsyncRenderer implements VideoRenderer.Callbacks {
|
| + static class FakeAsyncRenderer implements VideoRenderer.Callbacks {
|
| private final List<I420Frame> pendingFrames = new ArrayList<I420Frame>();
|
|
|
| @Override
|
| @@ -74,18 +76,12 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| }
|
|
|
| // Wait until at least one frame have been received, before returning them.
|
| - public List<I420Frame> WaitForFrames() {
|
| + public List<I420Frame> waitForPendingFrames() throws InterruptedException {
|
| synchronized (pendingFrames) {
|
| while (pendingFrames.isEmpty()) {
|
| - try {
|
| - pendingFrames.wait();
|
| - } catch (InterruptedException e) {
|
| - // Ignore.
|
| - }
|
| + pendingFrames.wait();
|
| }
|
| - final List<I420Frame> frames = new ArrayList<I420Frame>(pendingFrames);
|
| - pendingFrames.clear();
|
| - return frames;
|
| + return new ArrayList<I420Frame>(pendingFrames);
|
| }
|
| }
|
| }
|
| @@ -169,6 +165,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| track.dispose();
|
| source.dispose();
|
| factory.dispose();
|
| + assertTrue(capturer.isReleased());
|
| }
|
|
|
| @Override
|
| @@ -213,6 +210,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null);
|
| assertNotNull(capturer);
|
| capturer.dispose();
|
| + assertTrue(capturer.isReleased());
|
| }
|
|
|
| @SmallTest
|
| @@ -250,7 +248,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| }
|
|
|
| @SmallTest
|
| - // This test that the default camera can be started and but the camera can
|
| + // This test that the default camera can be started and that the camera can
|
| // later be switched to another camera.
|
| // It tests both the Java and the C++ layer.
|
| public void testSwitchVideoCapturer() throws Exception {
|
| @@ -260,14 +258,30 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| factory.createVideoSource(capturer, new MediaConstraints());
|
| VideoTrack track = factory.createVideoTrack("dummy", source);
|
|
|
| - if (HaveTwoCameras())
|
| - assertTrue(capturer.switchCamera(null));
|
| - else
|
| - assertFalse(capturer.switchCamera(null));
|
| -
|
| - // Wait until the camera have been switched.
|
| - capturer.runCameraThreadUntilIdle();
|
| -
|
| + // Array with one element to avoid final problem in nested classes.
|
| + final boolean[] cameraSwitchSuccessful = new boolean[1];
|
| + final CountDownLatch barrier = new CountDownLatch(1);
|
| + capturer.switchCamera(new VideoCapturerAndroid.CameraSwitchHandler() {
|
| + @Override
|
| + public void onCameraSwitchDone(boolean isFrontCamera) {
|
| + cameraSwitchSuccessful[0] = true;
|
| + barrier.countDown();
|
| + }
|
| + @Override
|
| + public void onCameraSwitchError(String errorDescription) {
|
| + cameraSwitchSuccessful[0] = false;
|
| + barrier.countDown();
|
| + }
|
| + });
|
| + // Wait until the camera has been switched.
|
| + barrier.await();
|
| +
|
| + // Check result.
|
| + if (HaveTwoCameras()) {
|
| + assertTrue(cameraSwitchSuccessful[0]);
|
| + } else {
|
| + assertFalse(cameraSwitchSuccessful[0]);
|
| + }
|
| // Ensure that frames are received.
|
| RendererCallbacks callbacks = new RendererCallbacks();
|
| track.addRenderer(new VideoRenderer(callbacks));
|
| @@ -275,6 +289,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| track.dispose();
|
| source.dispose();
|
| factory.dispose();
|
| + assertTrue(capturer.isReleased());
|
| }
|
|
|
| @SmallTest
|
| @@ -300,6 +315,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| track.dispose();
|
| source.dispose();
|
| factory.dispose();
|
| + assertTrue(capturer.isReleased());
|
| }
|
|
|
| @SmallTest
|
| @@ -322,8 +338,12 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| // Check the frame size.
|
| assertEquals(format.frameSize(), observer.frameSize());
|
| capturer.stopCapture();
|
| + for (long timestamp : observer.getCopyAndResetListOftimeStamps()) {
|
| + capturer.returnBuffer(timestamp);
|
| + }
|
| }
|
| capturer.dispose();
|
| + assertTrue(capturer.isReleased());
|
| }
|
|
|
| @SmallTest
|
| @@ -365,55 +385,48 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
| for (Long timeStamp : listOftimestamps) {
|
| capturer.returnBuffer(timeStamp);
|
| }
|
| + capturer.dispose();
|
| + assertTrue(capturer.isReleased());
|
| }
|
|
|
| - @SmallTest
|
| - // This test that we can capture frames, stop capturing, keep the frames for rendering, and then
|
| - // return the frames. It tests both the Java and the C++ layer.
|
| - public void testCaptureAndAsyncRender() {
|
| + @MediumTest
|
| + // This test that we can capture frames, keep the frames in a local renderer, stop capturing,
|
| + // and then return the frames. The difference between the test testReturnBufferLate() is that we
|
| + // also test the JNI and C++ AndroidVideoCapturer parts.
|
| + public void testReturnBufferLateEndToEnd() throws InterruptedException {
|
| final VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null);
|
| - // Helper class that sets everything up, captures at least one frame, and then shuts
|
| - // everything down.
|
| - class CaptureFramesRunnable implements Runnable {
|
| - public List<I420Frame> frames;
|
| + final PeerConnectionFactory factory = new PeerConnectionFactory();
|
| + final VideoSource source = factory.createVideoSource(capturer, new MediaConstraints());
|
| + final VideoTrack track = factory.createVideoTrack("dummy", source);
|
| + final FakeAsyncRenderer renderer = new FakeAsyncRenderer();
|
| + track.addRenderer(new VideoRenderer(renderer));
|
| + // Wait for at least one frame that has not been returned.
|
| + assertFalse(renderer.waitForPendingFrames().isEmpty());
|
| +
|
| + capturer.stopCapture();
|
| +
|
| + // Dispose source and |capturer|.
|
| + track.dispose();
|
| + source.dispose();
|
| + // The pending frames should keep the JNI parts and |capturer| alive.
|
| + assertFalse(capturer.isReleased());
|
|
|
| + // Return the frame(s), on a different thread out of spite.
|
| + final List<I420Frame> pendingFrames = renderer.waitForPendingFrames();
|
| + final Thread returnThread = new Thread(new Runnable() {
|
| @Override
|
| public void run() {
|
| - PeerConnectionFactory factory = new PeerConnectionFactory();
|
| - VideoSource source = factory.createVideoSource(capturer, new MediaConstraints());
|
| - VideoTrack track = factory.createVideoTrack("dummy", source);
|
| - AsyncRenderer renderer = new AsyncRenderer();
|
| - track.addRenderer(new VideoRenderer(renderer));
|
| -
|
| - // Wait until we get at least one frame.
|
| - frames = renderer.WaitForFrames();
|
| -
|
| - // Stop everything.
|
| - track.dispose();
|
| - source.dispose();
|
| - factory.dispose();
|
| + for (I420Frame frame : pendingFrames) {
|
| + VideoRenderer.renderFrameDone(frame);
|
| + }
|
| }
|
| - }
|
| + });
|
| + returnThread.start();
|
| + returnThread.join();
|
|
|
| - // Capture frames on a separate thread.
|
| - CaptureFramesRunnable captureFramesRunnable = new CaptureFramesRunnable();
|
| - Thread captureThread = new Thread(captureFramesRunnable);
|
| - captureThread.start();
|
| + // Check that frames have successfully returned. This will cause |capturer| to be released.
|
| + assertTrue(capturer.isReleased());
|
|
|
| - // Wait until frames are captured, and then kill the thread.
|
| - try {
|
| - captureThread.join();
|
| - } catch (InterruptedException e) {
|
| - fail("Capture thread was interrupted");
|
| - }
|
| - captureThread = null;
|
| -
|
| - // Assert that we have frames that have not been returned.
|
| - assertTrue(!captureFramesRunnable.frames.isEmpty());
|
| - // Return the frame(s).
|
| - for (I420Frame frame : captureFramesRunnable.frames) {
|
| - VideoRenderer.renderFrameDone(frame);
|
| - }
|
| - assertEquals(capturer.pendingFramesTimeStamps(), "[]");
|
| + factory.dispose();
|
| }
|
| }
|
|
|