| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/optional.h" |
| #include "media/base/limits.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/platform/web_media_constraints.h" |
| #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h" |
| #include "third_party/blink/renderer/modules/mediastream/mock_constraint_factory.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| const char kDeviceID1[] = "fake_device_1"; |
| const char kDeviceID2[] = "fake_device_2"; |
| const char kDeviceID3[] = "fake_device_3"; |
| const char kDeviceID4[] = "fake_device_4"; |
| const char kDeviceID5[] = "fake_device_5"; |
| |
| const char kGroupID1[] = "fake_group_1"; |
| const char kGroupID2[] = "fake_group_2"; |
| const char kGroupID3[] = "fake_group_3"; |
| const char kGroupID4[] = "fake_group_4"; |
| const char kGroupID5[] = "fake_group_5"; |
| |
| void CheckTrackAdapterSettingsEqualsResolution( |
| const VideoCaptureSettings& settings) { |
| EXPECT_FALSE(settings.track_adapter_settings().target_size()); |
| EXPECT_EQ(1.0 / settings.Format().frame_size.height(), |
| settings.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(settings.Format().frame_size.width(), |
| settings.track_adapter_settings().max_aspect_ratio()); |
| } |
| |
| void CheckTrackAdapterSettingsEqualsFrameRate( |
| const VideoCaptureSettings& settings, |
| double value = 0.0) { |
| if (value >= settings.FrameRate()) |
| value = 0.0; |
| EXPECT_EQ(value, settings.track_adapter_settings().max_frame_rate()); |
| } |
| |
| void CheckTrackAdapterSettingsEqualsFormat( |
| const VideoCaptureSettings& settings) { |
| CheckTrackAdapterSettingsEqualsResolution(settings); |
| CheckTrackAdapterSettingsEqualsFrameRate(settings); |
| } |
| |
| double AspectRatio(const media::VideoCaptureFormat& format) { |
| return static_cast<double>(format.frame_size.width()) / |
| static_cast<double>(format.frame_size.height()); |
| } |
| |
| VideoCaptureSettings SelectSettingsVideoDeviceCapture( |
| const VideoDeviceCaptureCapabilities& capabilities, |
| const WebMediaConstraints& constraints) { |
| return SelectSettingsVideoDeviceCapture( |
| capabilities, constraints, MediaStreamVideoSource::kDefaultWidth, |
| MediaStreamVideoSource::kDefaultHeight, |
| MediaStreamVideoSource::kDefaultFrameRate); |
| } |
| |
| } // namespace |
| |
| class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test { |
| public: |
| void SetUp() override { |
| // Default device. It is default because it is the first in the enumeration. |
| VideoInputDeviceCapabilities device; |
| device.device_id = kDeviceID1; |
| device.group_id = kGroupID1; |
| device.facing_mode = media::MEDIA_VIDEO_FACING_NONE; |
| device.formats = { |
| media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f, |
| media::PIXEL_FORMAT_I420), |
| // This entry is is the closest to defaults. |
| media::VideoCaptureFormat(gfx::Size(500, 500), 40.0f, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(1000, 1000), 20.0f, |
| media::PIXEL_FORMAT_I420), |
| }; |
| capabilities_.device_capabilities.push_back(std::move(device)); |
| |
| // A low-resolution device. |
| device.device_id = kDeviceID2; |
| device.group_id = kGroupID2; |
| device.facing_mode = media::MEDIA_VIDEO_FACING_ENVIRONMENT; |
| device.formats = { |
| media::VideoCaptureFormat(gfx::Size(40, 30), 20.0f, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(320, 240), 30.0f, |
| media::PIXEL_FORMAT_I420), |
| // This format has defaults for all settings |
| media::VideoCaptureFormat( |
| gfx::Size(MediaStreamVideoSource::kDefaultWidth, |
| MediaStreamVideoSource::kDefaultHeight), |
| MediaStreamVideoSource::kDefaultFrameRate, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(800, 600), 20.0f, |
| media::PIXEL_FORMAT_I420), |
| }; |
| capabilities_.device_capabilities.push_back(std::move(device)); |
| |
| // A high-resolution device. |
| device.device_id = kDeviceID3; |
| device.group_id = kGroupID3; |
| device.facing_mode = media::MEDIA_VIDEO_FACING_USER; |
| device.formats = { |
| media::VideoCaptureFormat(gfx::Size(600, 400), 10.0f, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(640, 480), 10.0f, |
| media::PIXEL_FORMAT_I420), |
| // This format has default for all settings, except that the resolution |
| // is inverted. |
| media::VideoCaptureFormat( |
| gfx::Size(MediaStreamVideoSource::kDefaultHeight, |
| MediaStreamVideoSource::kDefaultWidth), |
| MediaStreamVideoSource::kDefaultFrameRate, |
| media::PIXEL_FORMAT_I420), |
| // This format has defaults for all settings |
| media::VideoCaptureFormat( |
| gfx::Size(MediaStreamVideoSource::kDefaultWidth, |
| MediaStreamVideoSource::kDefaultHeight), |
| MediaStreamVideoSource::kDefaultFrameRate, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(1280, 720), 60.0f, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(1920, 1080), 60.0f, |
| media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(2304, 1536), 10.0f, |
| media::PIXEL_FORMAT_I420), |
| }; |
| capabilities_.device_capabilities.push_back(std::move(device)); |
| |
| // A depth capture device. |
| device.device_id = kDeviceID4; |
| device.group_id = kGroupID4; |
| device.facing_mode = media::MEDIA_VIDEO_FACING_ENVIRONMENT; |
| device.formats = {media::VideoCaptureFormat(gfx::Size(640, 480), 30.0f, |
| media::PIXEL_FORMAT_Y16)}; |
| capabilities_.device_capabilities.push_back(std::move(device)); |
| |
| // A device that reports invalid frame rates. These devices exist and should |
| // be supported if no constraints are placed on the frame rate. |
| device.device_id = kDeviceID5; |
| device.group_id = kGroupID5; |
| device.facing_mode = media::MEDIA_VIDEO_FACING_NONE; |
| device.formats = { |
| media::VideoCaptureFormat( |
| gfx::Size(MediaStreamVideoSource::kDefaultWidth, |
| MediaStreamVideoSource::kDefaultHeight), |
| 0.0f, media::PIXEL_FORMAT_I420), |
| media::VideoCaptureFormat(gfx::Size(500, 500), 0.1f, |
| media::PIXEL_FORMAT_I420), |
| }; |
| capabilities_.device_capabilities.push_back(std::move(device)); |
| |
| capabilities_.noise_reduction_capabilities = { |
| base::Optional<bool>(), |
| base::Optional<bool>(true), |
| base::Optional<bool>(false), |
| }; |
| |
| default_device_ = &capabilities_.device_capabilities[0]; |
| low_res_device_ = &capabilities_.device_capabilities[1]; |
| high_res_device_ = &capabilities_.device_capabilities[2]; |
| invalid_frame_rate_device_ = &capabilities_.device_capabilities[4]; |
| default_closest_format_ = &default_device_->formats[1]; |
| low_res_closest_format_ = &low_res_device_->formats[2]; |
| high_res_closest_format_ = &high_res_device_->formats[3]; |
| high_res_highest_format_ = &high_res_device_->formats[6]; |
| } |
| |
| protected: |
| VideoCaptureSettings SelectSettings() { |
| WebMediaConstraints constraints = |
| constraint_factory_.CreateWebMediaConstraints(); |
| return SelectSettingsVideoDeviceCapture(capabilities_, constraints); |
| } |
| |
| VideoDeviceCaptureCapabilities capabilities_; |
| const VideoInputDeviceCapabilities* default_device_; |
| const VideoInputDeviceCapabilities* low_res_device_; |
| const VideoInputDeviceCapabilities* high_res_device_; |
| const VideoInputDeviceCapabilities* invalid_frame_rate_device_; |
| // Closest formats to the default settings. |
| const media::VideoCaptureFormat* default_closest_format_; |
| const media::VideoCaptureFormat* low_res_closest_format_; |
| const media::VideoCaptureFormat* high_res_closest_format_; |
| const media::VideoCaptureFormat* high_res_highest_format_; |
| |
| MockConstraintFactory constraint_factory_; |
| }; |
| |
| // The Unconstrained test checks the default selection criteria. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, Unconstrained) { |
| constraint_factory_.Reset(); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Should select the default device with closest-to-default settings. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| // Should select default settings for other constraints. |
| EXPECT_EQ(base::Optional<bool>(), result.noise_reduction()); |
| } |
| |
| // The "Overconstrained" tests verify that failure of any single required |
| // constraint results in failure to select a candidate. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnDeviceID) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().device_id.SetExact( |
| WebString::FromASCII("NONEXISTING")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().device_id.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnGroupID) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().group_id.SetExact( |
| WebString::FromASCII("NONEXISTING")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().group_id.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnFacingMode) { |
| constraint_factory_.Reset(); |
| // No device in |capabilities_| has facing mode equal to LEFT. |
| constraint_factory_.basic().facing_mode.SetExact( |
| WebString::FromASCII("left")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().facing_mode.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| OverconstrainedOnEmptyFacingMode) { |
| constraint_factory_.Reset(); |
| // Empty is not a valid facingMode value. |
| constraint_factory_.basic().facing_mode.SetExact(WebString::FromASCII("")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().facing_mode.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| OverconstrainedOnInvalidResizeMode) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().resize_mode.SetExact( |
| WebString::FromASCII("invalid")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().resize_mode.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| OverconstrainedOnEmptyResizeMode) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().resize_mode.SetExact(WebString::FromASCII("")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().resize_mode.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnVideoKind) { |
| constraint_factory_.Reset(); |
| // No device in |capabilities_| has video kind infrared. |
| constraint_factory_.basic().video_kind.SetExact( |
| WebString::FromASCII("infrared")); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().video_kind.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnHeight) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().height.SetExact(123467890); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().height.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().height.SetMin(123467890); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().height.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().height.SetMax(0); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().height.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnWidth) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetExact(123467890); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().width.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetMin(123467890); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().width.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetMax(0); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().width.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| OverconstrainedOnAspectRatio) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().aspect_ratio.SetExact(123467890.0); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().aspect_ratio.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().aspect_ratio.SetMin(123467890.0); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().aspect_ratio.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| // This value is lower than the minimum supported by the test devices. |
| const double kLowAspectRatio = 0.00001; |
| constraint_factory_.basic().aspect_ratio.SetMax(kLowAspectRatio); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().aspect_ratio.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnFrameRate) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().frame_rate.SetExact(123467890.0); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().frame_rate.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().frame_rate.SetMin(123467890.0); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().frame_rate.GetName(), |
| result.failed_constraint_name()); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().frame_rate.SetMax(0.0); |
| result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().frame_rate.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| OverconstrainedOnNoiseReduction) { |
| // Simulate a system that does not support noise reduction. |
| // Manually adding device capabilities because VideoDeviceCaptureCapabilities |
| // is move only. |
| VideoDeviceCaptureCapabilities capabilities; |
| VideoInputDeviceCapabilities device; |
| device.device_id = kDeviceID1; |
| device.facing_mode = media::MEDIA_VIDEO_FACING_NONE; |
| device.formats = { |
| media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f, |
| media::PIXEL_FORMAT_I420), |
| }; |
| capabilities.device_capabilities.push_back(std::move(device)); |
| capabilities.noise_reduction_capabilities = {base::Optional<bool>(false)}; |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().goog_noise_reduction.SetExact(true); |
| auto constraints = constraint_factory_.CreateWebMediaConstraints(); |
| auto result = SelectSettingsVideoDeviceCapture(capabilities, constraints); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().goog_noise_reduction.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| // The "Mandatory" and "Ideal" tests check that various selection criteria work |
| // for each individual constraint in the basic constraint set. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryDeviceID) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().device_id.SetExact( |
| WebString(default_device_->device_id)); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| constraint_factory_.basic().device_id.SetExact( |
| WebString(low_res_device_->device_id)); |
| result = SelectSettings(); |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| constraint_factory_.basic().device_id.SetExact( |
| WebString(high_res_device_->device_id)); |
| result = SelectSettings(); |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryGroupID) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().group_id.SetExact( |
| WebString(default_device_->group_id)); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| constraint_factory_.basic().group_id.SetExact( |
| WebString(low_res_device_->group_id)); |
| result = SelectSettings(); |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| constraint_factory_.basic().group_id.SetExact( |
| WebString(high_res_device_->group_id)); |
| result = SelectSettings(); |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFacingMode) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().facing_mode.SetExact( |
| WebString::FromASCII("environment")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the low-res device supports environment facing mode. Should select |
| // default settings for everything else. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(media::MEDIA_VIDEO_FACING_ENVIRONMENT, |
| low_res_device_->facing_mode); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| constraint_factory_.basic().facing_mode.SetExact( |
| WebString::FromASCII("user")); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device supports user facing mode. Should select default |
| // settings for everything else. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(media::MEDIA_VIDEO_FACING_USER, high_res_device_->facing_mode); |
| EXPECT_EQ(*high_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryVideoKind) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().video_kind.SetExact( |
| WebString::FromASCII("depth")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(kDeviceID4, result.device_id()); |
| EXPECT_EQ(media::PIXEL_FORMAT_Y16, result.Format().pixel_format); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| constraint_factory_.basic().video_kind.SetExact( |
| WebString::FromASCII("color")); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryNoiseReduction) { |
| constraint_factory_.Reset(); |
| const bool kNoiseReductionValues[] = {true, false}; |
| for (auto noise_reduction : kNoiseReductionValues) { |
| constraint_factory_.basic().goog_noise_reduction.SetExact(noise_reduction); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(noise_reduction, result.noise_reduction()); |
| // The default device and settings closest to the default should be |
| // selected. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactHeight) { |
| constraint_factory_.Reset(); |
| const int kHeight = MediaStreamVideoSource::kDefaultHeight; |
| constraint_factory_.basic().height.SetExact(kHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested height. The algorithm |
| // should prefer the first device that supports the requested height natively, |
| // which is the low-res device. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(kHeight, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| |
| const int kLargeHeight = 1500; |
| constraint_factory_.basic().height.SetExact(kLargeHeight); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device at the highest resolution supports the requested |
| // height, even if not natively. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| EXPECT_EQ(kLargeHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(kLargeHeight * AspectRatio(*high_res_highest_format_)), |
| result.track_adapter_settings().target_width()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinHeight) { |
| constraint_factory_.Reset(); |
| const int kHeight = MediaStreamVideoSource::kDefaultHeight; |
| constraint_factory_.basic().height.SetMin(kHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested height range. The |
| // algorithm should prefer the default device. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(kHeight, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kLargeHeight = 1500; |
| constraint_factory_.basic().height.SetMin(kLargeHeight); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device at the highest resolution supports the requested |
| // height range. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| EXPECT_LE(kHeight, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kLargeHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxHeight) { |
| constraint_factory_.Reset(); |
| const int kLowHeight = 20; |
| constraint_factory_.basic().height.SetMax(kLowHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested height range. The |
| // algorithm should prefer the settings that natively exceed the requested |
| // maximum by the lowest amount. In this case it is the low-res device. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(low_res_device_->formats[0], result.Format()); |
| EXPECT_EQ(kLowHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(kLowHeight * AspectRatio(result.Format())), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(static_cast<double>(result.Width()), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / kLowHeight, |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryHeightRange) { |
| constraint_factory_.Reset(); |
| { |
| const int kMinHeight = 480; |
| const int kMaxHeight = 720; |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Height(), kMinHeight); |
| EXPECT_LE(result.Height(), kMaxHeight); |
| // All devices in |capabilities_| support the constraint range. The |
| // algorithm should prefer the default device since it has at least one |
| // native format (the closest-to-default format) included in the requested |
| // range. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kMinHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kMinHeight = 550; |
| const int kMaxHeight = 650; |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Height(), kMinHeight); |
| EXPECT_LE(result.Height(), kMaxHeight); |
| // In this case, the algorithm should prefer the low-res device since it is |
| // the first device with a native format (800x600) included in the requested |
| // range. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(800, result.Width()); |
| EXPECT_EQ(600, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kMinHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kMinHeight = 700; |
| const int kMaxHeight = 800; |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Height(), kMinHeight); |
| EXPECT_LE(result.Height(), kMaxHeight); |
| // In this case, the algorithm should prefer the high-res device since it is |
| // the only device with a native format (1280x720) included in the requested |
| // range. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kMinHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealHeight) { |
| constraint_factory_.Reset(); |
| { |
| const int kIdealHeight = 480; |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm should select the first device that supports the ideal |
| // height natively. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(kIdealHeight, result.Height()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| { |
| const int kIdealHeight = 481; |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // In this case, the default device is selected because it can satisfy the |
| // ideal at a lower cost than the other devices (500 vs 600 or 720). |
| // Note that a native resolution of 480 is further from the ideal than |
| // 500 cropped to 480. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| // The track is cropped to the ideal height, maintaining the source aspect |
| // ratio. |
| EXPECT_EQ(kIdealHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(kIdealHeight * AspectRatio(result.Format())), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kIdealHeight = 1079; |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // In this case, the high-res device has two configurations that satisfy |
| // the ideal value (1920x1080 and 2304x1536). Select the one with shortest |
| // native distance to the ideal value (1920x1080). |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1920, result.Width()); |
| EXPECT_EQ(1080, result.Height()); |
| EXPECT_EQ(kIdealHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(kIdealHeight * AspectRatio(result.Format())), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kIdealHeight = 1200; |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm must the select the only device that can satisfy the ideal, |
| // which is the high-res device at the highest resolution. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| EXPECT_EQ(kIdealHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(kIdealHeight * AspectRatio(result.Format())), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactWidth) { |
| constraint_factory_.Reset(); |
| const int kWidth = 640; |
| constraint_factory_.basic().width.SetExact(kWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested width. The algorithm |
| // should prefer the first device that supports the requested width natively, |
| // which is the low-res device. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(kWidth, result.Width()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(kWidth, result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kLargeWidth = 2000; |
| constraint_factory_.basic().width.SetExact(kLargeWidth); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_LE(kLargeWidth, result.Width()); |
| // Only the high-res device at the highest resolution supports the requested |
| // width, even if not natively. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| EXPECT_EQ(std::round(kLargeWidth / AspectRatio(result.Format())), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(kLargeWidth, result.track_adapter_settings().target_width()); |
| EXPECT_EQ(kLargeWidth, result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kLargeWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinWidth) { |
| constraint_factory_.Reset(); |
| const int kWidth = 640; |
| constraint_factory_.basic().width.SetMin(kWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested width range. The |
| // algorithm should prefer the default device at 1000x1000, which is the |
| // first configuration that satisfies the minimum width. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(kWidth, result.Width()); |
| EXPECT_EQ(1000, result.Width()); |
| EXPECT_EQ(1000, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kLargeWidth = 2000; |
| constraint_factory_.basic().width.SetMin(kLargeWidth); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device at the highest resolution supports the requested |
| // minimum width. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(kLargeWidth, result.Width()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kLargeWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxWidth) { |
| constraint_factory_.Reset(); |
| const int kLowWidth = 30; |
| constraint_factory_.basic().width.SetMax(kLowWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested width range. The |
| // algorithm should prefer the settings that natively exceed the requested |
| // maximum by the lowest amount. In this case it is the low-res device at its |
| // lowest resolution. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(low_res_device_->formats[0], result.Format()); |
| // The track is cropped to kLowWidth and keeps the source aspect ratio. |
| EXPECT_EQ(std::round(kLowWidth / AspectRatio(result.Format())), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(kLowWidth, result.track_adapter_settings().target_width()); |
| EXPECT_EQ(kLowWidth, result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryWidthRange) { |
| constraint_factory_.Reset(); |
| { |
| const int kMinWidth = 640; |
| const int kMaxWidth = 1280; |
| constraint_factory_.basic().width.SetMin(kMinWidth); |
| constraint_factory_.basic().width.SetMax(kMaxWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Width(), kMinWidth); |
| EXPECT_LE(result.Width(), kMaxWidth); |
| // All devices in |capabilities_| support the constraint range. The |
| // algorithm should prefer the default device since it has at least one |
| // native format (1000x1000) included in the requested range. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1000, result.Width()); |
| EXPECT_EQ(1000, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kMinWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kMinWidth = 750; |
| const int kMaxWidth = 850; |
| constraint_factory_.basic().width.SetMin(kMinWidth); |
| constraint_factory_.basic().width.SetMax(kMaxWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Width(), kMinWidth); |
| EXPECT_LE(result.Width(), kMaxWidth); |
| // In this case, the algorithm should prefer the low-res device since it is |
| // the first device with a native format (800x600) included in the requested |
| // range. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(800, result.Width()); |
| EXPECT_EQ(600, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kMinWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kMinWidth = 1900; |
| const int kMaxWidth = 2000; |
| constraint_factory_.basic().width.SetMin(kMinWidth); |
| constraint_factory_.basic().width.SetMax(kMaxWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Width(), kMinWidth); |
| EXPECT_LE(result.Width(), kMaxWidth); |
| // In this case, the algorithm should prefer the high-res device since it is |
| // the only device with a native format (1920x1080) included in the |
| // requested range. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1920, result.Width()); |
| EXPECT_EQ(1080, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(kMinWidth) / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealWidth) { |
| constraint_factory_.Reset(); |
| { |
| const int kIdealWidth = 320; |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm should select the first device that supports the ideal |
| // width natively, which is the low-res device at 320x240. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(kIdealWidth, result.Width()); |
| // The ideal value is satisfied with a native resolution, so no rescaling. |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(kIdealWidth, result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kIdealWidth = 321; |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // In this case, the high_res device is selected because it has a mode that |
| // can satisfy the ideal at a lower cost than other devices (480 vs 500). |
| // Note that a native resolution of 320 is further from the ideal value of |
| // 321 than 480 cropped to 321. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(480, result.Width()); |
| // The track is cropped to kIdealWidth and keeps the source aspect ratio. |
| EXPECT_EQ(std::round(kIdealWidth / AspectRatio(result.Format())), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(kIdealWidth, result.track_adapter_settings().target_width()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kIdealWidth = 2000; |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm must the select the only device that can satisfy the ideal. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| // The track is cropped to kIdealWidth and keeps the source aspect ratio. |
| EXPECT_EQ(std::round(kIdealWidth / AspectRatio(result.Format())), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(kIdealWidth, result.track_adapter_settings().target_width()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const int kIdealWidth = 3000; |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm must the select the device and setting with less distance |
| // to the ideal. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactFrameRate) { |
| constraint_factory_.Reset(); |
| const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate; |
| constraint_factory_.basic().frame_rate.SetExact(kFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested frame rate. The |
| // algorithm should prefer the first device that supports the requested frame |
| // rate natively, which is the low-res device at 640x480x30Hz. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(kFrameRate, result.FrameRate()); |
| EXPECT_EQ(640, result.Width()); |
| EXPECT_EQ(480, result.Height()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, kFrameRate); |
| |
| const double kLargeFrameRate = 50; |
| constraint_factory_.basic().frame_rate.SetExact(kLargeFrameRate); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device supports the requested frame rate, even if not |
| // natively. The least expensive configuration that supports the requested |
| // frame rate is 1280x720x60Hz. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(60.0, result.FrameRate()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, kLargeFrameRate); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinFrameRate) { |
| // MinFrameRate equal to default frame rate. |
| { |
| constraint_factory_.Reset(); |
| const double kMinFrameRate = MediaStreamVideoSource::kDefaultFrameRate; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested frame-rate range. |
| // The algorithm should prefer the default device. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| // The format closest to the default satisfies the constraint. |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| EXPECT_TRUE(result.min_frame_rate().has_value()); |
| EXPECT_EQ(result.min_frame_rate(), kMinFrameRate); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| } |
| |
| // MinFrameRate greater than default frame rate. |
| { |
| const double kMinFrameRate = 50; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device supports the requested frame-rate range. |
| // The least expensive configuration is 1280x720x60Hz. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(kMinFrameRate, result.FrameRate()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| EXPECT_TRUE(result.min_frame_rate().has_value()); |
| EXPECT_EQ(result.min_frame_rate(), kMinFrameRate); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| } |
| |
| // MinFrameRate lower than the minimum allowed value. |
| { |
| const double kMinFrameRate = -0.01; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The minimum frame rate is ignored. Default settings should be used. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| EXPECT_FALSE(result.min_frame_rate().has_value()); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| } |
| |
| // MinFrameRate equal to the minimum allowed value. |
| { |
| const double kMinFrameRate = 0.0; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_TRUE(result.min_frame_rate().has_value()); |
| EXPECT_EQ(result.min_frame_rate(), kMinFrameRate); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxFrameRate) { |
| // MaxFrameRate within valid range. |
| { |
| constraint_factory_.Reset(); |
| const double kMaxFrameRate = 10; |
| constraint_factory_.basic().frame_rate.SetMax(kMaxFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // All devices in |capabilities_| support the requested frame-rate range. |
| // The algorithm should prefer the settings that natively exceed the |
| // requested maximum by the lowest amount. In this case it is the high-res |
| // device with default resolution . |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(kMaxFrameRate, result.FrameRate()); |
| EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height()); |
| EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width()); |
| EXPECT_FALSE(result.min_frame_rate().has_value()); |
| EXPECT_TRUE(result.max_frame_rate().has_value()); |
| EXPECT_EQ(kMaxFrameRate, result.max_frame_rate()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, kMaxFrameRate); |
| } |
| |
| // MaxFrameRate greater than the maximum allowed. |
| { |
| constraint_factory_.Reset(); |
| const double kMaxFrameRate = media::limits::kMaxFramesPerSecond + 0.1; |
| constraint_factory_.basic().frame_rate.SetMax(kMaxFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The maximum frame rate should be ignored. Default settings apply. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| EXPECT_FALSE(result.min_frame_rate().has_value()); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| } |
| |
| // MaxFrameRate equal to the maximum and minimum allowed MaxFrameRate. |
| { |
| const double kMaxFrameRates[] = {1.0, media::limits::kMaxFramesPerSecond}; |
| for (double max_frame_rate : kMaxFrameRates) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().frame_rate.SetMax(max_frame_rate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_TRUE(result.max_frame_rate().has_value()); |
| EXPECT_FALSE(result.min_frame_rate().has_value()); |
| EXPECT_EQ(result.max_frame_rate(), max_frame_rate); |
| } |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFrameRateRange) { |
| constraint_factory_.Reset(); |
| { |
| const double kMinFrameRate = 10; |
| const double kMaxFrameRate = 40; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| constraint_factory_.basic().frame_rate.SetMax(kMaxFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_LE(kMinFrameRate, result.FrameRate()); |
| EXPECT_GE(kMaxFrameRate, result.FrameRate()); |
| // All devices in |capabilities_| support the constraint range. The |
| // algorithm should prefer the default device since its closest-to-default |
| // format has a frame rate included in the requested range. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| { |
| const double kMinFrameRate = 25; |
| const double kMaxFrameRate = 35; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| constraint_factory_.basic().frame_rate.SetMax(kMaxFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.FrameRate(), kMinFrameRate); |
| EXPECT_LE(result.FrameRate(), kMaxFrameRate); |
| // In this case, the algorithm should prefer the low-res device since it is |
| // the first device with a native frame rate included in the requested |
| // range. The default resolution should be preferred as secondary criterion. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| { |
| const double kMinFrameRate = 50; |
| const double kMaxFrameRate = 70; |
| constraint_factory_.basic().frame_rate.SetMin(kMinFrameRate); |
| constraint_factory_.basic().frame_rate.SetMax(kMaxFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.FrameRate(), kMinFrameRate); |
| EXPECT_LE(result.FrameRate(), kMaxFrameRate); |
| // In this case, the algorithm should prefer the high-res device since it is |
| // the only device with a native format included in the requested range. |
| // The 1280x720 resolution should be selected due to closeness to default |
| // settings, which is the second tie-breaker criterion that applies. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealFrameRate) { |
| constraint_factory_.Reset(); |
| { |
| const double kIdealFrameRate = MediaStreamVideoSource::kDefaultFrameRate; |
| constraint_factory_.basic().frame_rate.SetIdeal(kIdealFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm should select the first configuration that supports the |
| // ideal frame rate natively, which is the low-res device. Default |
| // resolution should be selected as secondary criterion. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, kIdealFrameRate); |
| } |
| |
| { |
| const double kIdealFrameRate = 31; |
| constraint_factory_.basic().frame_rate.SetIdeal(kIdealFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // In this case, the default device is selected because it can satisfy the |
| // ideal at a lower cost than the other devices (40 vs 60). |
| // Note that a native frame rate of 30 is further from the ideal than |
| // 31 adjusted to 30. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, kIdealFrameRate); |
| } |
| |
| { |
| const double kIdealFrameRate = 55; |
| constraint_factory_.basic().frame_rate.SetIdeal(kIdealFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The high-res device format 1280x720x60.0 must be selected because its |
| // frame rate can satisfy the ideal frame rate and has resolution closest |
| // to the default. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| EXPECT_EQ(60, result.FrameRate()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, kIdealFrameRate); |
| } |
| |
| { |
| const double kIdealFrameRate = 100; |
| constraint_factory_.basic().frame_rate.SetIdeal(kIdealFrameRate); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The algorithm must select settings with frame rate closest to the ideal. |
| // The high-res device format 1280x720x60.0 must be selected because its |
| // frame rate it closest to the ideal value and it has resolution closest to |
| // the default. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| EXPECT_EQ(60, result.FrameRate()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactAspectRatio) { |
| constraint_factory_.Reset(); |
| const double kAspectRatio = 4.0 / 3.0; |
| constraint_factory_.basic().aspect_ratio.SetExact(kAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| double min_width = 1.0; |
| double max_width = result.Width(); |
| double min_height = 1.0; |
| double max_height = result.Height(); |
| double min_aspect_ratio = min_width / max_height; |
| double max_aspect_ratio = max_width / min_height; |
| // The requested aspect ratio must be within the supported range. |
| EXPECT_GE(kAspectRatio, min_aspect_ratio); |
| EXPECT_LE(kAspectRatio, max_aspect_ratio); |
| // All devices in |capabilities_| support the requested aspect ratio. |
| // The algorithm should prefer the first device that supports the requested |
| // aspect ratio. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| EXPECT_EQ(std::round(result.Width() / kAspectRatio), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kMinWidth = 500; |
| const int kMaxWidth = 1000; |
| const int kMaxHeight = 500; |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| constraint_factory_.basic().width.SetMin(kMinWidth); |
| constraint_factory_.basic().width.SetMax(kMaxWidth); |
| constraint_factory_.basic().aspect_ratio.SetExact(kAspectRatio); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| min_width = std::max(1, kMinWidth); |
| max_width = std::min(result.Width(), kMaxWidth); |
| min_height = 1.0; |
| max_height = std::min(result.Height(), kMaxHeight); |
| min_aspect_ratio = min_width / max_height; |
| max_aspect_ratio = max_width / min_height; |
| // The requested aspect ratio must be within the supported range. |
| EXPECT_GE(kAspectRatio, min_aspect_ratio); |
| EXPECT_LE(kAspectRatio, max_aspect_ratio); |
| // The default device can support the requested aspect ratio with the default |
| // settings (500x500) using cropping. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| EXPECT_EQ(std::round(result.Width() / kAspectRatio), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kMinHeight = 480; |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| constraint_factory_.basic().width.SetMin(kMinWidth); |
| constraint_factory_.basic().width.SetMax(kMaxWidth); |
| constraint_factory_.basic().aspect_ratio.SetExact(kAspectRatio); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| min_width = std::max(1, kMinWidth); |
| max_width = std::min(result.Width(), kMaxWidth); |
| min_height = std::max(1, kMinHeight); |
| max_height = std::min(result.Height(), kMaxHeight); |
| min_aspect_ratio = min_width / max_height; |
| max_aspect_ratio = max_width / min_height; |
| // The requested aspect ratio must be within the supported range. |
| EXPECT_GE(kAspectRatio, min_aspect_ratio); |
| EXPECT_LE(kAspectRatio, max_aspect_ratio); |
| // Given resolution constraints, the default device with closest-to-default |
| // settings cannot satisfy the required aspect ratio. |
| // The first device that can do it is the low-res device with a native |
| // resolution of 640x480. Higher resolutions for the default device are more |
| // penalized by the constraints than the default native resolution of the |
| // low-res device. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| // Native resolution, so no rescaling. |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinAspectRatio) { |
| constraint_factory_.Reset(); |
| const double kAspectRatio = 4.0 / 3.0; |
| constraint_factory_.basic().aspect_ratio.SetMin(kAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| double max_width = result.Width(); |
| double min_height = 1.0; |
| double max_aspect_ratio = max_width / min_height; |
| // Minimum constraint aspect ratio must be less than or equal to the maximum |
| // supported by the source. |
| EXPECT_LE(kAspectRatio, max_aspect_ratio); |
| // All devices in |capabilities_| support the requested aspect-ratio range. |
| // The algorithm should prefer the first device that supports the requested |
| // aspect-ratio range, which in this case is the default device. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| // Adjust the track resolution to use the minimum aspect ratio, which is |
| // greater than the source's aspect ratio. |
| EXPECT_EQ(std::round(result.Width() / kAspectRatio), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kMinWidth = 500; |
| const int kMaxWidth = 1000; |
| const int kMinHeight = 480; |
| const int kMaxHeight = 500; |
| constraint_factory_.basic().width.SetMin(kMinWidth); |
| constraint_factory_.basic().width.SetMax(kMaxWidth); |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| constraint_factory_.basic().aspect_ratio.SetMin(kAspectRatio); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| max_width = std::min(result.Width(), kMaxWidth); |
| min_height = std::max(1, kMinHeight); |
| max_aspect_ratio = max_width / min_height; |
| // Minimum constraint aspect ratio must be less than or equal to the minimum |
| // supported by the source. |
| EXPECT_LE(kAspectRatio, max_aspect_ratio); |
| // Given resolution constraints, the default device with closest-to-default |
| // settings cannot satisfy the required minimum aspect ratio (maximum would |
| // be 500/480). The first device that can is the low-res device with a native |
| // resolution of 640x480. |
| // Higher resolutions for the default device are more penalized by the |
| // constraints than the default native resolution of the low-res device. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*low_res_closest_format_, result.Format()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| // The source's native aspect ratio equals the minimum aspect ratio. |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(max_aspect_ratio, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxAspectRatio) { |
| constraint_factory_.Reset(); |
| const double kAspectRatio = 0.5; |
| constraint_factory_.basic().aspect_ratio.SetMax(kAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| double min_width = 1.0; |
| double max_height = result.Height(); |
| double min_aspect_ratio = min_width / max_height; |
| // Minimum constraint aspect ratio must be less than or equal to the maximum |
| // supported by the source. |
| EXPECT_GE(kAspectRatio, min_aspect_ratio); |
| // All devices in |capabilities_| support the requested aspect-ratio range. |
| // The algorithm should prefer the first device that supports the requested |
| // aspect-ratio range, which in this case is the default device. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| // The track's aspect ratio is adjusted to the maximum, which is lower than |
| // the source's native aspect ratio. |
| EXPECT_EQ(result.Height(), result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(result.Height() * kAspectRatio), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(min_aspect_ratio, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| const int kExactWidth = 360; |
| const int kMinHeight = 360; |
| const int kMaxHeight = 720; |
| constraint_factory_.basic().width.SetExact(kExactWidth); |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().height.SetMax(kMaxHeight); |
| constraint_factory_.basic().aspect_ratio.SetMax(kAspectRatio); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| min_width = std::max(1, kExactWidth); |
| max_height = std::min(result.Height(), kMaxHeight); |
| min_aspect_ratio = min_width / max_height; |
| // Minimum constraint aspect ratio must be less than or equal to the minimum |
| // supported by the source. |
| EXPECT_GE(kAspectRatio, min_aspect_ratio); |
| // Given resolution constraints, the default device with closest-to-default |
| // settings cannot satisfy the required maximum aspect ratio (maximum would |
| // be 360/500). |
| // The high-res device with a native resolution of 1280x720 can support |
| // 360x720 with cropping with less penalty than the default device at |
| // 1000x1000. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| // The track's aspect ratio is adjusted to the maximum, which is lower than |
| // the source's native aspect ratio. |
| EXPECT_EQ(result.Height(), result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(result.Height() * kAspectRatio), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(min_aspect_ratio, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(kAspectRatio, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryAspectRatioRange) { |
| constraint_factory_.Reset(); |
| { |
| const double kMinAspectRatio = 0.5; |
| const double kMaxAspectRatio = 1.0; |
| |
| constraint_factory_.basic().aspect_ratio.SetMin(kMinAspectRatio); |
| constraint_factory_.basic().aspect_ratio.SetMax(kMaxAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| double min_width = 1.0; |
| double max_width = result.Width(); |
| double min_height = 1.0; |
| double max_height = result.Height(); |
| double min_aspect_ratio = min_width / max_height; |
| double max_aspect_ratio = max_width / min_height; |
| // Constraint aspect-ratio range must have nonempty intersection with |
| // supported range. |
| EXPECT_LE(kMinAspectRatio, max_aspect_ratio); |
| EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); |
| // All devices in |capabilities_| support the requested aspect-ratio range. |
| // The algorithm should prefer the first device that supports the requested |
| // aspect-ratio range, which in this case is the default device. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| // The source's aspect ratio matches the maximum aspect ratio. No adjustment |
| // is required. |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(kMinAspectRatio, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(kMaxAspectRatio, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const double kMinAspectRatio = 3.0; |
| const double kMaxAspectRatio = 4.0; |
| |
| const int kMinHeight = 600; |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().height.SetMin(kMinHeight); |
| constraint_factory_.basic().aspect_ratio.SetMin(kMinAspectRatio); |
| constraint_factory_.basic().aspect_ratio.SetMax(kMaxAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| double min_width = 1.0; |
| double max_width = result.Width(); |
| double min_height = 1.0; |
| double max_height = result.Height(); |
| double min_aspect_ratio = min_width / max_height; |
| double max_aspect_ratio = max_width / min_height; |
| // Constraint aspect-ratio range must have nonempty intersection with |
| // supported range. |
| EXPECT_LE(kMinAspectRatio, max_aspect_ratio); |
| EXPECT_GE(kMaxAspectRatio, min_aspect_ratio); |
| // The only device that supports the resolution and aspect ratio constraint |
| // is the high-res device. The 1920x1080 is the least expensive format. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1920, result.Width()); |
| EXPECT_EQ(1080, result.Height()); |
| // The track is cropped to support the minimum aspect ratio. |
| EXPECT_EQ(std::round(result.Width() / kMinAspectRatio), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(kMinAspectRatio, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kMinHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealAspectRatio) { |
| constraint_factory_.Reset(); |
| { |
| const double kIdealAspectRatio = 0.5; |
| constraint_factory_.basic().aspect_ratio.SetIdeal(kIdealAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| double min_width = 1.0; |
| double max_width = result.Width(); |
| double min_height = 1.0; |
| double max_height = result.Height(); |
| double min_aspect_ratio = min_width / max_height; |
| double max_aspect_ratio = max_width / min_height; |
| // All devices in |capabilities_| support the ideal aspect-ratio. |
| // The algorithm should prefer the default device with closest-to-default |
| // settings. |
| EXPECT_LE(kIdealAspectRatio, max_aspect_ratio); |
| EXPECT_GE(kIdealAspectRatio, min_aspect_ratio); |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| // The track is cropped to support the ideal aspect ratio. |
| EXPECT_EQ(result.Height(), result.track_adapter_settings().target_height()); |
| EXPECT_EQ(std::round(result.Height() * kIdealAspectRatio), |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(min_aspect_ratio, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(max_aspect_ratio, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const double kIdealAspectRatio = 1500.0; |
| constraint_factory_.basic().aspect_ratio.SetIdeal(kIdealAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The only device that supports the ideal aspect ratio is the high-res |
| // device. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| // The most exact way to support the ideal aspect ratio would be to crop to |
| // 1920x1080 to 1500x1. However, with 1920x1080 the algorithm tries to crop |
| // to 1920x1.28 and rounds to 1920x1. Since the aspect ratio of 1280x1 is |
| // closer to ideal than 1920x1, 1280x1 is selected instead. |
| // In this case, the effect of rounding is noticeable because of the |
| // resulting low value for height. For more typical aspect-ratio values, |
| // the 1-pixel error caused by rounding one dimension does not translate to |
| // a absolute error on the other dimension. |
| EXPECT_EQ(std::round(result.Width() / kIdealAspectRatio), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const double kIdealAspectRatio = 2000.0; |
| constraint_factory_.basic().aspect_ratio.SetIdeal(kIdealAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The best way to support this ideal aspect ratio would be to rescale |
| // 2304x1536 to 2000x1, but the algorithm would try to rescale to 2304x1.15 |
| // and then round. Since 1920x1 has an aspect ratio closer to 2000, it is |
| // selected over 2304x1. The only device that supports this resolution is |
| // the high-res device open at 1920x1080. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1920, result.Width()); |
| EXPECT_EQ(1080, result.Height()); |
| EXPECT_EQ(std::round(result.Width() / kIdealAspectRatio), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const double kIdealAspectRatio = 4000.0; |
| constraint_factory_.basic().aspect_ratio.SetIdeal(kIdealAspectRatio); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The configuration closest to the ideal aspect ratio is is the high-res |
| // device with its highest resolution, cropped to 2304x1. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| // In this case there is no rounding error. |
| EXPECT_EQ(1, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const double kIdealAspectRatio = 2.0; |
| const int kExactHeight = 400; |
| constraint_factory_.basic().aspect_ratio.SetIdeal(kIdealAspectRatio); |
| constraint_factory_.basic().height.SetExact(kExactHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The first device to support the ideal aspect ratio and the resolution |
| // constraint is the low-res device. The 800x600 format cropped to 800x400 |
| // is the lest expensive way to achieve it. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(800, result.Width()); |
| EXPECT_EQ(600, result.Height()); |
| EXPECT_EQ(kExactHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(kExactHeight * kIdealAspectRatio, |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(1.0 / kExactHeight, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kExactHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| { |
| const double kIdealAspectRatio = 3.0; |
| const int kExactHeight = 400; |
| constraint_factory_.basic().aspect_ratio.SetIdeal(kIdealAspectRatio); |
| constraint_factory_.basic().height.SetExact(kExactHeight); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The only device that supports the ideal aspect ratio and the resolution |
| // constraint is the high-res device. The 1280x720 cropped to 1200x400 is |
| // the lest expensive way to achieve it. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1280, result.Width()); |
| EXPECT_EQ(720, result.Height()); |
| EXPECT_EQ(kExactHeight, result.track_adapter_settings().target_height()); |
| EXPECT_EQ(kExactHeight * kIdealAspectRatio, |
| result.track_adapter_settings().target_width()); |
| EXPECT_EQ(1.0 / kExactHeight, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(static_cast<double>(result.Width()) / kExactHeight, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryResizeMode) { |
| const int kIdealWidth = 641; |
| const int kIdealHeight = 480; |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| constraint_factory_.basic().resize_mode.SetExact( |
| WebString::FromASCII("none")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // A native mode of 640x480 should be selected since it is closest native mode |
| // to the ideal values. |
| EXPECT_EQ(result.Width(), 640); |
| EXPECT_EQ(result.Height(), 480); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| |
| constraint_factory_.basic().resize_mode.SetExact( |
| WebString::FromASCII("crop-and-scale")); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Width(), kIdealWidth); |
| EXPECT_GE(result.Height(), kIdealHeight); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), kIdealWidth); |
| EXPECT_EQ(result.track_adapter_settings().target_height(), kIdealHeight); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealResizeMode) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("crop-and-scale")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Since no constraints are given, the default device with resolution closest |
| // to default is selected. However, rescaling is enabled due to the ideal |
| // resize mode. |
| EXPECT_EQ(result.device_id(), default_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 500); |
| EXPECT_EQ(result.Height(), 500); |
| EXPECT_TRUE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), 500); |
| EXPECT_EQ(result.track_adapter_settings().target_height(), 500); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| IdealResizeModeResolutionGreaterThanNative) { |
| // Ideal resolution is slightly greater than the closest native resolution. |
| const int kIdealWidth = 641; |
| const int kIdealHeight = 480; |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("none")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // A native mode of 640x480 should be selected since it is the closest native |
| // mode to the ideal resolution values. |
| EXPECT_EQ(result.Width(), 640); |
| EXPECT_EQ(result.Height(), 480); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("crop-and-scale")); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_GE(result.Width(), kIdealWidth); |
| EXPECT_GE(result.Height(), kIdealHeight); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), kIdealWidth); |
| EXPECT_EQ(result.track_adapter_settings().target_height(), kIdealHeight); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| IdealResizeModeResolutionLessThanNative) { |
| // Ideal resolution is slightly less than the closest native resolution. |
| const int kIdealWidth = 639; |
| const int kIdealHeight = 479; |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(kIdealWidth); |
| constraint_factory_.basic().height.SetIdeal(kIdealHeight); |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("none")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // A native mode of 640x480 should be selected since it is the closest native |
| // mode to the ideal values. |
| EXPECT_EQ(result.Width(), 640); |
| EXPECT_EQ(result.Height(), 480); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("crop-and-scale")); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Rescaling is preferred, therefore a native mode greater than the ideal |
| // resolution is chosen. |
| EXPECT_GE(result.Width(), kIdealWidth); |
| EXPECT_GE(result.Height(), kIdealHeight); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), kIdealWidth); |
| EXPECT_EQ(result.track_adapter_settings().target_height(), kIdealHeight); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealResizeFarFromNative) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(1); |
| constraint_factory_.basic().height.SetIdeal(1); |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("none")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The native mode closest to 1x1 is 40x30 with the low-res device. |
| EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 40); |
| EXPECT_EQ(result.Height(), 30); |
| // Despite resize_mode being ideal "none", SelectSettings opts for rescaling |
| // since the fitness distance of 40x30 with respect to the ideal 1x1 is larger |
| // than the fitness distance for resize_mode not being "none" |
| // (29/30 + 39/40 > 1.0) |
| EXPECT_TRUE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), 1); |
| EXPECT_EQ(result.track_adapter_settings().target_height(), 1); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(1); |
| constraint_factory_.basic().resize_mode.SetIdeal( |
| WebString::FromASCII("none")); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The native mode closest to 1x1 is 40x30 with the low-res device. |
| EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 40); |
| EXPECT_EQ(result.Height(), 30); |
| // In this case, SelectSettings opts for not rescaling since the fitness |
| // distance of width 40 with respect to the ideal 1 is larger than the |
| // fitness distance for resize_mode not being "none" (39/40 < 1.0) |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, TwoIdealResizeValues) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(641); |
| constraint_factory_.basic().height.SetIdeal(481); |
| constraint_factory_.basic().resize_mode.SetIdeal(WebVector<WebString>( |
| {WebString::FromASCII("none"), WebString::FromASCII("crop-and-scale")})); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // 800x600 rescaled to 641x481 is closest to the specified ideal values. |
| EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 800); |
| EXPECT_EQ(result.Height(), 600); |
| // Since both resize modes are considered ideal, rescaling is preferred |
| // because of the penalty due to deviating from the ideal reo |
| EXPECT_TRUE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), 641); |
| EXPECT_EQ(result.track_adapter_settings().target_height(), 481); |
| |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().resize_mode.SetIdeal(WebVector<WebString>( |
| {WebString::FromASCII("none"), WebString::FromASCII("crop-and-scale")})); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Given that both resize modes are ideal, the default device with the |
| // resolution closest to the default without rescaling is selected. |
| EXPECT_EQ(result.device_id(), default_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 500); |
| EXPECT_EQ(result.Height(), 500); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| } |
| |
| // The "Advanced" tests check selection criteria involving advanced constraint |
| // sets. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedMinMaxResolutionFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMin(4000); |
| advanced1.height.SetMin(4000); |
| // No device supports the first advanced set. This first advanced constraint |
| // set is therefore ignored in all calls to SelectSettings(). |
| // Tie-breaker rule that applies is closeness to default settings. |
| auto result = SelectSettings(); |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMin(320); |
| advanced2.height.SetMin(240); |
| advanced2.width.SetMax(640); |
| advanced2.height.SetMax(480); |
| result = SelectSettings(); |
| // The device that best supports this advanced set is the low-res device, |
| // which natively supports the maximum resolution. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(640, result.Width()); |
| EXPECT_EQ(480, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(320.0 / 480.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(640.0 / 240.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| |
| WebMediaTrackConstraintSet& advanced3 = constraint_factory_.AddAdvanced(); |
| advanced3.frame_rate.SetMax(10.0); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The high-res device natively supports the third advanced set in addition |
| // to the previous set and should be selected. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(640, result.Width()); |
| EXPECT_EQ(480, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(320.0 / 480.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(640.0 / 240.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, 10.0); |
| |
| WebMediaTrackConstraintSet& advanced4 = constraint_factory_.AddAdvanced(); |
| advanced4.width.SetMax(1000); |
| advanced4.height.SetMax(1000); |
| result = SelectSettings(); |
| // The fourth advanced set does not change the allowed range set by previous |
| // sets, so the selection is the same as in the previous case. |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(640, result.Width()); |
| EXPECT_EQ(480, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(320.0 / 480.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(640.0 / 240.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, 10.0); |
| |
| constraint_factory_.basic().width.SetIdeal(100); |
| constraint_factory_.basic().height.SetIdeal(100); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The allowed resolution range set by constraints is [320x240-640x480], but |
| // since the ideal resolution is 100x100, the preferred resolution in the |
| // allowed range is 320x240. |
| // With regards to frame rate, the maximum allowed is 10Hz. |
| // This means that the track should be configured as 320x240@10Hz. |
| // The low-res device at 320x240@30Hz is selected over the high-res device |
| // at 640x400@10Hz because the distance between 320x240@30Hz and 320x240@10Hz |
| // is lower than the distance between 640x400@10Hz and 320x240@10Hz. |
| // Both candidates support standard fitness distance equally, since both can |
| // use adjusments to produce 320x240@10Hz. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(320, result.Width()); |
| EXPECT_EQ(240, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(320.0 / 240.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(320.0 / 240.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, 10.0); |
| |
| constraint_factory_.basic().width.SetIdeal(2000); |
| constraint_factory_.basic().height.SetIdeal(1500); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The high-res device at 640x480@10Hz is closer to the large ideal |
| // resolution. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(640, result.Width()); |
| EXPECT_EQ(480, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(320.0 / 480.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(640.0 / 240.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, 10.0); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedResolutionAndFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetExact(1920); |
| advanced1.height.SetExact(1080); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.frame_rate.SetExact(60.0); |
| WebMediaTrackConstraintSet& advanced3 = constraint_factory_.AddAdvanced(); |
| advanced3.width.SetExact(2304); |
| advanced3.height.SetExact(1536); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The high-res device is the only one that satisfies the first advanced |
| // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0 |
| // satisfies sets 1, and 2. The latter must be selected, regardless of |
| // any other criteria. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1920, result.Width()); |
| EXPECT_EQ(1080, result.Height()); |
| EXPECT_EQ(60.0, result.FrameRate()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(1920.0 / 1080.0, |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(1920.0 / 1080.0, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result, 60.0); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedNoiseReduction) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMin(640); |
| advanced1.height.SetMin(480); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMin(1920); |
| advanced2.height.SetMin(1080); |
| advanced2.goog_noise_reduction.SetExact(false); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(1920, result.Width()); |
| EXPECT_LE(1080, result.Height()); |
| EXPECT_TRUE(result.noise_reduction() && !*result.noise_reduction()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(1920.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width() / 1080.0, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryNoiseReduction) { |
| { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMin(640); |
| advanced1.height.SetMin(480); |
| advanced1.goog_noise_reduction.SetExact(true); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMin(1920); |
| advanced2.height.SetMin(1080); |
| advanced2.goog_noise_reduction.SetExact(false); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set cannot be satisfied because it contradicts the |
| // first set. The default device supports the first set and should be |
| // selected. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(640, result.Width()); |
| EXPECT_LE(480, result.Height()); |
| EXPECT_TRUE(result.noise_reduction() && *result.noise_reduction()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(640.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width() / 480.0, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| // Same test without noise reduction |
| { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMin(640); |
| advanced1.height.SetMin(480); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMin(1920); |
| advanced2.height.SetMin(1080); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Only the high-res device can satisfy the second advanced set. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_LE(1920, result.Width()); |
| EXPECT_LE(1080, result.Height()); |
| // Should select default noise reduction setting. |
| EXPECT_TRUE(!result.noise_reduction()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(1920.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width() / 1080.0, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryExactResolution) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetExact(640); |
| advanced1.height.SetExact(480); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetExact(1920); |
| advanced2.height.SetExact(1080); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. The low-res device is the one that best supports the requested |
| // resolution. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(640, result.Width()); |
| EXPECT_EQ(480, result.Height()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(640.0 / 480.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(640.0 / 480.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryMaxMinResolutionFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMax(640); |
| advanced1.height.SetMax(480); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMin(1920); |
| advanced2.height.SetMin(1080); |
| advanced2.frame_rate.SetExact(60.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. The default device with the 200x200@40Hz format should be selected. |
| // That format satisfies the first advanced set as well as any other, so the |
| // tie breaker rule that applies is default device ID. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(200, result.Width()); |
| EXPECT_EQ(200, result.Height()); |
| EXPECT_EQ(40, result.FrameRate()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(1.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryMinMaxResolutionFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMin(800); |
| advanced1.height.SetMin(600); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMax(640); |
| advanced2.height.SetMax(480); |
| advanced2.frame_rate.SetExact(60.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. The default device with the 1000x1000@20Hz format should be selected. |
| // That format satisfies the first advanced set as well as any other, so the |
| // tie breaker rule that applies is default device ID. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(1000, result.Width()); |
| EXPECT_EQ(1000, result.Height()); |
| EXPECT_EQ(20, result.FrameRate()); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(800.0 / result.Height(), |
| result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width() / 600.0, |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryExactAspectRatio) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.aspect_ratio.SetExact(2300.0); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.aspect_ratio.SetExact(3.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. Only the high-res device in the highest-resolution format supports the |
| // requested aspect ratio. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| // The track is cropped to support the exact aspect ratio. |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(std::round(result.Height() / 2300.0), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(2300.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(2300.0, result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryAspectRatioRange) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.aspect_ratio.SetMin(2300.0); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.aspect_ratio.SetMax(3.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. Only the high-res device in the highest-resolution format supports the |
| // requested aspect ratio. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*high_res_highest_format_, result.Format()); |
| // The track is cropped to support the min aspect ratio. |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(std::round(result.Height() / 2300.0), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(2300.0, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryExactFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.frame_rate.SetExact(40.0); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.frame_rate.SetExact(45.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. |
| EXPECT_EQ(40.0, result.FrameRate()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryFrameRateRange) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.frame_rate.SetMin(40.0); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.frame_rate.SetMax(35.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. |
| EXPECT_LE(40.0, result.FrameRate()); |
| CheckTrackAdapterSettingsEqualsResolution(result); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryWidthFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.width.SetMax(1920); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMin(2000); |
| advanced2.frame_rate.SetExact(10.0); |
| WebMediaTrackConstraintSet& advanced3 = constraint_factory_.AddAdvanced(); |
| advanced3.frame_rate.SetExact(30.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The low-res device at 320x240@30Hz satisfies advanced sets 1 and 3. |
| // The high-res device at 2304x1536@10.0f can satisfy sets 1 and 2, but not |
| // both at the same time. Thus, low-res device must be preferred. |
| EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(30.0, result.FrameRate()); |
| EXPECT_GE(1920, result.Width()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryHeightFrameRate) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.height.SetMax(1080); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.height.SetMin(1500); |
| advanced2.frame_rate.SetExact(10.0); |
| WebMediaTrackConstraintSet& advanced3 = constraint_factory_.AddAdvanced(); |
| advanced3.frame_rate.SetExact(60.0); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The high-res device at 1280x768@60Hz and 1920x1080@60Hz satisfies advanced |
| // sets 1 and 3. The same device at 2304x1536@10.0f can satisfy sets 1 and 2, |
| // but not both at the same time. Thus, the format closest to default that |
| // satisfies sets 1 and 3 must be chosen. |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(60.0, result.FrameRate()); |
| EXPECT_GE(1080, result.Height()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedDeviceID) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| WebString id_vector1[] = {WebString::FromASCII(kDeviceID1), |
| WebString::FromASCII(kDeviceID2)}; |
| advanced1.device_id.SetExact( |
| WebVector<WebString>(id_vector1, base::size(id_vector1))); |
| WebString id_vector2[] = {WebString::FromASCII(kDeviceID2), |
| WebString::FromASCII(kDeviceID3)}; |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.device_id.SetExact( |
| WebVector<WebString>(id_vector2, base::size(id_vector2))); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // kDeviceID2 must be selected because it is the only one that satisfies both |
| // advanced sets. |
| EXPECT_EQ(std::string(kDeviceID2), result.device_id()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedGroupID) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| WebString id_vector1[] = {WebString::FromASCII(kGroupID1), |
| WebString::FromASCII(kGroupID2)}; |
| advanced1.group_id.SetExact( |
| WebVector<WebString>(id_vector1, base::size(id_vector1))); |
| WebString id_vector2[] = {WebString::FromASCII(kGroupID2), |
| WebString::FromASCII(kGroupID3)}; |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.group_id.SetExact( |
| WebVector<WebString>(id_vector2, base::size(id_vector2))); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The device with group_id kGroupID2 must be selected because it is the only |
| // one that satisfies both advanced sets. |
| EXPECT_EQ(std::string(kDeviceID2), result.device_id()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryDeviceID) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| WebString id_vector1[] = {WebString::FromASCII(kDeviceID1), |
| WebString::FromASCII(kDeviceID2)}; |
| advanced1.device_id.SetExact( |
| WebVector<WebString>(id_vector1, base::size(id_vector1))); |
| WebString id_vector2[] = {WebString::FromASCII(kDeviceID3), |
| WebString::FromASCII(kDeviceID4)}; |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.device_id.SetExact( |
| WebVector<WebString>(id_vector2, base::size(id_vector2))); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. |
| EXPECT_EQ(std::string(kDeviceID1), result.device_id()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryDeviceIDAndResolution) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.device_id.SetExact({WebString(low_res_device_->device_id)}); |
| |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.device_id.SetExact({WebString(high_res_device_->device_id)}); |
| advanced2.width.SetMax(50); |
| advanced2.height.SetMax(50); |
| |
| WebMediaTrackConstraintSet& advanced3 = constraint_factory_.AddAdvanced(); |
| advanced3.width.SetExact(800); |
| advanced3.height.SetExact(600); |
| |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set, but the third set must be applied. |
| EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 800); |
| EXPECT_EQ(result.Height(), 600); |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryGroupID) { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| WebString id_vector1[] = {WebString::FromASCII(kGroupID1), |
| WebString::FromASCII(kGroupID2)}; |
| advanced1.group_id.SetExact( |
| WebVector<WebString>(id_vector1, base::size(id_vector1))); |
| WebString id_vector2[] = {WebString::FromASCII(kGroupID3), |
| WebString::FromASCII(kGroupID4)}; |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.group_id.SetExact( |
| WebVector<WebString>(id_vector2, base::size(id_vector2))); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set must be ignored because it contradicts the first |
| // set. |
| EXPECT_EQ(std::string(kDeviceID1), result.device_id()); |
| CheckTrackAdapterSettingsEqualsFormat(result); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedContradictoryAspectRatioWidth) { |
| { |
| constraint_factory_.Reset(); |
| WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); |
| advanced1.aspect_ratio.SetMin(17); |
| WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); |
| advanced2.width.SetMax(1); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The second advanced set cannot be satisfied because it contradicts the |
| // second set. The default device supports the first set and should be |
| // selected. |
| EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(*default_closest_format_, result.Format()); |
| EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width()); |
| EXPECT_EQ(std::round(result.Width() / 17.0), |
| result.track_adapter_settings().target_height()); |
| EXPECT_EQ(17, result.track_adapter_settings().min_aspect_ratio()); |
| EXPECT_EQ(result.Width(), |
| result.track_adapter_settings().max_aspect_ratio()); |
| CheckTrackAdapterSettingsEqualsFrameRate(result); |
| } |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedResize) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetIdeal(1); |
| constraint_factory_.basic().height.SetIdeal(1); |
| WebMediaTrackConstraintSet& advanced = constraint_factory_.AddAdvanced(); |
| |
| advanced.resize_mode.SetExact(WebString::FromASCII("none")); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // The native mode closest to 1x1 is 40x30 with the low-res device. |
| EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 40); |
| EXPECT_EQ(result.Height(), 30); |
| // No rescaling occurs due to the advanced constraint specifying resizeMode |
| // equal to "none". |
| EXPECT_FALSE(result.track_adapter_settings().target_size().has_value()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| AdvancedResolutionResizeFrameRate) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetExact(639); |
| |
| // This advanced set must be ignored because there are no native resolutions |
| // with width equal to 639. |
| WebMediaTrackConstraintSet& advanced = constraint_factory_.AddAdvanced(); |
| advanced.resize_mode.SetExact(WebString::FromASCII("none")); |
| advanced.frame_rate.SetExact(19.0); |
| |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| // Rescaling is enabled to satisfy the required resolution. |
| EXPECT_TRUE(result.track_adapter_settings().target_size().has_value()); |
| EXPECT_EQ(result.track_adapter_settings().target_width(), 639); |
| // Height gets adjusted as well to maintain the aspect ratio. |
| EXPECT_EQ(result.track_adapter_settings().target_height(), 479); |
| // Using native frame rate because the advanced set is ignored. |
| EXPECT_EQ(result.track_adapter_settings().max_frame_rate(), 0.0); |
| |
| // The low-res device at 640x480@30Hz is the |
| EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8()); |
| EXPECT_EQ(result.Width(), 640); |
| EXPECT_EQ(result.Height(), 480); |
| EXPECT_EQ(result.FrameRate(), 30.0); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, BasicContradictoryWidth) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetMin(10); |
| constraint_factory_.basic().width.SetMax(9); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().width.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, |
| BasicContradictoryWidthAspectRatio) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().width.SetMax(1); |
| constraint_factory_.basic().aspect_ratio.SetExact(100.0); |
| auto result = SelectSettings(); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_EQ(constraint_factory_.basic().aspect_ratio.GetName(), |
| result.failed_constraint_name()); |
| } |
| |
| // The "NoDevices" tests verify that the algorithm returns the expected result |
| // when there are no candidates to choose from. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, NoDevicesNoConstraints) { |
| constraint_factory_.Reset(); |
| VideoDeviceCaptureCapabilities capabilities; |
| auto result = SelectSettingsVideoDeviceCapture( |
| capabilities, constraint_factory_.CreateWebMediaConstraints()); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_TRUE(std::string(result.failed_constraint_name()).empty()); |
| } |
| |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, NoDevicesWithConstraints) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().height.SetExact(100); |
| VideoDeviceCaptureCapabilities capabilities; |
| auto result = SelectSettingsVideoDeviceCapture( |
| capabilities, constraint_factory_.CreateWebMediaConstraints()); |
| EXPECT_FALSE(result.HasValue()); |
| EXPECT_TRUE(std::string(result.failed_constraint_name()).empty()); |
| } |
| |
| // This test verifies that having a device that reports a frame rate lower than |
| // 1 fps works. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, InvalidFrameRateDevice) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().device_id.SetExact( |
| WebString(invalid_frame_rate_device_->device_id)); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(invalid_frame_rate_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(invalid_frame_rate_device_->formats[0].frame_rate, |
| result.FrameRate()); |
| EXPECT_EQ(result.FrameRate(), 0.0); |
| EXPECT_FALSE(result.min_frame_rate().has_value()); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| |
| // Select the second format with invalid frame rate. |
| constraint_factory_.basic().width.SetExact(500); |
| result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(invalid_frame_rate_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(invalid_frame_rate_device_->formats[1].frame_rate, |
| result.FrameRate()); |
| EXPECT_LT(result.FrameRate(), 1.0); |
| EXPECT_FALSE(result.min_frame_rate().has_value()); |
| EXPECT_FALSE(result.max_frame_rate().has_value()); |
| } |
| |
| // This test verifies that an inverted default resolution is not preferred over |
| // the actual default resolution. |
| TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, InvertedDefaultResolution) { |
| constraint_factory_.Reset(); |
| constraint_factory_.basic().device_id.SetExact( |
| WebString(high_res_device_->device_id)); |
| auto result = SelectSettings(); |
| EXPECT_TRUE(result.HasValue()); |
| EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id()); |
| EXPECT_EQ(result.Width(), MediaStreamVideoSource::kDefaultWidth); |
| EXPECT_EQ(result.Height(), MediaStreamVideoSource::kDefaultHeight); |
| } |
| |
| } // namespace blink |