| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 package org.webrtc; | 10 package org.webrtc; |
| 11 | 11 |
| 12 import android.content.Context; | 12 import static junit.framework.Assert.*; |
| 13 | 13 |
| 14 import org.webrtc.VideoCapturerAndroidTestFixtures; | |
| 15 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; | 14 import org.webrtc.CameraEnumerationAndroid.CaptureFormat; |
| 16 import org.webrtc.VideoRenderer.I420Frame; | 15 import org.webrtc.VideoRenderer.I420Frame; |
| 17 | 16 |
| 17 import android.content.Context; |
| 18 |
| 18 import java.util.ArrayList; | 19 import java.util.ArrayList; |
| 19 import java.util.List; | 20 import java.util.List; |
| 20 import java.util.concurrent.CountDownLatch; | 21 import java.util.concurrent.CountDownLatch; |
| 21 | 22 |
| 22 import static junit.framework.Assert.*; | 23 class CameraVideoCapturerTestFixtures { |
| 24 static final String TAG = "CameraVideoCapturerTestFixtures"; |
| 23 | 25 |
| 24 @SuppressWarnings("deprecation") | 26 static private class RendererCallbacks implements VideoRenderer.Callbacks { |
| 25 public class VideoCapturerAndroidTestFixtures { | |
| 26 static class RendererCallbacks implements VideoRenderer.Callbacks { | |
| 27 private int framesRendered = 0; | 27 private int framesRendered = 0; |
| 28 private Object frameLock = 0; | 28 private Object frameLock = 0; |
| 29 private int width = 0; | 29 private int width = 0; |
| 30 private int height = 0; | 30 private int height = 0; |
| 31 | 31 |
| 32 @Override | 32 @Override |
| 33 public void renderFrame(I420Frame frame) { | 33 public void renderFrame(I420Frame frame) { |
| 34 synchronized (frameLock) { | 34 synchronized (frameLock) { |
| 35 ++framesRendered; | 35 ++framesRendered; |
| 36 width = frame.rotatedWidth(); | 36 width = frame.rotatedWidth(); |
| 37 height = frame.rotatedHeight(); | 37 height = frame.rotatedHeight(); |
| 38 frameLock.notify(); | 38 frameLock.notify(); |
| 39 } | 39 } |
| 40 VideoRenderer.renderFrameDone(frame); | 40 VideoRenderer.renderFrameDone(frame); |
| 41 } | 41 } |
| 42 | 42 |
| 43 public int frameWidth() { | 43 public int frameWidth() { |
| 44 synchronized (frameLock) { | 44 synchronized (frameLock) { |
| 45 return width; | 45 return width; |
| 46 } | 46 } |
| 47 } | 47 } |
| 48 | 48 |
| 49 public int frameHeight() { | 49 public int frameHeight() { |
| 50 synchronized (frameLock) { | 50 synchronized (frameLock) { |
| 51 return height; | 51 return height; |
| 52 } | 52 } |
| 53 } | 53 } |
| 54 | 54 |
| 55 public int WaitForNextFrameToRender() throws InterruptedException { | 55 public int waitForNextFrameToRender() throws InterruptedException { |
| 56 Logging.d(TAG, "Waiting for the next frame to render"); |
| 56 synchronized (frameLock) { | 57 synchronized (frameLock) { |
| 57 frameLock.wait(); | 58 frameLock.wait(); |
| 58 return framesRendered; | 59 return framesRendered; |
| 59 } | 60 } |
| 60 } | 61 } |
| 61 } | 62 } |
| 62 | 63 |
| 63 static class FakeAsyncRenderer implements VideoRenderer.Callbacks { | 64 static private class FakeAsyncRenderer implements VideoRenderer.Callbacks { |
| 64 private final List<I420Frame> pendingFrames = new ArrayList<I420Frame>(); | 65 private final List<I420Frame> pendingFrames = new ArrayList<I420Frame>(); |
| 65 | 66 |
| 66 @Override | 67 @Override |
| 67 public void renderFrame(I420Frame frame) { | 68 public void renderFrame(I420Frame frame) { |
| 68 synchronized (pendingFrames) { | 69 synchronized (pendingFrames) { |
| 69 pendingFrames.add(frame); | 70 pendingFrames.add(frame); |
| 70 pendingFrames.notifyAll(); | 71 pendingFrames.notifyAll(); |
| 71 } | 72 } |
| 72 } | 73 } |
| 73 | 74 |
| 74 // Wait until at least one frame have been received, before returning them. | 75 // Wait until at least one frame have been received, before returning them. |
| 75 public List<I420Frame> waitForPendingFrames() throws InterruptedException { | 76 public List<I420Frame> waitForPendingFrames() throws InterruptedException { |
| 77 Logging.d(TAG, "Waiting for pending frames"); |
| 76 synchronized (pendingFrames) { | 78 synchronized (pendingFrames) { |
| 77 while (pendingFrames.isEmpty()) { | 79 while (pendingFrames.isEmpty()) { |
| 78 pendingFrames.wait(); | 80 pendingFrames.wait(); |
| 79 } | 81 } |
| 80 return new ArrayList<I420Frame>(pendingFrames); | 82 return new ArrayList<I420Frame>(pendingFrames); |
| 81 } | 83 } |
| 82 } | 84 } |
| 83 } | 85 } |
| 84 | 86 |
| 85 static class FakeCapturerObserver implements VideoCapturer.CapturerObserver { | 87 static private class FakeCapturerObserver implements CameraVideoCapturer.Captu
rerObserver { |
| 86 private int framesCaptured = 0; | 88 private int framesCaptured = 0; |
| 87 private int frameSize = 0; | 89 private int frameSize = 0; |
| 88 private int frameWidth = 0; | 90 private int frameWidth = 0; |
| 89 private int frameHeight = 0; | 91 private int frameHeight = 0; |
| 90 private Object frameLock = 0; | 92 final private Object frameLock = new Object(); |
| 91 private Object capturerStartLock = 0; | 93 final private Object capturerStartLock = new Object(); |
| 92 private boolean captureStartResult = false; | 94 private boolean capturerStartResult = false; |
| 93 private List<Long> timestamps = new ArrayList<Long>(); | 95 final private List<Long> timestamps = new ArrayList<Long>(); |
| 94 | 96 |
| 95 @Override | 97 @Override |
| 96 public void onCapturerStarted(boolean success) { | 98 public void onCapturerStarted(boolean success) { |
| 99 Logging.d(TAG, "onCapturerStarted: " + success); |
| 100 |
| 97 synchronized (capturerStartLock) { | 101 synchronized (capturerStartLock) { |
| 98 captureStartResult = success; | 102 capturerStartResult = success; |
| 99 capturerStartLock.notify(); | 103 capturerStartLock.notifyAll(); |
| 100 } | 104 } |
| 101 } | 105 } |
| 102 | 106 |
| 103 @Override | 107 @Override |
| 104 public void onByteBufferFrameCaptured(byte[] frame, int width, int height, i
nt rotation, | 108 public void onByteBufferFrameCaptured(byte[] frame, int width, int height, i
nt rotation, |
| 105 long timeStamp) { | 109 long timeStamp) { |
| 106 synchronized (frameLock) { | 110 synchronized (frameLock) { |
| 107 ++framesCaptured; | 111 ++framesCaptured; |
| 108 frameSize = frame.length; | 112 frameSize = frame.length; |
| 109 frameWidth = width; | 113 frameWidth = width; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 122 frameHeight = height; | 126 frameHeight = height; |
| 123 frameSize = 0; | 127 frameSize = 0; |
| 124 timestamps.add(timeStamp); | 128 timestamps.add(timeStamp); |
| 125 frameLock.notify(); | 129 frameLock.notify(); |
| 126 } | 130 } |
| 127 } | 131 } |
| 128 | 132 |
| 129 @Override | 133 @Override |
| 130 public void onOutputFormatRequest(int width, int height, int fps) {} | 134 public void onOutputFormatRequest(int width, int height, int fps) {} |
| 131 | 135 |
| 132 public boolean WaitForCapturerToStart() throws InterruptedException { | 136 public boolean waitForCapturerToStart() throws InterruptedException { |
| 137 Logging.d(TAG, "Waiting for the capturer to start"); |
| 133 synchronized (capturerStartLock) { | 138 synchronized (capturerStartLock) { |
| 134 capturerStartLock.wait(); | 139 capturerStartLock.wait(); |
| 135 return captureStartResult; | 140 return capturerStartResult; |
| 136 } | 141 } |
| 137 } | 142 } |
| 138 | 143 |
| 139 public int WaitForNextCapturedFrame() throws InterruptedException { | 144 public int waitForNextCapturedFrame() throws InterruptedException { |
| 145 Logging.d(TAG, "Waiting for the next captured frame"); |
| 140 synchronized (frameLock) { | 146 synchronized (frameLock) { |
| 141 frameLock.wait(); | 147 frameLock.wait(); |
| 142 return framesCaptured; | 148 return framesCaptured; |
| 143 } | 149 } |
| 144 } | 150 } |
| 145 | 151 |
| 146 int frameSize() { | 152 int frameSize() { |
| 147 synchronized (frameLock) { | 153 synchronized (frameLock) { |
| 148 return frameSize; | 154 return frameSize; |
| 149 } | 155 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 164 List<Long> getCopyAndResetListOftimeStamps() { | 170 List<Long> getCopyAndResetListOftimeStamps() { |
| 165 synchronized (frameLock) { | 171 synchronized (frameLock) { |
| 166 ArrayList<Long> list = new ArrayList<Long>(timestamps); | 172 ArrayList<Long> list = new ArrayList<Long>(timestamps); |
| 167 timestamps.clear(); | 173 timestamps.clear(); |
| 168 return list; | 174 return list; |
| 169 } | 175 } |
| 170 } | 176 } |
| 171 } | 177 } |
| 172 | 178 |
| 173 static class CameraEvents implements | 179 static class CameraEvents implements |
| 174 VideoCapturerAndroid.CameraEventsHandler { | 180 CameraVideoCapturer.CameraEventsHandler { |
| 175 public boolean onCameraOpeningCalled; | 181 public boolean onCameraOpeningCalled; |
| 176 public boolean onFirstFrameAvailableCalled; | 182 public boolean onFirstFrameAvailableCalled; |
| 177 public final Object onCameraFreezedLock = new Object(); | 183 public final Object onCameraFreezedLock = new Object(); |
| 178 private String onCameraFreezedDescription; | 184 private String onCameraFreezedDescription; |
| 179 | 185 |
| 180 @Override | 186 @Override |
| 181 public void onCameraError(String errorDescription) { | 187 public void onCameraError(String errorDescription) { |
| 182 } | 188 } |
| 183 | 189 |
| 184 @Override | 190 @Override |
| (...skipping 10 matching lines...) Expand all Loading... |
| 195 } | 201 } |
| 196 | 202 |
| 197 @Override | 203 @Override |
| 198 public void onFirstFrameAvailable() { | 204 public void onFirstFrameAvailable() { |
| 199 onFirstFrameAvailableCalled = true; | 205 onFirstFrameAvailableCalled = true; |
| 200 } | 206 } |
| 201 | 207 |
| 202 @Override | 208 @Override |
| 203 public void onCameraClosed() { } | 209 public void onCameraClosed() { } |
| 204 | 210 |
| 205 public String WaitForCameraFreezed() throws InterruptedException { | 211 public String waitForCameraFreezed() throws InterruptedException { |
| 212 Logging.d(TAG, "Waiting for the camera to freeze"); |
| 206 synchronized (onCameraFreezedLock) { | 213 synchronized (onCameraFreezedLock) { |
| 207 onCameraFreezedLock.wait(); | 214 onCameraFreezedLock.wait(); |
| 208 return onCameraFreezedDescription; | 215 return onCameraFreezedDescription; |
| 209 } | 216 } |
| 210 } | 217 } |
| 211 } | 218 } |
| 212 | 219 |
| 213 static public CameraEvents createCameraEvents() { | 220 /** |
| 214 return new CameraEvents(); | 221 * Class to collect all classes related to single capturer instance. |
| 222 */ |
| 223 static private class CapturerInstance { |
| 224 public CameraVideoCapturer capturer; |
| 225 public CameraEvents cameraEvents; |
| 226 public SurfaceTextureHelper surfaceTextureHelper; |
| 227 public FakeCapturerObserver observer; |
| 228 public List<CaptureFormat> supportedFormats; |
| 229 public CaptureFormat format; |
| 215 } | 230 } |
| 216 | 231 |
| 217 // Return true if the device under test have at least two cameras. | 232 /** |
| 218 @SuppressWarnings("deprecation") | 233 * Class used for collecting a VideoSource, a VideoTrack and a renderer. The c
lass |
| 219 static public boolean HaveTwoCameras() { | 234 * is used for testing local rendering from a capturer. |
| 220 return (android.hardware.Camera.getNumberOfCameras() >= 2); | 235 */ |
| 236 static private class VideoTrackWithRenderer { |
| 237 public VideoSource source; |
| 238 public VideoTrack track; |
| 239 public RendererCallbacks rendererCallbacks; |
| 240 public FakeAsyncRenderer fakeAsyncRenderer; |
| 221 } | 241 } |
| 222 | 242 |
| 223 static public void release(VideoCapturerAndroid capturer) { | 243 public interface TestObjectFactory { |
| 224 assertNotNull(capturer); | 244 CameraVideoCapturer createCapturer( |
| 225 capturer.dispose(); | 245 String name, CameraVideoCapturer.CameraEventsHandler eventsHandler); |
| 246 String getNameOfFrontFacingDevice(); |
| 247 String getNameOfBackFacingDevice(); |
| 248 boolean haveTwoCameras(); |
| 249 boolean isCapturingToTexture(); |
| 250 Context getAppContext(); |
| 251 |
| 252 // CameraVideoCapturer API is too slow for some of our tests where we need t
o open a competing |
| 253 // camera. These methods are used instead. |
| 254 Object rawOpenCamera(String cameraName); |
| 255 void rawCloseCamera(Object camera); |
| 226 } | 256 } |
| 227 | 257 |
| 228 static public void startCapturerAndRender(VideoCapturerAndroid capturer) | 258 private PeerConnectionFactory peerConnectionFactory; |
| 229 throws InterruptedException { | 259 private TestObjectFactory testObjectFactory; |
| 230 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */
); | 260 |
| 231 VideoSource source = | 261 CameraVideoCapturerTestFixtures(TestObjectFactory testObjectFactory) { |
| 232 factory.createVideoSource(capturer, new MediaConstraints()); | 262 PeerConnectionFactory.initializeAndroidGlobals( |
| 233 VideoTrack track = factory.createVideoTrack("dummy", source); | 263 testObjectFactory.getAppContext(), true, true, true); |
| 234 RendererCallbacks callbacks = new RendererCallbacks(); | 264 |
| 235 track.addRenderer(new VideoRenderer(callbacks)); | 265 this.peerConnectionFactory = new PeerConnectionFactory(null /* options */); |
| 236 assertTrue(callbacks.WaitForNextFrameToRender() > 0); | 266 this.testObjectFactory = testObjectFactory; |
| 237 track.dispose(); | |
| 238 source.dispose(); | |
| 239 factory.dispose(); | |
| 240 } | 267 } |
| 241 | 268 |
| 242 static public void switchCamera(VideoCapturerAndroid capturer) throws Interrup
tedException { | 269 public void dispose() { |
| 243 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */
); | 270 this.peerConnectionFactory.dispose(); |
| 244 VideoSource source = | 271 } |
| 245 factory.createVideoSource(capturer, new MediaConstraints()); | 272 |
| 246 VideoTrack track = factory.createVideoTrack("dummy", source); | 273 // Internal helper methods |
| 274 private CapturerInstance createCapturer(String name) { |
| 275 CapturerInstance instance = new CapturerInstance(); |
| 276 instance.cameraEvents = new CameraEvents(); |
| 277 instance.capturer = testObjectFactory.createCapturer(name, instance.cameraEv
ents); |
| 278 instance.surfaceTextureHelper = SurfaceTextureHelper.create( |
| 279 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); |
| 280 instance.observer = new FakeCapturerObserver(); |
| 281 instance.supportedFormats = instance.capturer.getSupportedFormats(); |
| 282 return instance; |
| 283 } |
| 284 |
| 285 private CapturerInstance createCapturer() { |
| 286 return createCapturer(""); |
| 287 } |
| 288 |
| 289 private void startCapture(CapturerInstance instance) { |
| 290 startCapture(instance, 0); |
| 291 } |
| 292 |
| 293 private void startCapture(CapturerInstance instance, int formatIndex) { |
| 294 final CameraEnumerationAndroid.CaptureFormat format = |
| 295 instance.supportedFormats.get(formatIndex); |
| 296 |
| 297 instance.capturer.startCapture(format.width, format.height, format.framerate
.max, |
| 298 instance.surfaceTextureHelper, testObjectFactory.getAppContext(), instan
ce.observer); |
| 299 instance.format = format; |
| 300 } |
| 301 |
| 302 private void disposeCapturer(CapturerInstance instance) { |
| 303 instance.capturer.dispose(); |
| 304 instance.surfaceTextureHelper.returnTextureFrame(); |
| 305 instance.surfaceTextureHelper.dispose(); |
| 306 } |
| 307 |
| 308 private VideoTrackWithRenderer createVideoTrackWithRenderer(CameraVideoCapture
r capturer, |
| 309 VideoRenderer.Callbacks rendererCallbacks) { |
| 310 VideoTrackWithRenderer videoTrackWithRenderer = new VideoTrackWithRenderer()
; |
| 311 videoTrackWithRenderer.source = |
| 312 peerConnectionFactory.createVideoSource(capturer, new MediaConstraints()
); |
| 313 videoTrackWithRenderer.track = |
| 314 peerConnectionFactory.createVideoTrack("dummy", videoTrackWithRenderer.s
ource); |
| 315 videoTrackWithRenderer.track.addRenderer(new VideoRenderer(rendererCallbacks
)); |
| 316 return videoTrackWithRenderer; |
| 317 } |
| 318 |
| 319 private VideoTrackWithRenderer createVideoTrackWithRenderer(CameraVideoCapture
r capturer) { |
| 320 RendererCallbacks rendererCallbacks = new RendererCallbacks(); |
| 321 VideoTrackWithRenderer videoTrackWithRenderer = |
| 322 createVideoTrackWithRenderer(capturer, rendererCallbacks); |
| 323 videoTrackWithRenderer.rendererCallbacks = rendererCallbacks; |
| 324 return videoTrackWithRenderer; |
| 325 } |
| 326 |
| 327 private VideoTrackWithRenderer createVideoTrackWithFakeAsyncRenderer( |
| 328 CameraVideoCapturer capturer) { |
| 329 FakeAsyncRenderer fakeAsyncRenderer = new FakeAsyncRenderer(); |
| 330 VideoTrackWithRenderer videoTrackWithRenderer = |
| 331 createVideoTrackWithRenderer(capturer, fakeAsyncRenderer); |
| 332 videoTrackWithRenderer.fakeAsyncRenderer = fakeAsyncRenderer; |
| 333 return videoTrackWithRenderer; |
| 334 } |
| 335 |
| 336 private void disposeVideoTrackWithRenderer(VideoTrackWithRenderer videoTrackWi
thRenderer) { |
| 337 videoTrackWithRenderer.track.dispose(); |
| 338 videoTrackWithRenderer.source.dispose(); |
| 339 } |
| 340 |
| 341 private void waitUntilIdle(CapturerInstance capturerInstance) throws Interrupt
edException { |
| 342 final CountDownLatch barrier = new CountDownLatch(1); |
| 343 capturerInstance.surfaceTextureHelper.getHandler().post(new Runnable() { |
| 344 @Override public void run() { |
| 345 barrier.countDown(); |
| 346 } |
| 347 }); |
| 348 barrier.await(); |
| 349 } |
| 350 |
| 351 private void createCapturerAndRender(String name) throws InterruptedException
{ |
| 352 if (name == null) { |
| 353 Logging.w(TAG, "Skipping video capturer test because device name is null."
); |
| 354 return; |
| 355 } |
| 356 |
| 357 final CapturerInstance capturerInstance = createCapturer(name); |
| 358 final VideoTrackWithRenderer videoTrackWithRenderer = |
| 359 createVideoTrackWithRenderer(capturerInstance.capturer); |
| 360 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender
() > 0); |
| 361 disposeVideoTrackWithRenderer(videoTrackWithRenderer); |
| 362 disposeCapturer(capturerInstance); |
| 363 } |
| 364 |
| 365 // Test methods |
| 366 public void createCapturerAndDispose() { |
| 367 disposeCapturer(createCapturer()); |
| 368 } |
| 369 |
| 370 public void createNonExistingCamera() { |
| 371 try { |
| 372 disposeCapturer(createCapturer("non-existing camera")); |
| 373 } catch (IllegalArgumentException e) { |
| 374 return; |
| 375 } |
| 376 |
| 377 fail("Expected illegal argument exception when creating non-existing camera.
"); |
| 378 } |
| 379 |
| 380 public void createCapturerAndRender() throws InterruptedException { |
| 381 createCapturerAndRender(""); |
| 382 } |
| 383 |
| 384 public void createFrontFacingCapturerAndRender() throws InterruptedException { |
| 385 createCapturerAndRender(testObjectFactory.getNameOfFrontFacingDevice()); |
| 386 } |
| 387 |
| 388 public void createBackFacingCapturerAndRender() throws InterruptedException { |
| 389 createCapturerAndRender(testObjectFactory.getNameOfBackFacingDevice()); |
| 390 } |
| 391 |
| 392 public void switchCamera() throws InterruptedException { |
| 393 if (!testObjectFactory.haveTwoCameras()) { |
| 394 Logging.w(TAG, |
| 395 "Skipping test switch video capturer because the device doesn't have t
wo cameras."); |
| 396 return; |
| 397 } |
| 398 |
| 399 final CapturerInstance capturerInstance = createCapturer(); |
| 400 final VideoTrackWithRenderer videoTrackWithRenderer = |
| 401 createVideoTrackWithRenderer(capturerInstance.capturer); |
| 247 | 402 |
| 248 // Array with one element to avoid final problem in nested classes. | 403 // Array with one element to avoid final problem in nested classes. |
| 249 final boolean[] cameraSwitchSuccessful = new boolean[1]; | 404 final boolean[] cameraSwitchSuccessful = new boolean[1]; |
| 250 final CountDownLatch barrier = new CountDownLatch(1); | 405 final CountDownLatch barrier = new CountDownLatch(1); |
| 251 capturer.switchCamera(new VideoCapturerAndroid.CameraSwitchHandler() { | 406 capturerInstance.capturer.switchCamera(new CameraVideoCapturer.CameraSwitchH
andler() { |
| 252 @Override | 407 @Override |
| 253 public void onCameraSwitchDone(boolean isFrontCamera) { | 408 public void onCameraSwitchDone(boolean isFrontCamera) { |
| 254 cameraSwitchSuccessful[0] = true; | 409 cameraSwitchSuccessful[0] = true; |
| 255 barrier.countDown(); | 410 barrier.countDown(); |
| 256 } | 411 } |
| 257 @Override | 412 @Override |
| 258 public void onCameraSwitchError(String errorDescription) { | 413 public void onCameraSwitchError(String errorDescription) { |
| 259 cameraSwitchSuccessful[0] = false; | 414 cameraSwitchSuccessful[0] = false; |
| 260 barrier.countDown(); | 415 barrier.countDown(); |
| 261 } | 416 } |
| 262 }); | 417 }); |
| 263 // Wait until the camera has been switched. | 418 // Wait until the camera has been switched. |
| 264 barrier.await(); | 419 barrier.await(); |
| 265 | 420 |
| 266 // Check result. | 421 // Check result. |
| 267 if (HaveTwoCameras()) { | 422 assertTrue(cameraSwitchSuccessful[0]); |
| 268 assertTrue(cameraSwitchSuccessful[0]); | |
| 269 } else { | |
| 270 assertFalse(cameraSwitchSuccessful[0]); | |
| 271 } | |
| 272 // Ensure that frames are received. | 423 // Ensure that frames are received. |
| 273 RendererCallbacks callbacks = new RendererCallbacks(); | 424 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender
() > 0); |
| 274 track.addRenderer(new VideoRenderer(callbacks)); | 425 disposeVideoTrackWithRenderer(videoTrackWithRenderer); |
| 275 assertTrue(callbacks.WaitForNextFrameToRender() > 0); | 426 disposeCapturer(capturerInstance); |
| 276 track.dispose(); | |
| 277 source.dispose(); | |
| 278 factory.dispose(); | |
| 279 } | 427 } |
| 280 | 428 |
| 281 static public void cameraEventsInvoked(VideoCapturerAndroid capturer, CameraEv
ents events, | 429 public void cameraEventsInvoked() throws InterruptedException { |
| 282 Context appContext) throws InterruptedException { | 430 final CapturerInstance capturerInstance = createCapturer(); |
| 283 final List<CaptureFormat> formats = capturer.getSupportedFormats(); | 431 startCapture(capturerInstance); |
| 284 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | 432 // Make sure camera is started and first frame is received and then stop it. |
| 433 assertTrue(capturerInstance.observer.waitForCapturerToStart()); |
| 434 capturerInstance.observer.waitForNextCapturedFrame(); |
| 435 capturerInstance.capturer.stopCapture(); |
| 436 disposeCapturer(capturerInstance); |
| 285 | 437 |
| 286 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | 438 assertTrue(capturerInstance.cameraEvents.onCameraOpeningCalled); |
| 287 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | 439 assertTrue(capturerInstance.cameraEvents.onFirstFrameAvailableCalled); |
| 288 final FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 289 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 290 surfaceTextureHelper, appContext, observer); | |
| 291 // Make sure camera is started and first frame is received and then stop it. | |
| 292 assertTrue(observer.WaitForCapturerToStart()); | |
| 293 observer.WaitForNextCapturedFrame(); | |
| 294 capturer.stopCapture(); | |
| 295 if (capturer.isCapturingToTexture()) { | |
| 296 surfaceTextureHelper.returnTextureFrame(); | |
| 297 } | |
| 298 release(capturer); | |
| 299 surfaceTextureHelper.dispose(); | |
| 300 | |
| 301 assertTrue(events.onCameraOpeningCalled); | |
| 302 assertTrue(events.onFirstFrameAvailableCalled); | |
| 303 } | 440 } |
| 304 | 441 |
| 305 static public void cameraCallsAfterStop( | 442 public void cameraCallsAfterStop() throws InterruptedException { |
| 306 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep
tion { | 443 final CapturerInstance capturerInstance = createCapturer(); |
| 307 final List<CaptureFormat> formats = capturer.getSupportedFormats(); | 444 startCapture(capturerInstance); |
| 308 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | |
| 309 | |
| 310 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | |
| 311 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 312 final FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 313 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 314 surfaceTextureHelper, appContext, observer); | |
| 315 // Make sure camera is started and then stop it. | 445 // Make sure camera is started and then stop it. |
| 316 assertTrue(observer.WaitForCapturerToStart()); | 446 assertTrue(capturerInstance.observer.waitForCapturerToStart()); |
| 317 capturer.stopCapture(); | 447 capturerInstance.capturer.stopCapture(); |
| 318 if (capturer.isCapturingToTexture()) { | 448 capturerInstance.surfaceTextureHelper.returnTextureFrame(); |
| 319 surfaceTextureHelper.returnTextureFrame(); | |
| 320 } | |
| 321 | 449 |
| 322 // We can't change |capturer| at this point, but we should not crash. | 450 // We can't change |capturer| at this point, but we should not crash. |
| 323 capturer.switchCamera(null); | 451 capturerInstance.capturer.switchCamera(null /* switchEventsHandler */); |
| 324 capturer.onOutputFormatRequest(640, 480, 15); | 452 capturerInstance.capturer.onOutputFormatRequest(640, 480, 15); |
| 325 capturer.changeCaptureFormat(640, 480, 15); | 453 capturerInstance.capturer.changeCaptureFormat(640, 480, 15); |
| 326 | 454 |
| 327 release(capturer); | 455 disposeCapturer(capturerInstance); |
| 328 surfaceTextureHelper.dispose(); | |
| 329 } | 456 } |
| 330 | 457 |
| 331 static public void stopRestartVideoSource(VideoCapturerAndroid capturer) | 458 public void stopRestartVideoSource() throws InterruptedException { |
| 332 throws InterruptedException { | 459 final CapturerInstance capturerInstance = createCapturer(); |
| 333 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */
); | 460 final VideoTrackWithRenderer videoTrackWithRenderer = |
| 334 VideoSource source = | 461 createVideoTrackWithRenderer(capturerInstance.capturer); |
| 335 factory.createVideoSource(capturer, new MediaConstraints()); | |
| 336 VideoTrack track = factory.createVideoTrack("dummy", source); | |
| 337 RendererCallbacks callbacks = new RendererCallbacks(); | |
| 338 track.addRenderer(new VideoRenderer(callbacks)); | |
| 339 assertTrue(callbacks.WaitForNextFrameToRender() > 0); | |
| 340 assertEquals(MediaSource.State.LIVE, source.state()); | |
| 341 | 462 |
| 342 source.stop(); | 463 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender
() > 0); |
| 343 assertEquals(MediaSource.State.ENDED, source.state()); | 464 assertEquals(MediaSource.State.LIVE, videoTrackWithRenderer.source.state()); |
| 344 | 465 |
| 345 source.restart(); | 466 videoTrackWithRenderer.source.stop(); |
| 346 assertTrue(callbacks.WaitForNextFrameToRender() > 0); | 467 assertEquals(MediaSource.State.ENDED, videoTrackWithRenderer.source.state())
; |
| 347 assertEquals(MediaSource.State.LIVE, source.state()); | 468 |
| 348 track.dispose(); | 469 videoTrackWithRenderer.source.restart(); |
| 349 source.dispose(); | 470 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender
() > 0); |
| 350 factory.dispose(); | 471 assertEquals(MediaSource.State.LIVE, videoTrackWithRenderer.source.state()); |
| 472 |
| 473 disposeVideoTrackWithRenderer(videoTrackWithRenderer); |
| 474 disposeCapturer(capturerInstance); |
| 351 } | 475 } |
| 352 | 476 |
| 353 static public void startStopWithDifferentResolutions(VideoCapturerAndroid capt
urer, | 477 public void startStopWithDifferentResolutions() throws InterruptedException { |
| 354 Context appContext) throws InterruptedException { | 478 final CapturerInstance capturerInstance = createCapturer(); |
| 355 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | |
| 356 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 357 FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 358 List<CaptureFormat> formats = capturer.getSupportedFormats(); | |
| 359 | 479 |
| 360 for(int i = 0; i < 3 ; ++i) { | 480 for(int i = 0; i < 3 ; ++i) { |
| 361 CameraEnumerationAndroid.CaptureFormat format = formats.get(i); | 481 startCapture(capturerInstance, i); |
| 362 capturer.startCapture(format.width, format.height, format.framerate.max, | 482 assertTrue(capturerInstance.observer.waitForCapturerToStart()); |
| 363 surfaceTextureHelper, appContext, observer); | 483 capturerInstance.observer.waitForNextCapturedFrame(); |
| 364 assertTrue(observer.WaitForCapturerToStart()); | |
| 365 observer.WaitForNextCapturedFrame(); | |
| 366 | 484 |
| 367 // Check the frame size. The actual width and height depend on how the cap
turer is mounted. | 485 // Check the frame size. The actual width and height depend on how the cap
turer is mounted. |
| 368 final boolean identicalResolution = (observer.frameWidth() == format.width | 486 final boolean identicalResolution = ( |
| 369 && observer.frameHeight() == format.height); | 487 capturerInstance.observer.frameWidth() == capturerInstance.format.widt
h |
| 370 final boolean flippedResolution = (observer.frameWidth() == format.height | 488 && capturerInstance.observer.frameHeight() == capturerInstance.format
.height); |
| 371 && observer.frameHeight() == format.width); | 489 final boolean flippedResolution = ( |
| 490 capturerInstance.observer.frameWidth() == capturerInstance.format.heig
ht |
| 491 && capturerInstance.observer.frameHeight() == capturerInstance.format.
width); |
| 372 if (!identicalResolution && !flippedResolution) { | 492 if (!identicalResolution && !flippedResolution) { |
| 373 fail("Wrong resolution, got: " + observer.frameWidth() + "x" + observer.
frameHeight() | 493 fail("Wrong resolution, got: " |
| 374 + " expected: " + format.width + "x" + format.height + " or " + form
at.height + "x" | 494 + capturerInstance.observer.frameWidth() + "x" + capturerInstance.ob
server.frameHeight() |
| 375 + format.width); | 495 + " expected: "+ capturerInstance.format.width + "x" + capturerInsta
nce.format.height |
| 496 + " or " + capturerInstance.format.height + "x" + capturerInstance.f
ormat.width); |
| 376 } | 497 } |
| 377 | 498 |
| 378 if (capturer.isCapturingToTexture()) { | 499 if (testObjectFactory.isCapturingToTexture()) { |
| 379 assertEquals(0, observer.frameSize()); | 500 assertEquals(0, capturerInstance.observer.frameSize()); |
| 380 } else { | 501 } else { |
| 381 assertTrue(format.frameSize() <= observer.frameSize()); | 502 assertTrue(capturerInstance.format.frameSize() <= capturerInstance.obser
ver.frameSize()); |
| 382 } | 503 } |
| 383 capturer.stopCapture(); | 504 capturerInstance.capturer.stopCapture(); |
| 384 if (capturer.isCapturingToTexture()) { | 505 capturerInstance.surfaceTextureHelper.returnTextureFrame(); |
| 385 surfaceTextureHelper.returnTextureFrame(); | |
| 386 } | |
| 387 } | 506 } |
| 388 release(capturer); | 507 disposeCapturer(capturerInstance); |
| 389 surfaceTextureHelper.dispose(); | |
| 390 } | 508 } |
| 391 | 509 |
| 392 static void waitUntilIdle(VideoCapturerAndroid capturer) throws InterruptedExc
eption { | 510 public void returnBufferLate() throws InterruptedException { |
| 393 final CountDownLatch barrier = new CountDownLatch(1); | 511 final CapturerInstance capturerInstance = createCapturer(); |
| 394 capturer.getCameraThreadHandler().post(new Runnable() { | 512 startCapture(capturerInstance); |
| 395 @Override public void run() { | 513 assertTrue(capturerInstance.observer.waitForCapturerToStart()); |
| 396 barrier.countDown(); | 514 |
| 397 } | 515 capturerInstance.observer.waitForNextCapturedFrame(); |
| 398 }); | 516 capturerInstance.capturer.stopCapture(); |
| 399 barrier.await(); | 517 List<Long> listOftimestamps = capturerInstance.observer.getCopyAndResetListO
ftimeStamps(); |
| 518 assertTrue(listOftimestamps.size() >= 1); |
| 519 |
| 520 startCapture(capturerInstance, 1); |
| 521 capturerInstance.observer.waitForCapturerToStart(); |
| 522 capturerInstance.surfaceTextureHelper.returnTextureFrame(); |
| 523 |
| 524 capturerInstance.observer.waitForNextCapturedFrame(); |
| 525 capturerInstance.capturer.stopCapture(); |
| 526 |
| 527 listOftimestamps = capturerInstance.observer.getCopyAndResetListOftimeStamps
(); |
| 528 assertTrue(listOftimestamps.size() >= 1); |
| 529 |
| 530 disposeCapturer(capturerInstance); |
| 400 } | 531 } |
| 401 | 532 |
| 402 static public void startWhileCameraIsAlreadyOpen( | 533 public void returnBufferLateEndToEnd() |
| 403 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep
tion { | 534 throws InterruptedException { |
| 404 final List<CaptureFormat> formats = capturer.getSupportedFormats(); | 535 final CapturerInstance capturerInstance = createCapturer(); |
| 405 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | 536 final VideoTrackWithRenderer videoTrackWithRenderer = |
| 406 android.hardware.Camera camera = android.hardware.Camera.open(capturer.getCu
rrentCameraId()); | 537 createVideoTrackWithFakeAsyncRenderer(capturerInstance.capturer); |
| 538 // Wait for at least one frame that has not been returned. |
| 539 assertFalse(videoTrackWithRenderer.fakeAsyncRenderer.waitForPendingFrames().
isEmpty()); |
| 407 | 540 |
| 408 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | 541 capturerInstance.capturer.stopCapture(); |
| 409 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 410 final FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 411 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 412 surfaceTextureHelper, appContext, observer); | |
| 413 | |
| 414 if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIP
OP_MR1) { | |
| 415 // The first opened camera client will be evicted. | |
| 416 assertTrue(observer.WaitForCapturerToStart()); | |
| 417 capturer.stopCapture(); | |
| 418 } else { | |
| 419 assertFalse(observer.WaitForCapturerToStart()); | |
| 420 } | |
| 421 | |
| 422 release(capturer); | |
| 423 camera.release(); | |
| 424 surfaceTextureHelper.dispose(); | |
| 425 } | |
| 426 | |
| 427 static public void startWhileCameraIsAlreadyOpenAndCloseCamera( | |
| 428 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep
tion { | |
| 429 final PeerConnectionFactory factory = new PeerConnectionFactory(null /* opti
ons */); | |
| 430 final List<CaptureFormat> formats = capturer.getSupportedFormats(); | |
| 431 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | |
| 432 android.hardware.Camera camera = android.hardware.Camera.open(capturer.getCu
rrentCameraId()); | |
| 433 | |
| 434 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | |
| 435 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 436 final VideoSource source = factory.createVideoSource(capturer, new MediaCons
traints()); | |
| 437 final VideoTrack track = factory.createVideoTrack("dummy", source); | |
| 438 final RendererCallbacks callbacks = new RendererCallbacks(); | |
| 439 track.addRenderer(new VideoRenderer(callbacks)); | |
| 440 waitUntilIdle(capturer); | |
| 441 | |
| 442 camera.release(); | |
| 443 | |
| 444 // Make sure camera is started and first frame is received and then stop it. | |
| 445 callbacks.WaitForNextFrameToRender(); | |
| 446 capturer.stopCapture(); | |
| 447 release(capturer); | |
| 448 surfaceTextureHelper.dispose(); | |
| 449 } | |
| 450 | |
| 451 static public void startWhileCameraIsAlreadyOpenAndStop( | |
| 452 VideoCapturerAndroid capturer, Context appContext) throws InterruptedExcep
tion { | |
| 453 final List<CaptureFormat> formats = capturer.getSupportedFormats(); | |
| 454 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | |
| 455 android.hardware.Camera camera = android.hardware.Camera.open(capturer.getCu
rrentCameraId()); | |
| 456 | |
| 457 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | |
| 458 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 459 final FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 460 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 461 surfaceTextureHelper, appContext, observer); | |
| 462 capturer.stopCapture(); | |
| 463 release(capturer); | |
| 464 camera.release(); | |
| 465 surfaceTextureHelper.dispose(); | |
| 466 } | |
| 467 | |
| 468 static public void returnBufferLate(VideoCapturerAndroid capturer, | |
| 469 Context appContext) throws InterruptedException { | |
| 470 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | |
| 471 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 472 FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 473 | |
| 474 List<CaptureFormat> formats = capturer.getSupportedFormats(); | |
| 475 CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | |
| 476 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 477 surfaceTextureHelper, appContext, observer); | |
| 478 assertTrue(observer.WaitForCapturerToStart()); | |
| 479 | |
| 480 observer.WaitForNextCapturedFrame(); | |
| 481 capturer.stopCapture(); | |
| 482 List<Long> listOftimestamps = observer.getCopyAndResetListOftimeStamps(); | |
| 483 assertTrue(listOftimestamps.size() >= 1); | |
| 484 | |
| 485 format = formats.get(1); | |
| 486 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 487 surfaceTextureHelper, appContext, observer); | |
| 488 observer.WaitForCapturerToStart(); | |
| 489 if (capturer.isCapturingToTexture()) { | |
| 490 surfaceTextureHelper.returnTextureFrame(); | |
| 491 } | |
| 492 | |
| 493 observer.WaitForNextCapturedFrame(); | |
| 494 capturer.stopCapture(); | |
| 495 | |
| 496 listOftimestamps = observer.getCopyAndResetListOftimeStamps(); | |
| 497 assertTrue(listOftimestamps.size() >= 1); | |
| 498 if (capturer.isCapturingToTexture()) { | |
| 499 surfaceTextureHelper.returnTextureFrame(); | |
| 500 } | |
| 501 | |
| 502 release(capturer); | |
| 503 surfaceTextureHelper.dispose(); | |
| 504 } | |
| 505 | |
| 506 static public void returnBufferLateEndToEnd(VideoCapturerAndroid capturer) | |
| 507 throws InterruptedException { | |
| 508 final PeerConnectionFactory factory = new PeerConnectionFactory(null /* opti
ons */); | |
| 509 final VideoSource source = factory.createVideoSource(capturer, new MediaCons
traints()); | |
| 510 final VideoTrack track = factory.createVideoTrack("dummy", source); | |
| 511 final FakeAsyncRenderer renderer = new FakeAsyncRenderer(); | |
| 512 | |
| 513 track.addRenderer(new VideoRenderer(renderer)); | |
| 514 // Wait for at least one frame that has not been returned. | |
| 515 assertFalse(renderer.waitForPendingFrames().isEmpty()); | |
| 516 | |
| 517 capturer.stopCapture(); | |
| 518 | 542 |
| 519 // Dispose everything. | 543 // Dispose everything. |
| 520 track.dispose(); | 544 disposeVideoTrackWithRenderer(videoTrackWithRenderer); |
| 521 source.dispose(); | 545 disposeCapturer(capturerInstance); |
| 522 factory.dispose(); | |
| 523 | 546 |
| 524 // Return the frame(s), on a different thread out of spite. | 547 // Return the frame(s), on a different thread out of spite. |
| 525 final List<I420Frame> pendingFrames = renderer.waitForPendingFrames(); | 548 final List<I420Frame> pendingFrames = |
| 549 videoTrackWithRenderer.fakeAsyncRenderer.waitForPendingFrames(); |
| 526 final Thread returnThread = new Thread(new Runnable() { | 550 final Thread returnThread = new Thread(new Runnable() { |
| 527 @Override | 551 @Override |
| 528 public void run() { | 552 public void run() { |
| 529 for (I420Frame frame : pendingFrames) { | 553 for (I420Frame frame : pendingFrames) { |
| 530 VideoRenderer.renderFrameDone(frame); | 554 VideoRenderer.renderFrameDone(frame); |
| 531 } | 555 } |
| 532 } | 556 } |
| 533 }); | 557 }); |
| 534 returnThread.start(); | 558 returnThread.start(); |
| 535 returnThread.join(); | 559 returnThread.join(); |
| 536 } | 560 } |
| 537 | 561 |
| 538 static public void cameraFreezedEventOnBufferStarvationUsingTextures( | 562 public void cameraFreezedEventOnBufferStarvation() throws InterruptedException
{ |
| 539 VideoCapturerAndroid capturer, | 563 final CapturerInstance capturerInstance = createCapturer(); |
| 540 CameraEvents events, Context appContext) throws InterruptedException { | 564 startCapture(capturerInstance); |
| 541 assertTrue("Not capturing to textures.", capturer.isCapturingToTexture()); | |
| 542 | |
| 543 final List<CaptureFormat> formats = capturer.getSupportedFormats(); | |
| 544 final CameraEnumerationAndroid.CaptureFormat format = formats.get(0); | |
| 545 | |
| 546 final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.creat
e( | |
| 547 "SurfaceTextureHelper test" /* threadName */, null /* sharedContext */); | |
| 548 final FakeCapturerObserver observer = new FakeCapturerObserver(); | |
| 549 capturer.startCapture(format.width, format.height, format.framerate.max, | |
| 550 surfaceTextureHelper, appContext, observer); | |
| 551 // Make sure camera is started. | 565 // Make sure camera is started. |
| 552 assertTrue(observer.WaitForCapturerToStart()); | 566 assertTrue(capturerInstance.observer.waitForCapturerToStart()); |
| 553 // Since we don't return the buffer, we should get a starvation message if w
e are | 567 // Since we don't return the buffer, we should get a starvation message if w
e are |
| 554 // capturing to a texture. | 568 // capturing to a texture. |
| 555 assertEquals("Camera failure. Client must return video buffers.", | 569 assertEquals("Camera failure. Client must return video buffers.", |
| 556 events.WaitForCameraFreezed()); | 570 capturerInstance.cameraEvents.waitForCameraFreezed()); |
| 557 | 571 |
| 558 capturer.stopCapture(); | 572 capturerInstance.capturer.stopCapture(); |
| 559 if (capturer.isCapturingToTexture()) { | 573 disposeCapturer(capturerInstance); |
| 560 surfaceTextureHelper.returnTextureFrame(); | |
| 561 } | |
| 562 | |
| 563 release(capturer); | |
| 564 surfaceTextureHelper.dispose(); | |
| 565 } | 574 } |
| 566 | 575 |
| 567 static public void scaleCameraOutput(VideoCapturerAndroid capturer) throws Int
erruptedException { | 576 public void scaleCameraOutput() throws InterruptedException { |
| 568 PeerConnectionFactory factory = new PeerConnectionFactory(null /* options */
); | 577 final CapturerInstance capturerInstance = createCapturer(); |
| 569 VideoSource source = | 578 final VideoTrackWithRenderer videoTrackWithRenderer = |
| 570 factory.createVideoSource(capturer, new MediaConstraints()); | 579 createVideoTrackWithRenderer(capturerInstance.capturer); |
| 571 VideoTrack track = factory.createVideoTrack("dummy", source); | 580 assertTrue(videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender
() > 0); |
| 572 RendererCallbacks renderer = new RendererCallbacks(); | |
| 573 track.addRenderer(new VideoRenderer(renderer)); | |
| 574 assertTrue(renderer.WaitForNextFrameToRender() > 0); | |
| 575 | 581 |
| 576 final int startWidth = renderer.frameWidth(); | 582 final int startWidth = videoTrackWithRenderer.rendererCallbacks.frameWidth()
; |
| 577 final int startHeight = renderer.frameHeight(); | 583 final int startHeight = videoTrackWithRenderer.rendererCallbacks.frameHeight
(); |
| 578 final int frameRate = 30; | 584 final int frameRate = 30; |
| 579 final int scaledWidth = startWidth / 2; | 585 final int scaledWidth = startWidth / 2; |
| 580 final int scaledHeight = startHeight / 2; | 586 final int scaledHeight = startHeight / 2; |
| 581 | 587 |
| 582 // Request the captured frames to be scaled. | 588 // Request the captured frames to be scaled. |
| 583 capturer.onOutputFormatRequest(scaledWidth, scaledHeight, frameRate); | 589 capturerInstance.capturer.onOutputFormatRequest(scaledWidth, scaledHeight, f
rameRate); |
| 584 | 590 |
| 585 boolean gotExpectedResolution = false; | 591 boolean gotExpectedResolution = false; |
| 586 int numberOfInspectedFrames = 0; | 592 int numberOfInspectedFrames = 0; |
| 587 | 593 |
| 588 do { | 594 do { |
| 589 renderer.WaitForNextFrameToRender(); | 595 videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender(); |
| 590 ++numberOfInspectedFrames; | 596 ++numberOfInspectedFrames; |
| 591 | 597 |
| 592 gotExpectedResolution = (renderer.frameWidth() == scaledWidth | 598 gotExpectedResolution = (videoTrackWithRenderer.rendererCallbacks.frameWid
th() == scaledWidth |
| 593 && renderer.frameHeight() == scaledHeight); | 599 && videoTrackWithRenderer.rendererCallbacks.frameHeight() == scaledHe
ight); |
| 594 } while (!gotExpectedResolution && numberOfInspectedFrames < 30); | 600 } while (!gotExpectedResolution && numberOfInspectedFrames < 30); |
| 595 | 601 |
| 596 source.stop(); | 602 disposeVideoTrackWithRenderer(videoTrackWithRenderer); |
| 597 track.dispose(); | 603 disposeCapturer(capturerInstance); |
| 598 source.dispose(); | |
| 599 factory.dispose(); | |
| 600 | 604 |
| 601 assertTrue(gotExpectedResolution); | 605 assertTrue(gotExpectedResolution); |
| 602 } | 606 } |
| 603 | 607 |
| 608 public void startWhileCameraIsAlreadyOpen() throws InterruptedException { |
| 609 final String cameraName = testObjectFactory.getNameOfBackFacingDevice(); |
| 610 // At this point camera is not actually opened. |
| 611 final CapturerInstance capturerInstance = createCapturer(cameraName); |
| 612 |
| 613 final Object competingCamera = testObjectFactory.rawOpenCamera(cameraName); |
| 614 |
| 615 startCapture(capturerInstance); |
| 616 |
| 617 if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.LOLLIP
OP_MR1) { |
| 618 // The first opened camera client will be evicted. |
| 619 assertTrue(capturerInstance.observer.waitForCapturerToStart()); |
| 620 capturerInstance.capturer.stopCapture(); |
| 621 } else { |
| 622 assertFalse(capturerInstance.observer.waitForCapturerToStart()); |
| 623 } |
| 624 |
| 625 testObjectFactory.rawCloseCamera(competingCamera); |
| 626 disposeCapturer(capturerInstance); |
| 627 } |
| 628 |
| 629 public void startWhileCameraIsAlreadyOpenAndCloseCamera() throws InterruptedEx
ception { |
| 630 final String cameraName = testObjectFactory.getNameOfBackFacingDevice(); |
| 631 // At this point camera is not actually opened. |
| 632 final CapturerInstance capturerInstance = createCapturer(cameraName); |
| 633 |
| 634 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Opening competi
ng camera."); |
| 635 final Object competingCamera = testObjectFactory.rawOpenCamera(cameraName); |
| 636 |
| 637 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Opening camera.
"); |
| 638 final VideoTrackWithRenderer videoTrackWithRenderer = |
| 639 createVideoTrackWithRenderer(capturerInstance.capturer); |
| 640 waitUntilIdle(capturerInstance); |
| 641 |
| 642 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Closing competi
ng camera."); |
| 643 testObjectFactory.rawCloseCamera(competingCamera); |
| 644 |
| 645 // Make sure camera is started and first frame is received and then stop it. |
| 646 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Waiting for cap
ture to start."); |
| 647 videoTrackWithRenderer.rendererCallbacks.waitForNextFrameToRender(); |
| 648 Logging.d(TAG, "startWhileCameraIsAlreadyOpenAndCloseCamera: Stopping captur
e."); |
| 649 capturerInstance.capturer.stopCapture(); |
| 650 disposeCapturer(capturerInstance); |
| 651 } |
| 652 |
| 653 public void startWhileCameraIsAlreadyOpenAndStop() throws InterruptedException
{ |
| 654 final String cameraName = testObjectFactory.getNameOfBackFacingDevice(); |
| 655 // At this point camera is not actually opened. |
| 656 final CapturerInstance capturerInstance = createCapturer(cameraName); |
| 657 |
| 658 final Object competingCamera = testObjectFactory.rawOpenCamera(cameraName); |
| 659 |
| 660 startCapture(capturerInstance); |
| 661 |
| 662 capturerInstance.capturer.stopCapture(); |
| 663 disposeCapturer(capturerInstance); |
| 664 |
| 665 testObjectFactory.rawCloseCamera(competingCamera); |
| 666 } |
| 604 } | 667 } |
| OLD | NEW |