1// Copyright 2014 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#include <string>
6#include <vector>
7
8#include "base/bind.h"
9#include "base/message_loop/message_loop.h"
10#include "base/run_loop.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/strings/utf_string_conversions.h"
13#include "content/child/child_process.h"
14#include "content/renderer/media/media_stream_video_source.h"
15#include "content/renderer/media/media_stream_video_track.h"
16#include "content/renderer/media/mock_media_constraint_factory.h"
17#include "content/renderer/media/mock_media_stream_video_sink.h"
18#include "content/renderer/media/mock_media_stream_video_source.h"
19#include "media/base/video_frame.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "third_party/WebKit/public/web/WebHeap.h"
22
23using ::testing::_;
24using ::testing::DoAll;
25using ::testing::SaveArg;
26
27namespace content {
28
29ACTION_P(RunClosure, closure) {
30  closure.Run();
31}
32
33class MediaStreamVideoSourceTest
34    : public ::testing::Test {
35 public:
36  MediaStreamVideoSourceTest()
37      : child_process_(new ChildProcess()),
38        number_of_successful_constraints_applied_(0),
39        number_of_failed_constraints_applied_(0),
40        result_(MEDIA_DEVICE_OK),
41        result_name_(""),
42        mock_source_(new MockMediaStreamVideoSource(true)) {
43    media::VideoCaptureFormats formats;
44    formats.push_back(media::VideoCaptureFormat(
45        gfx::Size(1280, 720), 30, media::PIXEL_FORMAT_I420));
46    formats.push_back(media::VideoCaptureFormat(
47        gfx::Size(640, 480), 30, media::PIXEL_FORMAT_I420));
48    formats.push_back(media::VideoCaptureFormat(
49        gfx::Size(352, 288), 30, media::PIXEL_FORMAT_I420));
50    formats.push_back(media::VideoCaptureFormat(
51        gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420));
52    mock_source_->SetSupportedFormats(formats);
53    webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
54                              blink::WebMediaStreamSource::TypeVideo,
55                              base::UTF8ToUTF16("dummy_source_name"));
56    webkit_source_.setExtraData(mock_source_);
57  }
58
59  virtual void TearDown() {
60    webkit_source_.reset();
61    blink::WebHeap::collectAllGarbageForTesting();
62  }
63
64 protected:
65  // Create a track that's associated with |webkit_source_|.
66  blink::WebMediaStreamTrack CreateTrack(
67      const std::string& id,
68      const blink::WebMediaConstraints& constraints) {
69    bool enabled = true;
70    return MediaStreamVideoTrack::CreateVideoTrack(
71        mock_source_, constraints,
72        base::Bind(
73            &MediaStreamVideoSourceTest::OnConstraintsApplied,
74            base::Unretained(this)),
75        enabled);
76  }
77
78  blink::WebMediaStreamTrack CreateTrackAndStartSource(
79      const blink::WebMediaConstraints& constraints,
80      int expected_width,
81      int expected_height,
82      int expected_frame_rate) {
83    blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
84
85    mock_source_->CompleteGetSupportedFormats();
86    const media::VideoCaptureFormat& format = mock_source()->start_format();
87    EXPECT_EQ(expected_width, format.frame_size.width());
88    EXPECT_EQ(expected_height, format.frame_size.height());
89    EXPECT_EQ(expected_frame_rate, format.frame_rate);
90
91    EXPECT_EQ(0, NumberOfSuccessConstraintsCallbacks());
92    mock_source_->StartMockedSource();
93    // Once the source has started successfully we expect that the
94    // ConstraintsCallback in MediaStreamSource::AddTrack completes.
95    EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
96    return track;
97  }
98
99  int NumberOfSuccessConstraintsCallbacks() const {
100    return number_of_successful_constraints_applied_;
101  }
102
103  int NumberOfFailedConstraintsCallbacks() const {
104    return number_of_failed_constraints_applied_;
105  }
106
107  content::MediaStreamRequestResult error_type() const { return result_; }
108  blink::WebString error_name() const { return result_name_; }
109
110  MockMediaStreamVideoSource* mock_source() { return mock_source_; }
111
112  // Test that the source crops/scales to the requested width and
113  // height even though the camera delivers a larger frame.
114  void TestSourceCropFrame(int capture_width,
115                           int capture_height,
116                           const blink::WebMediaConstraints& constraints,
117                           int expected_width,
118                           int expected_height) {
119    // Expect the source to start capture with the supported resolution.
120    blink::WebMediaStreamTrack track =
121        CreateTrackAndStartSource(constraints, capture_width, capture_height,
122                                  30);
123
124    MockMediaStreamVideoSink sink;
125    MediaStreamVideoSink::AddToVideoTrack(
126        &sink, sink.GetDeliverFrameCB(), track);
127    DeliverVideoFrameAndWaitForRenderer(capture_width, capture_height, &sink);
128    EXPECT_EQ(1, sink.number_of_frames());
129
130    // Expect the delivered frame to be cropped.
131    EXPECT_EQ(expected_height, sink.frame_size().height());
132    EXPECT_EQ(expected_width, sink.frame_size().width());
133    MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
134  }
135
136  void DeliverVideoFrameAndWaitForRenderer(int width, int height,
137                                           MockMediaStreamVideoSink* sink) {
138    base::RunLoop run_loop;
139    base::Closure quit_closure = run_loop.QuitClosure();
140    EXPECT_CALL(*sink, OnVideoFrame()).WillOnce(
141        RunClosure(quit_closure));
142    scoped_refptr<media::VideoFrame> frame =
143              media::VideoFrame::CreateBlackFrame(gfx::Size(width, height));
144    mock_source()->DeliverVideoFrame(frame);
145    run_loop.Run();
146  }
147
148  void DeliverVideoFrameAndWaitForTwoRenderers(
149      int width,
150      int height,
151      MockMediaStreamVideoSink* sink1,
152      MockMediaStreamVideoSink* sink2) {
153    base::RunLoop run_loop;
154    base::Closure quit_closure = run_loop.QuitClosure();
155    EXPECT_CALL(*sink1, OnVideoFrame());
156    EXPECT_CALL(*sink2, OnVideoFrame()).WillOnce(
157        RunClosure(quit_closure));
158    scoped_refptr<media::VideoFrame> frame =
159        media::VideoFrame::CreateBlackFrame(gfx::Size(width, height));
160    mock_source()->DeliverVideoFrame(frame);
161    run_loop.Run();
162  }
163
164  void TestTwoTracksWithDifferentConstraints(
165      const blink::WebMediaConstraints& constraints1,
166      const blink::WebMediaConstraints& constraints2,
167      int capture_width,
168      int capture_height,
169      int expected_width1,
170      int expected_height1,
171      int expected_width2,
172      int expected_height2) {
173    blink::WebMediaStreamTrack track1 =
174        CreateTrackAndStartSource(constraints1, capture_width, capture_height,
175                                  MediaStreamVideoSource::kDefaultFrameRate);
176
177    blink::WebMediaStreamTrack track2 =
178        CreateTrack("dummy", constraints2);
179
180    MockMediaStreamVideoSink sink1;
181    MediaStreamVideoSink::AddToVideoTrack(&sink1, sink1.GetDeliverFrameCB(),
182                                          track1);
183    EXPECT_EQ(0, sink1.number_of_frames());
184
185    MockMediaStreamVideoSink sink2;
186    MediaStreamVideoSink::AddToVideoTrack(&sink2, sink2.GetDeliverFrameCB(),
187                                          track2);
188    EXPECT_EQ(0, sink2.number_of_frames());
189
190    DeliverVideoFrameAndWaitForTwoRenderers(capture_width,
191                                            capture_height,
192                                            &sink1,
193                                            &sink2);
194
195    EXPECT_EQ(1, sink1.number_of_frames());
196    EXPECT_EQ(expected_width1, sink1.frame_size().width());
197    EXPECT_EQ(expected_height1, sink1.frame_size().height());
198
199    EXPECT_EQ(1, sink2.number_of_frames());
200    EXPECT_EQ(expected_width2, sink2.frame_size().width());
201    EXPECT_EQ(expected_height2, sink2.frame_size().height());
202
203    MediaStreamVideoSink::RemoveFromVideoTrack(&sink1, track1);
204    MediaStreamVideoSink::RemoveFromVideoTrack(&sink2, track2);
205  }
206
207  void SetSourceSupportedFormats(const media::VideoCaptureFormats& formats) {
208    mock_source_->SetSupportedFormats(formats);
209  }
210
211  void ReleaseTrackAndSourceOnAddTrackCallback(
212      const blink::WebMediaStreamTrack& track_to_release) {
213    track_to_release_ = track_to_release;
214  }
215
216 private:
217  void OnConstraintsApplied(MediaStreamSource* source,
218                            MediaStreamRequestResult result,
219                            const blink::WebString& result_name) {
220    ASSERT_EQ(source, webkit_source_.extraData());
221
222    if (result == MEDIA_DEVICE_OK) {
223      ++number_of_successful_constraints_applied_;
224    } else {
225      result_ = result;
226      result_name_ = result_name;
227      ++number_of_failed_constraints_applied_;
228    }
229
230    if (!track_to_release_.isNull()) {
231      mock_source_ = NULL;
232      webkit_source_.reset();
233      track_to_release_.reset();
234    }
235  }
236  base::MessageLoopForUI message_loop_;
237  scoped_ptr<ChildProcess> child_process_;
238  blink::WebMediaStreamTrack track_to_release_;
239  int number_of_successful_constraints_applied_;
240  int number_of_failed_constraints_applied_;
241  content::MediaStreamRequestResult result_;
242  blink::WebString result_name_;
243  blink::WebMediaStreamSource webkit_source_;
244  // |mock_source_| is owned by |webkit_source_|.
245  MockMediaStreamVideoSource* mock_source_;
246};
247
248TEST_F(MediaStreamVideoSourceTest, AddTrackAndStartSource) {
249  blink::WebMediaConstraints constraints;
250  constraints.initialize();
251  blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
252  mock_source()->CompleteGetSupportedFormats();
253  mock_source()->StartMockedSource();
254  EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
255}
256
257TEST_F(MediaStreamVideoSourceTest, AddTwoTracksBeforeSourceStarts) {
258  blink::WebMediaConstraints constraints;
259  constraints.initialize();
260  blink::WebMediaStreamTrack track1 = CreateTrack("123", constraints);
261  mock_source()->CompleteGetSupportedFormats();
262  blink::WebMediaStreamTrack track2 = CreateTrack("123", constraints);
263  EXPECT_EQ(0, NumberOfSuccessConstraintsCallbacks());
264  mock_source()->StartMockedSource();
265  EXPECT_EQ(2, NumberOfSuccessConstraintsCallbacks());
266}
267
268TEST_F(MediaStreamVideoSourceTest, AddTrackAfterSourceStarts) {
269  blink::WebMediaConstraints constraints;
270  constraints.initialize();
271  blink::WebMediaStreamTrack track1 = CreateTrack("123", constraints);
272  mock_source()->CompleteGetSupportedFormats();
273  mock_source()->StartMockedSource();
274  EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
275  blink::WebMediaStreamTrack track2 = CreateTrack("123", constraints);
276  EXPECT_EQ(2, NumberOfSuccessConstraintsCallbacks());
277}
278
279TEST_F(MediaStreamVideoSourceTest, AddTrackAndFailToStartSource) {
280  blink::WebMediaConstraints constraints;
281  constraints.initialize();
282  blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
283  mock_source()->CompleteGetSupportedFormats();
284  mock_source()->FailToStartMockedSource();
285  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
286}
287
288TEST_F(MediaStreamVideoSourceTest, AddTwoTracksBeforeGetSupportedFormats) {
289  blink::WebMediaConstraints constraints;
290  constraints.initialize();
291  blink::WebMediaStreamTrack track1 = CreateTrack("123", constraints);
292  blink::WebMediaStreamTrack track2 = CreateTrack("123", constraints);
293  mock_source()->CompleteGetSupportedFormats();
294  mock_source()->StartMockedSource();
295  EXPECT_EQ(2, NumberOfSuccessConstraintsCallbacks());
296}
297
298// Test that the capture output is CIF if we set max constraints to CIF.
299// and the capture device support CIF.
300TEST_F(MediaStreamVideoSourceTest, MandatoryConstraintCif5Fps) {
301  MockMediaConstraintFactory factory;
302  factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 352);
303  factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 288);
304  factory.AddMandatory(MediaStreamVideoSource::kMaxFrameRate, 5);
305
306  CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 352, 288, 5);
307}
308
309// Test that the capture output is 720P if the camera support it and the
310// optional constraint is set to 720P.
311TEST_F(MediaStreamVideoSourceTest, MandatoryMinVgaOptional720P) {
312  MockMediaConstraintFactory factory;
313  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 640);
314  factory.AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
315  factory.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
316  factory.AddOptional(MediaStreamVideoSource::kMinAspectRatio,
317                      1280.0 / 720);
318
319  CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 1280, 720, 30);
320}
321
322// Test that the capture output have aspect ratio 4:3 if a mandatory constraint
323// require it even if an optional constraint request a higher resolution
324// that don't have this aspect ratio.
325TEST_F(MediaStreamVideoSourceTest, MandatoryAspectRatio4To3) {
326  MockMediaConstraintFactory factory;
327  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 640);
328  factory.AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
329  factory.AddMandatory(MediaStreamVideoSource::kMaxAspectRatio,
330                       640.0 / 480);
331  factory.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
332
333  TestSourceCropFrame(1280, 720,
334                      factory.CreateWebMediaConstraints(), 960, 720);
335}
336
337// Test that AddTrack succeeds if the mandatory min aspect ratio it set to 2.
338TEST_F(MediaStreamVideoSourceTest, MandatoryAspectRatio2) {
339  MockMediaConstraintFactory factory;
340  factory.AddMandatory(MediaStreamVideoSource::kMinAspectRatio, 2);
341
342  TestSourceCropFrame(MediaStreamVideoSource::kDefaultWidth,
343                      MediaStreamVideoSource::kDefaultHeight,
344                      factory.CreateWebMediaConstraints(), 640, 320);
345}
346
347TEST_F(MediaStreamVideoSourceTest, MinAspectRatioLargerThanMaxAspectRatio) {
348  MockMediaConstraintFactory factory;
349  factory.AddMandatory(MediaStreamVideoSource::kMinAspectRatio, 2);
350  factory.AddMandatory(MediaStreamVideoSource::kMaxAspectRatio, 1);
351  blink::WebMediaStreamTrack track = CreateTrack(
352      "123", factory.CreateWebMediaConstraints());
353  mock_source()->CompleteGetSupportedFormats();
354  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
355}
356
357TEST_F(MediaStreamVideoSourceTest, MaxAspectRatioZero) {
358  MockMediaConstraintFactory factory;
359  factory.AddOptional(MediaStreamVideoSource::kMaxAspectRatio, 0);
360  blink::WebMediaStreamTrack track = CreateTrack(
361      "123", factory.CreateWebMediaConstraints());
362  mock_source()->CompleteGetSupportedFormats();
363  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
364}
365
366TEST_F(MediaStreamVideoSourceTest, MinWidthLargerThanMaxWidth) {
367  MockMediaConstraintFactory factory;
368  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 640);
369  factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 320);
370  blink::WebMediaStreamTrack track = CreateTrack(
371      "123", factory.CreateWebMediaConstraints());
372  mock_source()->CompleteGetSupportedFormats();
373  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
374}
375
376TEST_F(MediaStreamVideoSourceTest, MinHeightLargerThanMaxHeight) {
377  MockMediaConstraintFactory factory;
378  factory.AddMandatory(MediaStreamVideoSource::kMinHeight, 480);
379  factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 360);
380  blink::WebMediaStreamTrack track = CreateTrack(
381      "123", factory.CreateWebMediaConstraints());
382  mock_source()->CompleteGetSupportedFormats();
383  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
384}
385
386TEST_F(MediaStreamVideoSourceTest, MinFrameRateLargerThanMaxFrameRate) {
387  MockMediaConstraintFactory factory;
388  factory.AddMandatory(MediaStreamVideoSource::kMinFrameRate, 25);
389  factory.AddMandatory(MediaStreamVideoSource::kMaxFrameRate, 15);
390  blink::WebMediaStreamTrack track = CreateTrack(
391      "123", factory.CreateWebMediaConstraints());
392  mock_source()->CompleteGetSupportedFormats();
393  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
394}
395
396// Test that its safe to release the last reference of a blink track and the
397// source during the callback if adding a track succeeds.
398TEST_F(MediaStreamVideoSourceTest, ReleaseTrackAndSourceOnSuccessCallBack) {
399  MockMediaConstraintFactory factory;
400  {
401    blink::WebMediaStreamTrack track =
402        CreateTrack("123", factory.CreateWebMediaConstraints());
403    ReleaseTrackAndSourceOnAddTrackCallback(track);
404  }
405  mock_source()->CompleteGetSupportedFormats();
406  mock_source()->StartMockedSource();
407  EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
408}
409
410// Test that its safe to release the last reference of a blink track and the
411// source during the callback if adding a track fails.
412TEST_F(MediaStreamVideoSourceTest, ReleaseTrackAndSourceOnFailureCallBack) {
413  MockMediaConstraintFactory factory;
414  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 99999);
415  {
416    blink::WebMediaStreamTrack track =
417        CreateTrack("123", factory.CreateWebMediaConstraints());
418    ReleaseTrackAndSourceOnAddTrackCallback(track);
419  }
420  mock_source()->CompleteGetSupportedFormats();
421  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
422}
423
424// Test that the source ignores an optional aspect ratio that is higher than
425// supported.
426TEST_F(MediaStreamVideoSourceTest, OptionalAspectRatioTooHigh) {
427  MockMediaConstraintFactory factory;
428  factory.AddOptional(MediaStreamVideoSource::kMinAspectRatio, 2);
429  blink::WebMediaStreamTrack track = CreateTrack(
430      "123", factory.CreateWebMediaConstraints());
431  mock_source()->CompleteGetSupportedFormats();
432
433  const media::VideoCaptureFormat& format = mock_source()->start_format();
434  double aspect_ratio =
435      static_cast<double>(format.frame_size.width()) /
436      format.frame_size.height();
437  EXPECT_LT(aspect_ratio, 2);
438}
439
440// Test that the source starts video with the default resolution if the
441// that is the only supported.
442TEST_F(MediaStreamVideoSourceTest, DefaultCapability) {
443  media::VideoCaptureFormats formats;
444  formats.push_back(media::VideoCaptureFormat(
445      gfx::Size(MediaStreamVideoSource::kDefaultWidth,
446                MediaStreamVideoSource::kDefaultHeight),
447      MediaStreamVideoSource::kDefaultFrameRate,
448      media::PIXEL_FORMAT_I420));
449  mock_source()->SetSupportedFormats(formats);
450
451  blink::WebMediaConstraints constraints;
452  constraints.initialize();
453  CreateTrackAndStartSource(constraints,
454                            MediaStreamVideoSource::kDefaultWidth,
455                            MediaStreamVideoSource::kDefaultHeight,
456                            30);
457}
458
459TEST_F(MediaStreamVideoSourceTest, InvalidMandatoryConstraint) {
460  MockMediaConstraintFactory factory;
461  factory.AddMandatory("weird key", 640);
462  blink::WebMediaStreamTrack track = CreateTrack(
463      "123", factory.CreateWebMediaConstraints());
464  mock_source()->CompleteGetSupportedFormats();
465  EXPECT_EQ(MEDIA_DEVICE_CONSTRAINT_NOT_SATISFIED, error_type());
466  EXPECT_EQ("weird key", error_name());
467  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
468}
469
470// Test that the source ignores an unknown optional constraint.
471TEST_F(MediaStreamVideoSourceTest, InvalidOptionalConstraint) {
472  MockMediaConstraintFactory factory;
473  factory.AddOptional("weird key", 640);
474
475  CreateTrackAndStartSource(factory.CreateWebMediaConstraints(),
476                            MediaStreamVideoSource::kDefaultWidth,
477                            MediaStreamVideoSource::kDefaultHeight,
478                            30);
479}
480
481// Tests that the source starts video with the max width and height set by
482// constraints for screencast.
483TEST_F(MediaStreamVideoSourceTest, ScreencastResolutionWithConstraint) {
484  media::VideoCaptureFormats formats;
485      formats.push_back(media::VideoCaptureFormat(
486          gfx::Size(480, 270), 30, media::PIXEL_FORMAT_I420));
487  mock_source()->SetSupportedFormats(formats);
488  MockMediaConstraintFactory factory;
489  factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 480);
490  factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 270);
491
492  blink::WebMediaStreamTrack track = CreateTrackAndStartSource(
493      factory.CreateWebMediaConstraints(), 480, 270, 30);
494  EXPECT_EQ(480, mock_source()->max_requested_height());
495  EXPECT_EQ(270, mock_source()->max_requested_width());
496}
497
498// Test that optional constraints are applied in order.
499TEST_F(MediaStreamVideoSourceTest, OptionalConstraints) {
500  MockMediaConstraintFactory factory;
501  // Min width of 2056 pixels can not be fulfilled.
502  factory.AddOptional(MediaStreamVideoSource::kMinWidth, 2056);
503  factory.AddOptional(MediaStreamVideoSource::kMinWidth, 641);
504  // Since min width is set to 641 pixels, max width 640 can not be fulfilled.
505  factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 640);
506  CreateTrackAndStartSource(factory.CreateWebMediaConstraints(), 1280, 720, 30);
507}
508
509// Test that the source crops to the requested max width and
510// height even though the camera delivers a larger frame.
511TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrameOptional640360) {
512  MockMediaConstraintFactory factory;
513  factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 640);
514  factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 360);
515  TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 640, 360);
516}
517
518TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrameMandatory640360) {
519  MockMediaConstraintFactory factory;
520  factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 640);
521  factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 360);
522  TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 640, 360);
523}
524
525TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrameMandatory732489) {
526  MockMediaConstraintFactory factory;
527  factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 732);
528  factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 489);
529  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 732);
530  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 489);
531  TestSourceCropFrame(1280, 720, factory.CreateWebMediaConstraints(), 732, 489);
532}
533
534// Test that the source crops to the requested max width and
535// height even though the requested frame has odd size.
536TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrame637359) {
537  MockMediaConstraintFactory factory;
538  factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 637);
539  factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 359);
540  TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 637, 359);
541}
542
543TEST_F(MediaStreamVideoSourceTest, DeliverCroppedVideoFrame320320) {
544  MockMediaConstraintFactory factory;
545  factory.AddMandatory(MediaStreamVideoSource::kMaxWidth, 320);
546  factory.AddMandatory(MediaStreamVideoSource::kMaxHeight, 320);
547  factory.AddMandatory(MediaStreamVideoSource::kMinHeight, 320);
548  factory.AddMandatory(MediaStreamVideoSource::kMinWidth, 320);
549  TestSourceCropFrame(640, 480, factory.CreateWebMediaConstraints(), 320, 320);
550}
551
552TEST_F(MediaStreamVideoSourceTest, DeliverSmallerSizeWhenTooLargeMax) {
553  MockMediaConstraintFactory factory;
554  factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 1920);
555  factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 1080);
556  factory.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
557  factory.AddOptional(MediaStreamVideoSource::kMinHeight, 720);
558  TestSourceCropFrame(1280, 720, factory.CreateWebMediaConstraints(),
559                      1280, 720);
560}
561
562TEST_F(MediaStreamVideoSourceTest, TwoTracksWithVGAAndWVGA) {
563  MockMediaConstraintFactory factory1;
564  factory1.AddOptional(MediaStreamVideoSource::kMaxWidth, 640);
565  factory1.AddOptional(MediaStreamVideoSource::kMaxHeight, 480);
566
567  MockMediaConstraintFactory factory2;
568  factory2.AddOptional(MediaStreamVideoSource::kMaxHeight, 360);
569
570  TestTwoTracksWithDifferentConstraints(factory1.CreateWebMediaConstraints(),
571                                        factory2.CreateWebMediaConstraints(),
572                                        640, 480,
573                                        640, 480,
574                                        640, 360);
575}
576
577TEST_F(MediaStreamVideoSourceTest, TwoTracksWith720AndWVGA) {
578  MockMediaConstraintFactory factory1;
579  factory1.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
580  factory1.AddOptional(MediaStreamVideoSource::kMinHeight, 720);
581
582
583  MockMediaConstraintFactory factory2;
584  factory2.AddMandatory(MediaStreamVideoSource::kMaxWidth, 640);
585  factory2.AddMandatory(MediaStreamVideoSource::kMaxHeight, 360);
586
587  TestTwoTracksWithDifferentConstraints(factory1.CreateWebMediaConstraints(),
588                                        factory2.CreateWebMediaConstraints(),
589                                        1280, 720,
590                                        1280, 720,
591                                        640, 360);
592}
593
594TEST_F(MediaStreamVideoSourceTest, TwoTracksWith720AndW700H700) {
595  MockMediaConstraintFactory factory1;
596  factory1.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
597  factory1.AddOptional(MediaStreamVideoSource::kMinHeight, 720);
598
599  MockMediaConstraintFactory factory2;
600  factory2.AddMandatory(MediaStreamVideoSource::kMaxWidth, 700);
601  factory2.AddMandatory(MediaStreamVideoSource::kMaxHeight, 700);
602
603  TestTwoTracksWithDifferentConstraints(factory1.CreateWebMediaConstraints(),
604                                        factory2.CreateWebMediaConstraints(),
605                                        1280, 720,
606                                        1280, 720,
607                                        700, 700);
608}
609
610TEST_F(MediaStreamVideoSourceTest, TwoTracksWith720AndMaxAspectRatio4To3) {
611  MockMediaConstraintFactory factory1;
612  factory1.AddOptional(MediaStreamVideoSource::kMinWidth, 1280);
613  factory1.AddOptional(MediaStreamVideoSource::kMinHeight, 720);
614
615  MockMediaConstraintFactory factory2;
616  factory2.AddMandatory(MediaStreamVideoSource::kMaxAspectRatio, 640.0 / 480);
617
618  TestTwoTracksWithDifferentConstraints(factory1.CreateWebMediaConstraints(),
619                                        factory2.CreateWebMediaConstraints(),
620                                        1280, 720,
621                                        1280, 720,
622                                        960, 720);
623}
624
625TEST_F(MediaStreamVideoSourceTest, TwoTracksWithVgaAndMinAspectRatio) {
626  MockMediaConstraintFactory factory1;
627  factory1.AddOptional(MediaStreamVideoSource::kMaxWidth, 640);
628  factory1.AddOptional(MediaStreamVideoSource::kMaxHeight, 480);
629
630  MockMediaConstraintFactory factory2;
631  factory2.AddMandatory(MediaStreamVideoSource::kMinAspectRatio, 640.0 / 360);
632
633  TestTwoTracksWithDifferentConstraints(factory1.CreateWebMediaConstraints(),
634                                        factory2.CreateWebMediaConstraints(),
635                                        640, 480,
636                                        640, 480,
637                                        640, 360);
638}
639
640TEST_F(MediaStreamVideoSourceTest,
641       TwoTracksWithSecondTrackFrameRateHigherThanFirst) {
642  MockMediaConstraintFactory factory1;
643  factory1.AddMandatory(MediaStreamVideoSource::kMinFrameRate, 15);
644  factory1.AddMandatory(MediaStreamVideoSource::kMaxFrameRate, 15);
645
646  blink::WebMediaStreamTrack track1 =
647      CreateTrackAndStartSource(factory1.CreateWebMediaConstraints(),
648                                MediaStreamVideoSource::kDefaultWidth,
649                                MediaStreamVideoSource::kDefaultHeight,
650                                15);
651
652  MockMediaConstraintFactory factory2;
653  factory2.AddMandatory(MediaStreamVideoSource::kMinFrameRate, 30);
654  blink::WebMediaStreamTrack track2 = CreateTrack(
655      "123", factory2.CreateWebMediaConstraints());
656  EXPECT_EQ(1, NumberOfFailedConstraintsCallbacks());
657}
658
659// Test that a source can change the frame resolution on the fly and that
660// tracks sinks get the new frame size unless constraints force the frame to be
661// cropped.
662TEST_F(MediaStreamVideoSourceTest, SourceChangeFrameSize) {
663  MockMediaConstraintFactory factory;
664  factory.AddOptional(MediaStreamVideoSource::kMaxWidth, 800);
665  factory.AddOptional(MediaStreamVideoSource::kMaxHeight, 700);
666
667  // Expect the source to start capture with the supported resolution.
668  blink::WebMediaStreamTrack track =
669      CreateTrackAndStartSource(factory.CreateWebMediaConstraints(),
670                                640, 480, 30);
671
672  MockMediaStreamVideoSink sink;
673  MediaStreamVideoSink::AddToVideoTrack(
674      &sink, sink.GetDeliverFrameCB(), track);
675  EXPECT_EQ(0, sink.number_of_frames());
676  DeliverVideoFrameAndWaitForRenderer(320, 240, &sink);
677  EXPECT_EQ(1, sink.number_of_frames());
678  // Expect the delivered frame to be passed unchanged since its smaller than
679  // max requested.
680  EXPECT_EQ(320, sink.frame_size().width());
681  EXPECT_EQ(240, sink.frame_size().height());
682
683  DeliverVideoFrameAndWaitForRenderer(640, 480, &sink);
684  EXPECT_EQ(2, sink.number_of_frames());
685  // Expect the delivered frame to be passed unchanged since its smaller than
686  // max requested.
687  EXPECT_EQ(640, sink.frame_size().width());
688  EXPECT_EQ(480, sink.frame_size().height());
689
690  DeliverVideoFrameAndWaitForRenderer(1280, 720, &sink);
691
692  EXPECT_EQ(3, sink.number_of_frames());
693  // Expect a frame to be cropped since its larger than max requested.
694  EXPECT_EQ(800, sink.frame_size().width());
695  EXPECT_EQ(700, sink.frame_size().height());
696
697  MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
698}
699
700TEST_F(MediaStreamVideoSourceTest, IsConstraintSupported) {
701  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
702          MediaStreamVideoSource::kMaxFrameRate));
703  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
704        MediaStreamVideoSource::kMinFrameRate));
705  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
706      MediaStreamVideoSource::kMaxWidth));
707  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
708        MediaStreamVideoSource::kMinWidth));
709  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
710        MediaStreamVideoSource::kMaxHeight));
711  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
712      MediaStreamVideoSource::kMinHeight));
713  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
714        MediaStreamVideoSource::kMaxAspectRatio));
715  EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported(
716      MediaStreamVideoSource::kMinAspectRatio));
717
718  EXPECT_FALSE(MediaStreamVideoSource::IsConstraintSupported(
719      "something unsupported"));
720}
721
722// Test that the constraint negotiation can handle 0.0 fps as frame rate.
723TEST_F(MediaStreamVideoSourceTest, Use0FpsSupportedFormat) {
724  media::VideoCaptureFormats formats;
725  formats.push_back(media::VideoCaptureFormat(
726      gfx::Size(640, 480), 0.0f, media::PIXEL_FORMAT_I420));
727  formats.push_back(media::VideoCaptureFormat(
728      gfx::Size(320, 240), 0.0f, media::PIXEL_FORMAT_I420));
729  mock_source()->SetSupportedFormats(formats);
730
731  blink::WebMediaConstraints constraints;
732  constraints.initialize();
733  blink::WebMediaStreamTrack track = CreateTrack("123", constraints);
734  mock_source()->CompleteGetSupportedFormats();
735  mock_source()->StartMockedSource();
736  EXPECT_EQ(1, NumberOfSuccessConstraintsCallbacks());
737
738  MockMediaStreamVideoSink sink;
739  MediaStreamVideoSink::AddToVideoTrack(
740      &sink, sink.GetDeliverFrameCB(), track);
741  EXPECT_EQ(0, sink.number_of_frames());
742  DeliverVideoFrameAndWaitForRenderer(320, 240, &sink);
743  EXPECT_EQ(1, sink.number_of_frames());
744  // Expect the delivered frame to be passed unchanged since its smaller than
745  // max requested.
746  EXPECT_EQ(320, sink.frame_size().width());
747  EXPECT_EQ(240, sink.frame_size().height());
748  MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
749}
750
751// Test that a source producing no frames change the source readyState to muted.
752// that in a reasonable time frame the muted state turns to false.
753TEST_F(MediaStreamVideoSourceTest, MutedSource) {
754  // Setup the source for support a frame rate of 2000fps in order to test
755  // the muted event faster. This is since the frame monitoring uses
756  // PostDelayedTask that is dependent on the source frame rate.
757  media::VideoCaptureFormats formats;
758      formats.push_back(media::VideoCaptureFormat(
759          gfx::Size(640, 480), 2000, media::PIXEL_FORMAT_I420));
760  SetSourceSupportedFormats(formats);
761
762  MockMediaConstraintFactory factory;
763  blink::WebMediaStreamTrack track =
764      CreateTrackAndStartSource(factory.CreateWebMediaConstraints(),
765                                640, 480, 2000);
766  MockMediaStreamVideoSink sink;
767  MediaStreamVideoSink::AddToVideoTrack(&sink, sink.GetDeliverFrameCB(), track);
768  EXPECT_EQ(track.source().readyState(),
769            blink::WebMediaStreamSource::ReadyStateLive);
770
771  base::RunLoop run_loop;
772  base::Closure quit_closure = run_loop.QuitClosure();
773  bool muted_state = false;
774  EXPECT_CALL(*mock_source(), DoSetMutedState(_))
775      .WillOnce(DoAll(SaveArg<0>(&muted_state), RunClosure(quit_closure)));
776  run_loop.Run();
777  EXPECT_EQ(muted_state, true);
778
779  EXPECT_EQ(track.source().readyState(),
780            blink::WebMediaStreamSource::ReadyStateMuted);
781
782  base::RunLoop run_loop2;
783  base::Closure quit_closure2 = run_loop2.QuitClosure();
784  EXPECT_CALL(*mock_source(), DoSetMutedState(_))
785      .WillOnce(DoAll(SaveArg<0>(&muted_state), RunClosure(quit_closure2)));
786  DeliverVideoFrameAndWaitForRenderer(640, 480, &sink);
787  run_loop2.Run();
788
789  EXPECT_EQ(muted_state, false);
790  EXPECT_EQ(track.source().readyState(),
791            blink::WebMediaStreamSource::ReadyStateLive);
792
793  MediaStreamVideoSink::RemoveFromVideoTrack(&sink, track);
794}
795
796}  // namespace content
797