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 |