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