1/*
2 * libjingle
3 * Copyright 2012, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <string>
29#include <vector>
30
31#include "talk/app/webrtc/test/fakeconstraints.h"
32#include "talk/app/webrtc/remotevideocapturer.h"
33#include "talk/app/webrtc/videosource.h"
34#include "talk/base/gunit.h"
35#include "talk/media/base/fakemediaengine.h"
36#include "talk/media/base/fakevideorenderer.h"
37#include "talk/media/devices/fakedevicemanager.h"
38#include "talk/media/webrtc/webrtcvideoframe.h"
39#include "talk/session/media/channelmanager.h"
40
41using webrtc::FakeConstraints;
42using webrtc::VideoSource;
43using webrtc::MediaConstraintsInterface;
44using webrtc::MediaSourceInterface;
45using webrtc::ObserverInterface;
46using webrtc::VideoSourceInterface;
47
48namespace {
49
50// Max wait time for a test.
51const int kMaxWaitMs = 100;
52
53}  // anonymous namespace
54
55
56// TestVideoCapturer extends cricket::FakeVideoCapturer so it can be used for
57// testing without known camera formats.
58// It keeps its own lists of cricket::VideoFormats for the unit tests in this
59// file.
60class TestVideoCapturer : public cricket::FakeVideoCapturer {
61 public:
62  TestVideoCapturer() : test_without_formats_(false) {
63    std::vector<cricket::VideoFormat> formats;
64    formats.push_back(cricket::VideoFormat(1280, 720,
65        cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
66    formats.push_back(cricket::VideoFormat(640, 480,
67        cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
68    formats.push_back(cricket::VideoFormat(640, 400,
69            cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
70    formats.push_back(cricket::VideoFormat(320, 240,
71        cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
72    formats.push_back(cricket::VideoFormat(352, 288,
73            cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
74    ResetSupportedFormats(formats);
75  }
76
77  // This function is used for resetting the supported capture formats and
78  // simulating a cricket::VideoCapturer implementation that don't support
79  // capture format enumeration. This is used to simulate the current
80  // Chrome implementation.
81  void TestWithoutCameraFormats() {
82    test_without_formats_ = true;
83    std::vector<cricket::VideoFormat> formats;
84    ResetSupportedFormats(formats);
85  }
86
87  virtual cricket::CaptureState Start(
88      const cricket::VideoFormat& capture_format) {
89    if (test_without_formats_) {
90      std::vector<cricket::VideoFormat> formats;
91      formats.push_back(capture_format);
92      ResetSupportedFormats(formats);
93    }
94    return FakeVideoCapturer::Start(capture_format);
95  }
96
97  virtual bool GetBestCaptureFormat(const cricket::VideoFormat& desired,
98                                    cricket::VideoFormat* best_format) {
99    if (test_without_formats_) {
100      *best_format = desired;
101      return true;
102    }
103    return FakeVideoCapturer::GetBestCaptureFormat(desired,
104                                                   best_format);
105  }
106
107 private:
108  bool test_without_formats_;
109};
110
111class StateObserver : public ObserverInterface {
112 public:
113  explicit StateObserver(VideoSourceInterface* source)
114     : state_(source->state()),
115       source_(source) {
116  }
117  virtual void OnChanged() {
118    state_ = source_->state();
119  }
120  MediaSourceInterface::SourceState state() const { return state_; }
121
122 private:
123  MediaSourceInterface::SourceState state_;
124  talk_base::scoped_refptr<VideoSourceInterface> source_;
125};
126
127class VideoSourceTest : public testing::Test {
128 protected:
129  VideoSourceTest()
130      : capturer_cleanup_(new TestVideoCapturer()),
131        capturer_(capturer_cleanup_.get()),
132        channel_manager_(new cricket::ChannelManager(
133          new cricket::FakeMediaEngine(),
134          new cricket::FakeDeviceManager(), talk_base::Thread::Current())) {
135  }
136
137  void SetUp() {
138    ASSERT_TRUE(channel_manager_->Init());
139  }
140
141  void CreateVideoSource() {
142    CreateVideoSource(NULL);
143  }
144
145  void CreateVideoSource(
146      const webrtc::MediaConstraintsInterface* constraints) {
147    // VideoSource take ownership of |capturer_|
148    source_ = VideoSource::Create(channel_manager_.get(),
149                                  capturer_cleanup_.release(),
150                                  constraints);
151
152    ASSERT_TRUE(source_.get() != NULL);
153    EXPECT_EQ(capturer_, source_->GetVideoCapturer());
154
155    state_observer_.reset(new StateObserver(source_));
156    source_->RegisterObserver(state_observer_.get());
157    source_->AddSink(&renderer_);
158  }
159
160  talk_base::scoped_ptr<TestVideoCapturer> capturer_cleanup_;
161  TestVideoCapturer* capturer_;
162  cricket::FakeVideoRenderer renderer_;
163  talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
164  talk_base::scoped_ptr<StateObserver> state_observer_;
165  talk_base::scoped_refptr<VideoSource> source_;
166};
167
168
169// Test that a VideoSource transition to kLive state when the capture
170// device have started and kEnded if it is stopped.
171// It also test that an output can receive video frames.
172TEST_F(VideoSourceTest, StartStop) {
173  // Initialize without constraints.
174  CreateVideoSource();
175  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
176                 kMaxWaitMs);
177
178  ASSERT_TRUE(capturer_->CaptureFrame());
179  EXPECT_EQ(1, renderer_.num_rendered_frames());
180
181  capturer_->Stop();
182  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
183                 kMaxWaitMs);
184}
185
186// Test start stop with a remote VideoSource - the video source that has a
187// RemoteVideoCapturer and takes video frames from FrameInput.
188TEST_F(VideoSourceTest, StartStopRemote) {
189  source_ = VideoSource::Create(channel_manager_.get(),
190                                new webrtc::RemoteVideoCapturer(),
191                                NULL);
192
193  ASSERT_TRUE(source_.get() != NULL);
194  EXPECT_TRUE(NULL != source_->GetVideoCapturer());
195
196  state_observer_.reset(new StateObserver(source_));
197  source_->RegisterObserver(state_observer_.get());
198  source_->AddSink(&renderer_);
199
200  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
201                 kMaxWaitMs);
202
203  cricket::VideoRenderer* frameinput = source_->FrameInput();
204  cricket::WebRtcVideoFrame test_frame;
205  frameinput->SetSize(1280, 720, 0);
206  frameinput->RenderFrame(&test_frame);
207  EXPECT_EQ(1, renderer_.num_rendered_frames());
208
209  source_->GetVideoCapturer()->Stop();
210  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
211                 kMaxWaitMs);
212}
213
214// Test that a VideoSource transition to kEnded if the capture device
215// fails.
216TEST_F(VideoSourceTest, CameraFailed) {
217  CreateVideoSource();
218  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
219                 kMaxWaitMs);
220
221  capturer_->SignalStateChange(capturer_, cricket::CS_FAILED);
222  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
223                 kMaxWaitMs);
224}
225
226// Test that the capture output is CIF if we set max constraints to CIF.
227// and the capture device support CIF.
228TEST_F(VideoSourceTest, MandatoryConstraintCif5Fps) {
229  FakeConstraints constraints;
230  constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 352);
231  constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 288);
232  constraints.AddMandatory(MediaConstraintsInterface::kMaxFrameRate, 5);
233
234  CreateVideoSource(&constraints);
235  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
236                 kMaxWaitMs);
237  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
238  ASSERT_TRUE(format != NULL);
239  EXPECT_EQ(352, format->width);
240  EXPECT_EQ(288, format->height);
241  EXPECT_EQ(5, format->framerate());
242}
243
244// Test that the capture output is 720P if the camera support it and the
245// optional constraint is set to 720P.
246TEST_F(VideoSourceTest, MandatoryMinVgaOptional720P) {
247  FakeConstraints constraints;
248  constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640);
249  constraints.AddMandatory(MediaConstraintsInterface::kMinHeight, 480);
250  constraints.AddOptional(MediaConstraintsInterface::kMinWidth, 1280);
251  constraints.AddOptional(MediaConstraintsInterface::kMinAspectRatio,
252                          1280.0 / 720);
253
254  CreateVideoSource(&constraints);
255  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
256                 kMaxWaitMs);
257  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
258  ASSERT_TRUE(format != NULL);
259  EXPECT_EQ(1280, format->width);
260  EXPECT_EQ(720, format->height);
261  EXPECT_EQ(30, format->framerate());
262}
263
264// Test that the capture output have aspect ratio 4:3 if a mandatory constraint
265// require it even if an optional constraint request a higher resolution
266// that don't have this aspect ratio.
267TEST_F(VideoSourceTest, MandatoryAspectRatio4To3) {
268  FakeConstraints constraints;
269  constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640);
270  constraints.AddMandatory(MediaConstraintsInterface::kMinHeight, 480);
271  constraints.AddMandatory(MediaConstraintsInterface::kMaxAspectRatio,
272                           640.0 / 480);
273  constraints.AddOptional(MediaConstraintsInterface::kMinWidth, 1280);
274
275  CreateVideoSource(&constraints);
276  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
277                 kMaxWaitMs);
278  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
279  ASSERT_TRUE(format != NULL);
280  EXPECT_EQ(640, format->width);
281  EXPECT_EQ(480, format->height);
282  EXPECT_EQ(30, format->framerate());
283}
284
285
286// Test that the source state transition to kEnded if the mandatory aspect ratio
287// is set higher than supported.
288TEST_F(VideoSourceTest, MandatoryAspectRatioTooHigh) {
289  FakeConstraints constraints;
290  constraints.AddMandatory(MediaConstraintsInterface::kMinAspectRatio, 2);
291  CreateVideoSource(&constraints);
292  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
293                 kMaxWaitMs);
294}
295
296// Test that the source ignores an optional aspect ratio that is higher than
297// supported.
298TEST_F(VideoSourceTest, OptionalAspectRatioTooHigh) {
299  FakeConstraints constraints;
300  constraints.AddOptional(MediaConstraintsInterface::kMinAspectRatio, 2);
301  CreateVideoSource(&constraints);
302  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
303                 kMaxWaitMs);
304  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
305  ASSERT_TRUE(format != NULL);
306  double aspect_ratio = static_cast<double>(format->width) / format->height;
307  EXPECT_LT(aspect_ratio, 2);
308}
309
310// Test that the source starts video with the default resolution if the
311// camera doesn't support capability enumeration and there are no constraints.
312TEST_F(VideoSourceTest, NoCameraCapability) {
313  capturer_->TestWithoutCameraFormats();
314
315  CreateVideoSource();
316  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
317                 kMaxWaitMs);
318  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
319  ASSERT_TRUE(format != NULL);
320  EXPECT_EQ(640, format->width);
321  EXPECT_EQ(480, format->height);
322  EXPECT_EQ(30, format->framerate());
323}
324
325// Test that the source can start the video and get the requested aspect ratio
326// if the camera doesn't support capability enumeration and the aspect ratio is
327// set.
328TEST_F(VideoSourceTest, NoCameraCapability16To9Ratio) {
329  capturer_->TestWithoutCameraFormats();
330
331  FakeConstraints constraints;
332  double requested_aspect_ratio = 640.0 / 360;
333  constraints.AddMandatory(MediaConstraintsInterface::kMinWidth, 640);
334  constraints.AddMandatory(MediaConstraintsInterface::kMinAspectRatio,
335                           requested_aspect_ratio);
336
337  CreateVideoSource(&constraints);
338  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
339                 kMaxWaitMs);
340  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
341  double aspect_ratio = static_cast<double>(format->width) / format->height;
342  EXPECT_LE(requested_aspect_ratio, aspect_ratio);
343}
344
345// Test that the source state transitions to kEnded if an unknown mandatory
346// constraint is found.
347TEST_F(VideoSourceTest, InvalidMandatoryConstraint) {
348  FakeConstraints constraints;
349  constraints.AddMandatory("weird key", 640);
350
351  CreateVideoSource(&constraints);
352  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
353                 kMaxWaitMs);
354}
355
356// Test that the source ignores an unknown optional constraint.
357TEST_F(VideoSourceTest, InvalidOptionalConstraint) {
358  FakeConstraints constraints;
359  constraints.AddOptional("weird key", 640);
360
361  CreateVideoSource(&constraints);
362  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
363                 kMaxWaitMs);
364}
365
366TEST_F(VideoSourceTest, SetValidOptionValues) {
367  FakeConstraints constraints;
368  constraints.AddMandatory(MediaConstraintsInterface::kNoiseReduction, "false");
369  constraints.AddMandatory(
370      MediaConstraintsInterface::kTemporalLayeredScreencast, "false");
371  constraints.AddOptional(
372      MediaConstraintsInterface::kLeakyBucket, "true");
373  constraints.AddOptional(
374      MediaConstraintsInterface::kCpuOveruseDetection, "true");
375
376  CreateVideoSource(&constraints);
377
378  bool value = true;
379  EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
380  EXPECT_FALSE(value);
381  EXPECT_TRUE(source_->options()->
382      video_temporal_layer_screencast.Get(&value));
383  EXPECT_FALSE(value);
384  EXPECT_TRUE(source_->options()->video_leaky_bucket.Get(&value));
385  EXPECT_TRUE(value);
386  EXPECT_TRUE(source_->options()->
387      cpu_overuse_detection.GetWithDefaultIfUnset(false));
388}
389
390TEST_F(VideoSourceTest, OptionNotSet) {
391  FakeConstraints constraints;
392  CreateVideoSource(&constraints);
393  bool value;
394  EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
395  EXPECT_FALSE(source_->options()->cpu_overuse_detection.Get(&value));
396}
397
398TEST_F(VideoSourceTest, MandatoryOptionOverridesOptional) {
399  FakeConstraints constraints;
400  constraints.AddMandatory(
401      MediaConstraintsInterface::kNoiseReduction, true);
402  constraints.AddOptional(
403      MediaConstraintsInterface::kNoiseReduction, false);
404
405  CreateVideoSource(&constraints);
406
407  bool value = false;
408  EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
409  EXPECT_TRUE(value);
410  EXPECT_FALSE(source_->options()->video_leaky_bucket.Get(&value));
411}
412
413TEST_F(VideoSourceTest, InvalidOptionKeyOptional) {
414  FakeConstraints constraints;
415  constraints.AddOptional(
416      MediaConstraintsInterface::kNoiseReduction, false);
417  constraints.AddOptional("invalidKey", false);
418
419  CreateVideoSource(&constraints);
420
421  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
422      kMaxWaitMs);
423  bool value = true;
424  EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
425  EXPECT_FALSE(value);
426}
427
428TEST_F(VideoSourceTest, InvalidOptionKeyMandatory) {
429  FakeConstraints constraints;
430  constraints.AddMandatory(
431      MediaConstraintsInterface::kNoiseReduction, false);
432  constraints.AddMandatory("invalidKey", false);
433
434  CreateVideoSource(&constraints);
435
436  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
437      kMaxWaitMs);
438  bool value;
439  EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
440}
441
442TEST_F(VideoSourceTest, InvalidOptionValueOptional) {
443  FakeConstraints constraints;
444  constraints.AddOptional(
445      MediaConstraintsInterface::kNoiseReduction, "true");
446  constraints.AddOptional(
447      MediaConstraintsInterface::kLeakyBucket, "not boolean");
448
449  CreateVideoSource(&constraints);
450
451  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
452      kMaxWaitMs);
453  bool value = false;
454  EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
455  EXPECT_TRUE(value);
456  EXPECT_FALSE(source_->options()->video_leaky_bucket.Get(&value));
457}
458
459TEST_F(VideoSourceTest, InvalidOptionValueMandatory) {
460  FakeConstraints constraints;
461  // Optional constraints should be ignored if the mandatory constraints fail.
462  constraints.AddOptional(
463      MediaConstraintsInterface::kNoiseReduction, "false");
464  // Values are case-sensitive and must be all lower-case.
465  constraints.AddMandatory(
466      MediaConstraintsInterface::kLeakyBucket, "True");
467
468  CreateVideoSource(&constraints);
469
470  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
471      kMaxWaitMs);
472  bool value;
473  EXPECT_FALSE(source_->options()->video_noise_reduction.Get(&value));
474}
475
476TEST_F(VideoSourceTest, MixedOptionsAndConstraints) {
477  FakeConstraints constraints;
478  constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 352);
479  constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 288);
480  constraints.AddOptional(MediaConstraintsInterface::kMaxFrameRate, 5);
481
482  constraints.AddMandatory(
483      MediaConstraintsInterface::kNoiseReduction, false);
484  constraints.AddOptional(
485      MediaConstraintsInterface::kNoiseReduction, true);
486
487  CreateVideoSource(&constraints);
488  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
489                 kMaxWaitMs);
490  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
491  ASSERT_TRUE(format != NULL);
492  EXPECT_EQ(352, format->width);
493  EXPECT_EQ(288, format->height);
494  EXPECT_EQ(5, format->framerate());
495
496  bool value = true;
497  EXPECT_TRUE(source_->options()->video_noise_reduction.Get(&value));
498  EXPECT_FALSE(value);
499  EXPECT_FALSE(source_->options()->video_leaky_bucket.Get(&value));
500}
501
502// Tests that the source starts video with the default resolution for
503// screencast if no constraint is set.
504TEST_F(VideoSourceTest, ScreencastResolutionNoConstraint) {
505  capturer_->TestWithoutCameraFormats();
506  capturer_->SetScreencast(true);
507
508  CreateVideoSource();
509  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
510                 kMaxWaitMs);
511  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
512  ASSERT_TRUE(format != NULL);
513  EXPECT_EQ(640, format->width);
514  EXPECT_EQ(480, format->height);
515  EXPECT_EQ(30, format->framerate());
516}
517
518// Tests that the source starts video with the max width and height set by
519// constraints for screencast.
520TEST_F(VideoSourceTest, ScreencastResolutionWithConstraint) {
521  FakeConstraints constraints;
522  constraints.AddMandatory(MediaConstraintsInterface::kMaxWidth, 480);
523  constraints.AddMandatory(MediaConstraintsInterface::kMaxHeight, 270);
524
525  capturer_->TestWithoutCameraFormats();
526  capturer_->SetScreencast(true);
527
528  CreateVideoSource(&constraints);
529  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
530                 kMaxWaitMs);
531  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
532  ASSERT_TRUE(format != NULL);
533  EXPECT_EQ(480, format->width);
534  EXPECT_EQ(270, format->height);
535  EXPECT_EQ(30, format->framerate());
536}
537
538TEST_F(VideoSourceTest, MandatorySubOneFpsConstraints) {
539  FakeConstraints constraints;
540  constraints.AddMandatory(MediaConstraintsInterface::kMaxFrameRate, 0.5);
541
542  CreateVideoSource(&constraints);
543  EXPECT_EQ_WAIT(MediaSourceInterface::kEnded, state_observer_->state(),
544                 kMaxWaitMs);
545  ASSERT_TRUE(capturer_->GetCaptureFormat() == NULL);
546}
547
548TEST_F(VideoSourceTest, OptionalSubOneFpsConstraints) {
549  FakeConstraints constraints;
550  constraints.AddOptional(MediaConstraintsInterface::kMaxFrameRate, 0.5);
551
552  CreateVideoSource(&constraints);
553  EXPECT_EQ_WAIT(MediaSourceInterface::kLive, state_observer_->state(),
554                 kMaxWaitMs);
555  const cricket::VideoFormat* format = capturer_->GetCaptureFormat();
556  ASSERT_TRUE(format != NULL);
557  EXPECT_EQ(1, format->framerate());
558}
559
560