- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / media / video_capture_controller_unittest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Unit test for VideoCaptureController.
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "content/browser/renderer_host/media/media_stream_provider.h"
16 #include "content/browser/renderer_host/media/video_capture_controller.h"
17 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
18 #include "content/browser/renderer_host/media/video_capture_manager.h"
19 #include "content/common/media/media_stream_options.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "media/base/video_frame.h"
22 #include "media/base/video_util.h"
23 #include "media/video/capture/video_capture_types.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 using ::testing::InSequence;
28 using ::testing::Mock;
29
30 namespace content {
31
32 class MockVideoCaptureControllerEventHandler
33     : public VideoCaptureControllerEventHandler {
34  public:
35   explicit MockVideoCaptureControllerEventHandler(
36       VideoCaptureController* controller)
37       : controller_(controller) {}
38   virtual ~MockVideoCaptureControllerEventHandler() {}
39
40   // These mock methods are delegated to by our fake implementation of
41   // VideoCaptureControllerEventHandler, to be used in EXPECT_CALL().
42   MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&));
43   MOCK_METHOD1(DoBufferDestroyed, void(const VideoCaptureControllerID&));
44   MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&));
45   MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&));
46   MOCK_METHOD1(DoError, void(const VideoCaptureControllerID&));
47
48   virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE {
49     DoError(id);
50   }
51   virtual void OnBufferCreated(const VideoCaptureControllerID& id,
52                                base::SharedMemoryHandle handle,
53                                int length, int buffer_id) OVERRIDE {
54     DoBufferCreated(id);
55   }
56   virtual void OnBufferDestroyed(const VideoCaptureControllerID& id,
57                                  int buffer_id) OVERRIDE {
58     DoBufferDestroyed(id);
59   }
60   virtual void OnBufferReady(const VideoCaptureControllerID& id,
61                              int buffer_id,
62                              base::Time timestamp,
63                              const media::VideoCaptureFormat& format) OVERRIDE {
64     DoBufferReady(id);
65     base::MessageLoop::current()->PostTask(FROM_HERE,
66         base::Bind(&VideoCaptureController::ReturnBuffer,
67                    base::Unretained(controller_), id, this, buffer_id));
68   }
69   virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE {
70     DoEnded(id);
71     // OnEnded() must respond by (eventually) unregistering the client.
72     base::MessageLoop::current()->PostTask(FROM_HERE,
73         base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient),
74                    base::Unretained(controller_), id, this));
75   }
76
77   VideoCaptureController* controller_;
78 };
79
80 // Test class.
81 class VideoCaptureControllerTest : public testing::Test {
82  public:
83   VideoCaptureControllerTest() {}
84   virtual ~VideoCaptureControllerTest() {}
85
86  protected:
87   static const int kPoolSize = 3;
88
89   virtual void SetUp() OVERRIDE {
90     controller_.reset(new VideoCaptureController());
91     device_ = controller_->NewDeviceClient().Pass();
92     client_a_.reset(new MockVideoCaptureControllerEventHandler(
93         controller_.get()));
94     client_b_.reset(new MockVideoCaptureControllerEventHandler(
95         controller_.get()));
96   }
97
98   virtual void TearDown() OVERRIDE {
99     base::RunLoop().RunUntilIdle();
100   }
101
102   TestBrowserThreadBundle bindle_;
103   scoped_ptr<MockVideoCaptureControllerEventHandler> client_a_;
104   scoped_ptr<MockVideoCaptureControllerEventHandler> client_b_;
105   scoped_ptr<VideoCaptureController> controller_;
106   scoped_ptr<media::VideoCaptureDevice::Client> device_;
107
108  private:
109   DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest);
110 };
111
112 // A simple test of VideoCaptureController's ability to add, remove, and keep
113 // track of clients.
114 TEST_F(VideoCaptureControllerTest, AddAndRemoveClients) {
115   media::VideoCaptureParams session_100;
116   session_100.session_id = 100;
117   session_100.requested_format = media::VideoCaptureFormat(
118       320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
119
120   media::VideoCaptureParams session_200 = session_100;
121   session_200.session_id = 200;
122
123   media::VideoCaptureParams session_300 = session_100;
124   session_300.session_id = 300;
125
126   media::VideoCaptureParams session_400 = session_100;
127   session_400.session_id = 400;
128
129   // Intentionally use the same route ID for two of the clients: the device_ids
130   // are a per-VideoCaptureHost namespace, and can overlap across hosts.
131   const VideoCaptureControllerID client_a_route_1(44);
132   const VideoCaptureControllerID client_a_route_2(30);
133   const VideoCaptureControllerID client_b_route_1(30);
134   const VideoCaptureControllerID client_b_route_2(1);
135
136   // Clients in controller: []
137   ASSERT_EQ(0, controller_->GetClientCount())
138       << "Client count should initially be zero.";
139   controller_->AddClient(client_a_route_1, client_a_.get(),
140                          base::kNullProcessHandle, session_100);
141   // Clients in controller: [A/1]
142   ASSERT_EQ(1, controller_->GetClientCount())
143       << "Adding client A/1 should bump client count.";;
144   controller_->AddClient(client_a_route_2, client_a_.get(),
145                          base::kNullProcessHandle, session_200);
146   // Clients in controller: [A/1, A/2]
147   ASSERT_EQ(2, controller_->GetClientCount())
148       << "Adding client A/2 should bump client count.";
149   controller_->AddClient(client_b_route_1, client_b_.get(),
150                          base::kNullProcessHandle, session_300);
151   // Clients in controller: [A/1, A/2, B/1]
152   ASSERT_EQ(3, controller_->GetClientCount())
153       << "Adding client B/1 should bump client count.";
154   ASSERT_EQ(200,
155       controller_->RemoveClient(client_a_route_2, client_a_.get()))
156       << "Removing client A/1 should return its session_id.";
157   // Clients in controller: [A/1, B/1]
158   ASSERT_EQ(2, controller_->GetClientCount());
159   ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
160       controller_->RemoveClient(client_a_route_2, client_a_.get()))
161       << "Removing a nonexistant client should fail.";
162   // Clients in controller: [A/1, B/1]
163   ASSERT_EQ(2, controller_->GetClientCount());
164   ASSERT_EQ(300,
165       controller_->RemoveClient(client_b_route_1, client_b_.get()))
166       << "Removing client B/1 should return its session_id.";
167   // Clients in controller: [A/1]
168   ASSERT_EQ(1, controller_->GetClientCount());
169   controller_->AddClient(client_b_route_2, client_b_.get(),
170                          base::kNullProcessHandle, session_400);
171   // Clients in controller: [A/1, B/2]
172
173   EXPECT_CALL(*client_a_, DoEnded(client_a_route_1)).Times(1);
174   controller_->StopSession(100);  // Session 100 == client A/1
175   Mock::VerifyAndClearExpectations(client_a_.get());
176   ASSERT_EQ(2, controller_->GetClientCount())
177       << "Client should be closed but still exist after StopSession.";
178   // Clients in controller: [A/1 (closed, removal pending), B/2]
179   base::RunLoop().RunUntilIdle();
180   // Clients in controller: [B/2]
181   ASSERT_EQ(1, controller_->GetClientCount())
182       << "Client A/1 should be deleted by now.";
183   controller_->StopSession(200);  // Session 200 does not exist anymore
184   // Clients in controller: [B/2]
185   ASSERT_EQ(1, controller_->GetClientCount())
186       << "Stopping non-existant session 200 should be a no-op.";
187   controller_->StopSession(256);  // Session 256 never existed.
188   // Clients in controller: [B/2]
189   ASSERT_EQ(1, controller_->GetClientCount())
190       << "Stopping non-existant session 256 should be a no-op.";
191   ASSERT_EQ(static_cast<int>(kInvalidMediaCaptureSessionId),
192       controller_->RemoveClient(client_a_route_1, client_a_.get()))
193       << "Removing already-removed client A/1 should fail.";
194   // Clients in controller: [B/2]
195   ASSERT_EQ(1, controller_->GetClientCount())
196       << "Removing non-existant session 200 should be a no-op.";
197   ASSERT_EQ(400,
198       controller_->RemoveClient(client_b_route_2, client_b_.get()))
199       << "Removing client B/2 should return its session_id.";
200   // Clients in controller: []
201   ASSERT_EQ(0, controller_->GetClientCount())
202       << "Client count should return to zero after all clients are gone.";
203 }
204
205 // This test will connect and disconnect several clients while simulating an
206 // active capture device being started and generating frames. It runs on one
207 // thread and is intended to behave deterministically.
208 TEST_F(VideoCaptureControllerTest, NormalCaptureMultipleClients) {
209   media::VideoCaptureParams session_100;
210   session_100.session_id = 100;
211   session_100.requested_format = media::VideoCaptureFormat(
212       320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
213
214   media::VideoCaptureParams session_200 = session_100;
215   session_200.session_id = 200;
216
217   media::VideoCaptureParams session_300 = session_100;
218   session_300.session_id = 300;
219
220   media::VideoCaptureParams session_1 = session_100;
221   session_1.session_id = 1;
222
223   gfx::Size capture_resolution(444, 200);
224
225   // The device format needn't match the VideoCaptureParams (the camera can do
226   // what it wants). Pick something random to use for OnFrameInfo.
227   media::VideoCaptureCapability device_format(
228       10, 10, 25, media::PIXEL_FORMAT_RGB24,
229       media::ConstantResolutionVideoCaptureDevice);
230
231   const VideoCaptureControllerID client_a_route_1(0xa1a1a1a1);
232   const VideoCaptureControllerID client_a_route_2(0xa2a2a2a2);
233   const VideoCaptureControllerID client_b_route_1(0xb1b1b1b1);
234   const VideoCaptureControllerID client_b_route_2(0xb2b2b2b2);
235
236   // Start with two clients.
237   controller_->AddClient(client_a_route_1, client_a_.get(),
238                          base::kNullProcessHandle, session_100);
239   controller_->AddClient(client_b_route_1, client_b_.get(),
240                          base::kNullProcessHandle, session_300);
241   controller_->AddClient(client_a_route_2, client_a_.get(),
242                          base::kNullProcessHandle, session_200);
243   ASSERT_EQ(3, controller_->GetClientCount());
244
245   // Now, simulate an incoming captured frame from the capture device. As a side
246   // effect this will cause the first buffer to be shared with clients.
247   uint8 frame_no = 1;
248   scoped_refptr<media::VideoFrame> frame;
249   frame = device_->ReserveOutputBuffer(capture_resolution);
250   ASSERT_TRUE(frame);
251   media::FillYUV(frame, frame_no++, 0x22, 0x44);
252   {
253     InSequence s;
254     EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1)).Times(1);
255     EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
256   }
257   {
258     InSequence s;
259     EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1)).Times(1);
260     EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
261   }
262   {
263     InSequence s;
264     EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2)).Times(1);
265     EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
266   }
267   device_->OnIncomingCapturedVideoFrame(frame, base::Time());
268   frame = NULL;
269
270   base::RunLoop().RunUntilIdle();
271   Mock::VerifyAndClearExpectations(client_a_.get());
272   Mock::VerifyAndClearExpectations(client_b_.get());
273
274   // Second frame which ought to use the same shared memory buffer. In this case
275   // pretend that the VideoFrame pointer is held by the device for a long delay.
276   // This shouldn't affect anything.
277   frame = device_->ReserveOutputBuffer(capture_resolution);
278   ASSERT_TRUE(frame);
279   media::FillYUV(frame, frame_no++, 0x22, 0x44);
280   device_->OnIncomingCapturedVideoFrame(frame, base::Time());
281
282   // The buffer should be delivered to the clients in any order.
283   EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(1);
284   EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(1);
285   EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(1);
286   base::RunLoop().RunUntilIdle();
287   Mock::VerifyAndClearExpectations(client_a_.get());
288   Mock::VerifyAndClearExpectations(client_b_.get());
289   frame = NULL;
290
291   // Add a fourth client now that some frames have come through.
292   controller_->AddClient(client_b_route_2, client_b_.get(),
293                          base::kNullProcessHandle, session_1);
294   Mock::VerifyAndClearExpectations(client_b_.get());
295
296   // Third, fourth, and fifth frames. Pretend they all arrive at the same time.
297   for (int i = 0; i < kPoolSize; i++) {
298     frame = device_->ReserveOutputBuffer(capture_resolution);
299     ASSERT_TRUE(frame);
300     ASSERT_EQ(media::VideoFrame::I420, frame->format());
301     media::FillYUV(frame, frame_no++, 0x22, 0x44);
302     device_->OnIncomingCapturedVideoFrame(frame, base::Time());
303
304   }
305   // ReserveOutputBuffer ought to fail now, because the pool is depleted.
306   ASSERT_FALSE(device_->ReserveOutputBuffer(capture_resolution));
307
308   // The new client needs to be told of 3 buffers; the old clients only 2.
309   EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_2)).Times(kPoolSize);
310   EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(kPoolSize);
311   EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_1))
312       .Times(kPoolSize - 1);
313   EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_1)).Times(kPoolSize);
314   EXPECT_CALL(*client_a_, DoBufferCreated(client_a_route_2))
315       .Times(kPoolSize - 1);
316   EXPECT_CALL(*client_a_, DoBufferReady(client_a_route_2)).Times(kPoolSize);
317   EXPECT_CALL(*client_b_, DoBufferCreated(client_b_route_1))
318       .Times(kPoolSize - 1);
319   EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_1)).Times(kPoolSize);
320   base::RunLoop().RunUntilIdle();
321   Mock::VerifyAndClearExpectations(client_a_.get());
322   Mock::VerifyAndClearExpectations(client_b_.get());
323
324   // Now test the interaction of client shutdown and frame delivery.
325   // Kill A1 via renderer disconnect (synchronous).
326   controller_->RemoveClient(client_a_route_1, client_a_.get());
327   // Kill B1 via session close (posts a task to disconnect).
328   EXPECT_CALL(*client_b_, DoEnded(client_b_route_1)).Times(1);
329   controller_->StopSession(300);
330   // Queue up another frame.
331   frame = device_->ReserveOutputBuffer(capture_resolution);
332   ASSERT_TRUE(frame);
333   media::FillYUV(frame, frame_no++, 0x22, 0x44);
334   device_->OnIncomingCapturedVideoFrame(frame, base::Time());
335   frame = device_->ReserveOutputBuffer(capture_resolution);
336   {
337     // Kill A2 via session close (posts a task to disconnect, but A2 must not
338     // be sent either of these two frames)..
339     EXPECT_CALL(*client_a_, DoEnded(client_a_route_2)).Times(1);
340     controller_->StopSession(200);
341   }
342   ASSERT_TRUE(frame);
343   media::FillYUV(frame, frame_no++, 0x22, 0x44);
344   device_->OnIncomingCapturedVideoFrame(frame, base::Time());
345   // B2 is the only client left, and is the only one that should
346   // get the frame.
347   EXPECT_CALL(*client_b_, DoBufferReady(client_b_route_2)).Times(2);
348   base::RunLoop().RunUntilIdle();
349   Mock::VerifyAndClearExpectations(client_a_.get());
350   Mock::VerifyAndClearExpectations(client_b_.get());
351 }
352
353 // Exercises the OnError() codepath of VideoCaptureController, and tests the
354 // behavior of various operations after the error state has been signalled.
355 TEST_F(VideoCaptureControllerTest, ErrorBeforeDeviceCreation) {
356   media::VideoCaptureParams session_100;
357   session_100.session_id = 100;
358   session_100.requested_format = media::VideoCaptureFormat(
359     320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
360
361   media::VideoCaptureParams session_200 = session_100;
362   session_200.session_id = 200;
363
364   const VideoCaptureControllerID route_id(0x99);
365
366   // Start with one client.
367   controller_->AddClient(route_id, client_a_.get(),
368                          base::kNullProcessHandle, session_100);
369   device_->OnError();
370   EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
371   base::RunLoop().RunUntilIdle();
372   Mock::VerifyAndClearExpectations(client_a_.get());
373
374   // Second client connects after the error state. It also should get told of
375   // the error.
376   EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
377   controller_->AddClient(route_id, client_b_.get(),
378                          base::kNullProcessHandle, session_200);
379   base::RunLoop().RunUntilIdle();
380   Mock::VerifyAndClearExpectations(client_b_.get());
381
382   // OnFrameInfo from the VCD should become a no-op after the error occurs.
383   media::VideoCaptureCapability device_format(
384       10, 10, 25, media::PIXEL_FORMAT_ARGB,
385       media::ConstantResolutionVideoCaptureDevice);
386
387   device_->OnFrameInfo(device_format);
388   base::RunLoop().RunUntilIdle();
389 }
390
391 // Exercises the OnError() codepath of VideoCaptureController, and tests the
392 // behavior of various operations after the error state has been signalled.
393 TEST_F(VideoCaptureControllerTest, ErrorAfterDeviceCreation) {
394   media::VideoCaptureParams session_100;
395   session_100.session_id = 100;
396   session_100.requested_format = media::VideoCaptureFormat(
397       320, 240, 30, media::ConstantResolutionVideoCaptureDevice);
398
399   media::VideoCaptureParams session_200 = session_100;
400   session_200.session_id = 200;
401
402   const VideoCaptureControllerID route_id(0x99);
403
404   // Start with one client.
405   controller_->AddClient(route_id, client_a_.get(),
406                          base::kNullProcessHandle, session_100);
407   // OnFrameInfo from the VCD should become a no-op after the error occurs.
408   media::VideoCaptureCapability device_format(
409       10, 10, 25, media::PIXEL_FORMAT_ARGB,
410       media::ConstantResolutionVideoCaptureDevice);
411
412   // Start the device. Then, before the first frame, signal an error and deliver
413   // the frame. The error should be propagated to clients; the frame should not
414   // be.
415   base::RunLoop().RunUntilIdle();
416   Mock::VerifyAndClearExpectations(client_a_.get());
417
418   scoped_refptr<media::VideoFrame> frame =
419       device_->ReserveOutputBuffer(gfx::Size(320, 240));
420   ASSERT_TRUE(frame);
421
422   device_->OnError();
423   device_->OnIncomingCapturedVideoFrame(frame, base::Time());
424   frame = NULL;
425
426   EXPECT_CALL(*client_a_, DoError(route_id)).Times(1);
427   base::RunLoop().RunUntilIdle();
428   Mock::VerifyAndClearExpectations(client_a_.get());
429
430   // Second client connects after the error state. It also should get told of
431   // the error.
432   EXPECT_CALL(*client_b_, DoError(route_id)).Times(1);
433   controller_->AddClient(route_id, client_b_.get(),
434                          base::kNullProcessHandle, session_200);
435   Mock::VerifyAndClearExpectations(client_b_.get());
436 }
437
438 }  // namespace content