Index: content/renderer/media/media_stream_constraints_util_audio_unittest.cc |
diff --git a/content/renderer/media/media_stream_constraints_util_audio_unittest.cc b/content/renderer/media/media_stream_constraints_util_audio_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..db06ed6321677159f65b2a220b77c3d303ca64a6 |
--- /dev/null |
+++ b/content/renderer/media/media_stream_constraints_util_audio_unittest.cc |
@@ -0,0 +1,1396 @@ |
+// 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 "content/renderer/media/media_stream_constraints_util_audio.h" |
+ |
+#include <cmath> |
+#include <string> |
+#include <utility> |
+ |
+#include "content/common/media/media_devices.mojom.h" |
+#include "content/renderer/media/mock_constraint_factory.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "third_party/WebKit/public/platform/WebMediaConstraints.h" |
+#include "third_party/WebKit/public/platform/WebString.h" |
+ |
+namespace content { |
+ |
+namespace { |
+ |
+using BoolSetFunction = void (blink::BooleanConstraint::*)(bool); |
+using StringSetFunction = |
+ void (blink::StringConstraint::*)(const blink::WebString&); |
+using MockFactoryAccessor = |
+ blink::WebMediaTrackConstraintSet& (MockConstraintFactory::*)(); |
+ |
+const BoolSetFunction kBoolSetFunctions[] = { |
+ &blink::BooleanConstraint::SetExact, &blink::BooleanConstraint::SetIdeal, |
+}; |
+ |
+const StringSetFunction kStringSetFunctions[] = { |
+ &blink::StringConstraint::SetExact, &blink::StringConstraint::SetIdeal, |
+}; |
+ |
+const MockFactoryAccessor kFactoryAccessors[] = { |
+ &MockConstraintFactory::basic, &MockConstraintFactory::AddAdvanced}; |
+ |
+const bool kBoolValues[] = {true, false}; |
+ |
+using AudioSettingsBoolMembers = |
+ std::vector<bool (AudioCaptureSettings::*)() const>; |
+using AudioPropertiesBoolMembers = |
+ std::vector<bool AudioProcessingProperties::*>; |
+ |
+template <typename T> |
+static bool Contains(const std::vector<T>& vector, T value) { |
+ auto it = std::find(vector.begin(), vector.end(), value); |
+ return it != vector.end(); |
+} |
+ |
+} // namespace |
+ |
+class MediaStreamConstraintsUtilAudioTest |
+ : public testing::TestWithParam<std::string> { |
+ public: |
+ void SetUp() override { |
+ ResetFactory(); |
+ if (!IsDeviceCapture()) |
+ return; |
+ |
+ ::mojom::AudioInputDeviceCapabilitiesPtr device = |
+ ::mojom::AudioInputDeviceCapabilities::New(); |
+ device->device_id = "default_device"; |
+ device->parameters = media::AudioParameters( |
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ media::CHANNEL_LAYOUT_STEREO, |
+ media::AudioParameters::kAudioCDSampleRate, 16, 1000); |
+ capabilities_.push_back(std::move(device)); |
+ |
+ device = ::mojom::AudioInputDeviceCapabilities::New(); |
+ device->device_id = "mono_phone_device"; |
+ device->parameters = media::AudioParameters( |
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ media::CHANNEL_LAYOUT_MONO, |
+ media::AudioParameters::kTelephoneSampleRate, 16, 1000); |
+ capabilities_.push_back(std::move(device)); |
+ |
+ device = ::mojom::AudioInputDeviceCapabilities::New(); |
+ device->device_id = "hw_echo_canceller_device"; |
+ device->parameters = media::AudioParameters( |
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ media::CHANNEL_LAYOUT_STEREO, |
+ media::AudioParameters::kAudioCDSampleRate, 24, 1000); |
+ device->parameters.set_effects(media::AudioParameters::ECHO_CANCELLER); |
+ capabilities_.push_back(std::move(device)); |
+ |
+ device = ::mojom::AudioInputDeviceCapabilities::New(); |
+ device->device_id = "octagonal_device"; |
+ device->parameters = media::AudioParameters( |
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ media::CHANNEL_LAYOUT_OCTAGONAL, 100000, 8, 1000); |
+ capabilities_.push_back(std::move(device)); |
+ |
+ device = ::mojom::AudioInputDeviceCapabilities::New(); |
+ device->device_id = "geometry device"; |
+ device->parameters = media::AudioParameters( |
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ media::CHANNEL_LAYOUT_STEREO, |
+ media::AudioParameters::kAudioCDSampleRate, 16, 1000); |
+ device->parameters.set_mic_positions(kMicPositions); |
+ capabilities_.push_back(std::move(device)); |
+ |
+ default_device_ = capabilities_[0].get(); |
+ mono_phone_device_ = capabilities_[1].get(); |
+ hw_echo_canceller_device_ = capabilities_[2].get(); |
+ octagonal_device_ = capabilities_[3].get(); |
+ geometry_device_ = capabilities_[4].get(); |
+ } |
+ |
+ protected: |
+ void SetMediaStreamSource(const std::string& source) {} |
+ |
+ void ResetFactory() { |
+ constraint_factory_.Reset(); |
+ constraint_factory_.basic().media_stream_source.SetExact( |
+ blink::WebString::FromASCII(GetParam())); |
+ } |
+ |
+ std::string GetMediaStreamSource() { return GetParam(); } |
+ bool IsDeviceCapture() { return GetMediaStreamSource().empty(); } |
+ |
+ AudioCaptureSettings SelectSettings() { |
+ blink::WebMediaConstraints constraints = |
+ constraint_factory_.CreateWebMediaConstraints(); |
+ return SelectSettingsAudioCapture(capabilities_, constraints); |
+ } |
+ |
+ // When googExperimentalEchoCancellation is not explicitly set, its default |
+ // value is always false on Android. On other platforms it behaves like other |
+ // audio-processing properties. |
+ void CheckGoogExperimentalEchoCancellationDefault( |
+ const AudioProcessingProperties& properties, |
+ bool value) { |
+#if defined(OS_ANDROID) |
+ EXPECT_FALSE(properties.goog_experimental_echo_cancellation); |
+#else |
+ EXPECT_EQ(value, properties.goog_experimental_echo_cancellation); |
+#endif |
+ } |
+ |
+ void CheckBoolDefaultsDeviceCapture( |
+ const AudioSettingsBoolMembers& exclude_main_settings, |
+ const AudioPropertiesBoolMembers& exclude_audio_properties, |
+ const AudioCaptureSettings& result) { |
+ if (!Contains(exclude_main_settings, |
+ &AudioCaptureSettings::hotword_enabled)) { |
+ EXPECT_FALSE(result.hotword_enabled()); |
+ } |
+ if (!Contains(exclude_main_settings, |
+ &AudioCaptureSettings::disable_local_echo)) { |
+ EXPECT_TRUE(result.disable_local_echo()); |
+ } |
+ if (!Contains(exclude_main_settings, |
+ &AudioCaptureSettings::render_to_associated_sink)) { |
+ EXPECT_FALSE(result.render_to_associated_sink()); |
+ } |
+ |
+ const auto& properties = result.audio_processing_properties(); |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::enable_sw_echo_cancellation)) { |
+ EXPECT_TRUE(properties.enable_sw_echo_cancellation); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::disable_hw_echo_cancellation)) { |
+ EXPECT_FALSE(properties.disable_hw_echo_cancellation); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_audio_mirroring)) { |
+ EXPECT_FALSE(properties.goog_audio_mirroring); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_auto_gain_control)) { |
+ EXPECT_TRUE(properties.goog_auto_gain_control); |
+ } |
+ if (!Contains( |
+ exclude_audio_properties, |
+ &AudioProcessingProperties::goog_experimental_echo_cancellation)) { |
+ CheckGoogExperimentalEchoCancellationDefault(properties, true); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_typing_noise_detection)) { |
+ EXPECT_TRUE(properties.goog_typing_noise_detection); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_noise_suppression)) { |
+ EXPECT_TRUE(properties.goog_noise_suppression); |
+ } |
+ if (!Contains( |
+ exclude_audio_properties, |
+ &AudioProcessingProperties::goog_experimental_noise_suppression)) { |
+ EXPECT_TRUE(properties.goog_experimental_noise_suppression); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_beamforming)) { |
+ EXPECT_TRUE(properties.goog_beamforming); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_highpass_filter)) { |
+ EXPECT_TRUE(properties.goog_highpass_filter); |
+ } |
+ if (!Contains( |
+ exclude_audio_properties, |
+ &AudioProcessingProperties::goog_experimental_auto_gain_control)) { |
+ EXPECT_TRUE(properties.goog_experimental_auto_gain_control); |
+ } |
+ } |
+ |
+ void CheckBoolDefaultsContentCapture( |
+ const AudioSettingsBoolMembers& exclude_main_settings, |
+ const AudioPropertiesBoolMembers& exclude_audio_properties, |
+ const AudioCaptureSettings& result) { |
+ if (!Contains(exclude_main_settings, |
+ &AudioCaptureSettings::hotword_enabled)) { |
+ EXPECT_FALSE(result.hotword_enabled()); |
+ } |
+ if (!Contains(exclude_main_settings, |
+ &AudioCaptureSettings::disable_local_echo)) { |
+ EXPECT_EQ(GetMediaStreamSource() != kMediaStreamSourceDesktop, |
+ result.disable_local_echo()); |
+ } |
+ if (!Contains(exclude_main_settings, |
+ &AudioCaptureSettings::render_to_associated_sink)) { |
+ EXPECT_FALSE(result.render_to_associated_sink()); |
+ } |
+ |
+ const auto& properties = result.audio_processing_properties(); |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::enable_sw_echo_cancellation)) { |
+ EXPECT_FALSE(properties.enable_sw_echo_cancellation); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::disable_hw_echo_cancellation)) { |
+ EXPECT_FALSE(properties.disable_hw_echo_cancellation); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_audio_mirroring)) { |
+ EXPECT_FALSE(properties.goog_audio_mirroring); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_auto_gain_control)) { |
+ EXPECT_FALSE(properties.goog_auto_gain_control); |
+ } |
+ if (!Contains( |
+ exclude_audio_properties, |
+ &AudioProcessingProperties::goog_experimental_echo_cancellation)) { |
+ EXPECT_FALSE(properties.goog_experimental_echo_cancellation); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_typing_noise_detection)) { |
+ EXPECT_FALSE(properties.goog_typing_noise_detection); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_noise_suppression)) { |
+ EXPECT_FALSE(properties.goog_noise_suppression); |
+ } |
+ if (!Contains( |
+ exclude_audio_properties, |
+ &AudioProcessingProperties::goog_experimental_noise_suppression)) { |
+ EXPECT_FALSE(properties.goog_experimental_noise_suppression); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_beamforming)) { |
+ EXPECT_FALSE(properties.goog_beamforming); |
+ } |
+ if (!Contains(exclude_audio_properties, |
+ &AudioProcessingProperties::goog_highpass_filter)) { |
+ EXPECT_FALSE(properties.goog_highpass_filter); |
+ } |
+ if (!Contains( |
+ exclude_audio_properties, |
+ &AudioProcessingProperties::goog_experimental_auto_gain_control)) { |
+ EXPECT_FALSE(properties.goog_experimental_auto_gain_control); |
+ } |
+ } |
+ |
+ void CheckBoolDefaults( |
+ const AudioSettingsBoolMembers& exclude_main_settings, |
+ const AudioPropertiesBoolMembers& exclude_audio_properties, |
+ const AudioCaptureSettings& result) { |
+ if (IsDeviceCapture()) { |
+ CheckBoolDefaultsDeviceCapture(exclude_main_settings, |
+ exclude_audio_properties, result); |
+ } else { |
+ CheckBoolDefaultsContentCapture(exclude_main_settings, |
+ exclude_audio_properties, result); |
+ } |
+ } |
+ |
+ void CheckDevice(const mojom::AudioInputDeviceCapabilities& expected_device, |
+ const AudioCaptureSettings& result) { |
+ EXPECT_EQ(expected_device.device_id, result.device_id()); |
+ EXPECT_EQ(expected_device.parameters.sample_rate(), |
+ result.device_parameters().sample_rate()); |
+ EXPECT_EQ(expected_device.parameters.bits_per_sample(), |
+ result.device_parameters().bits_per_sample()); |
+ EXPECT_EQ(expected_device.parameters.channels(), |
+ result.device_parameters().channels()); |
+ EXPECT_EQ(expected_device.parameters.effects(), |
+ result.device_parameters().effects()); |
+ } |
+ |
+ void CheckDeviceDefaults(const AudioCaptureSettings& result) { |
+ if (IsDeviceCapture()) |
+ CheckDevice(*default_device_, result); |
+ else |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ |
+ void CheckGeometryDefaults(const AudioCaptureSettings& result) { |
+ EXPECT_TRUE( |
+ result.audio_processing_properties().goog_array_geometry.empty()); |
+ } |
+ |
+ void CheckAllDefaults( |
+ const AudioSettingsBoolMembers& exclude_main_settings, |
+ const AudioPropertiesBoolMembers& exclude_audio_properties, |
+ const AudioCaptureSettings& result) { |
+ CheckBoolDefaults(exclude_main_settings, exclude_audio_properties, result); |
+ CheckDeviceDefaults(result); |
+ CheckGeometryDefaults(result); |
+ } |
+ |
+ MockConstraintFactory constraint_factory_; |
+ AudioDeviceCaptureCapabilities capabilities_; |
+ const mojom::AudioInputDeviceCapabilities* default_device_ = nullptr; |
+ const mojom::AudioInputDeviceCapabilities* mono_phone_device_ = nullptr; |
+ const mojom::AudioInputDeviceCapabilities* hw_echo_canceller_device_ = |
+ nullptr; |
+ const mojom::AudioInputDeviceCapabilities* octagonal_device_ = nullptr; |
+ const mojom::AudioInputDeviceCapabilities* geometry_device_ = nullptr; |
+ const std::vector<media::Point> kMicPositions = {{8, 8, 8}, {4, 4, 4}}; |
+}; |
+ |
+// The Unconstrained test checks the default selection criteria. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, Unconstrained) { |
+ auto result = SelectSettings(); |
+ |
+ // All settings should have default values. |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckAllDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+} |
+ |
+// This test checks all possible ways to set boolean constraints (except |
+// echo cancellation constraints, which are not mapped 1:1 to output audio |
+// processing properties). |
+TEST_P(MediaStreamConstraintsUtilAudioTest, SingleBoolConstraint) { |
+ const AudioSettingsBoolMembers kMainSettings = { |
+ &AudioCaptureSettings::hotword_enabled, |
+ &AudioCaptureSettings::disable_local_echo, |
+ &AudioCaptureSettings::render_to_associated_sink}; |
+ |
+ const std::vector< |
+ blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*> |
+ kMainBoolConstraints = { |
+ &blink::WebMediaTrackConstraintSet::hotword_enabled, |
+ &blink::WebMediaTrackConstraintSet::disable_local_echo, |
+ &blink::WebMediaTrackConstraintSet::render_to_associated_sink}; |
+ |
+ ASSERT_EQ(kMainSettings.size(), kMainBoolConstraints.size()); |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (size_t i = 0; i < kMainSettings.size(); ++i) { |
+ for (bool value : kBoolValues) { |
+ ResetFactory(); |
+ (((constraint_factory_.*accessor)().*kMainBoolConstraints[i]).* |
+ set_function)(value); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_EQ(value, (result.*kMainSettings[i])()); |
+ CheckAllDefaults({kMainSettings[i]}, AudioPropertiesBoolMembers(), |
+ result); |
+ } |
+ } |
+ } |
+ } |
+ |
+ const AudioPropertiesBoolMembers kAudioProcessingProperties = { |
+ &AudioProcessingProperties::goog_audio_mirroring, |
+ &AudioProcessingProperties::goog_auto_gain_control, |
+ &AudioProcessingProperties::goog_experimental_echo_cancellation, |
+ &AudioProcessingProperties::goog_typing_noise_detection, |
+ &AudioProcessingProperties::goog_noise_suppression, |
+ &AudioProcessingProperties::goog_experimental_noise_suppression, |
+ &AudioProcessingProperties::goog_beamforming, |
+ &AudioProcessingProperties::goog_highpass_filter, |
+ &AudioProcessingProperties::goog_experimental_auto_gain_control}; |
+ |
+ const std::vector< |
+ blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*> |
+ kAudioProcessingConstraints = { |
+ &blink::WebMediaTrackConstraintSet::goog_audio_mirroring, |
+ &blink::WebMediaTrackConstraintSet::goog_auto_gain_control, |
+ &blink::WebMediaTrackConstraintSet:: |
+ goog_experimental_echo_cancellation, |
+ &blink::WebMediaTrackConstraintSet::goog_typing_noise_detection, |
+ &blink::WebMediaTrackConstraintSet::goog_noise_suppression, |
+ &blink::WebMediaTrackConstraintSet:: |
+ goog_experimental_noise_suppression, |
+ &blink::WebMediaTrackConstraintSet::goog_beamforming, |
+ &blink::WebMediaTrackConstraintSet::goog_highpass_filter, |
+ &blink::WebMediaTrackConstraintSet:: |
+ goog_experimental_auto_gain_control, |
+ }; |
+ |
+ ASSERT_EQ(kAudioProcessingProperties.size(), |
+ kAudioProcessingConstraints.size()); |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (size_t i = 0; i < kAudioProcessingProperties.size(); ++i) { |
+ for (bool value : kBoolValues) { |
+ ResetFactory(); |
+ (((constraint_factory_.*accessor)().*kAudioProcessingConstraints[i]).* |
+ set_function)(value); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_EQ(value, result.audio_processing_properties().* |
+ kAudioProcessingProperties[i]); |
+ CheckAllDefaults(AudioSettingsBoolMembers(), |
+ {kAudioProcessingProperties[i]}, result); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+// DeviceID tests. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactArbitraryDeviceID) { |
+ const std::string kArbitraryDeviceID = "arbitrary"; |
+ constraint_factory_.basic().device_id.SetExact( |
+ blink::WebString::FromASCII(kArbitraryDeviceID)); |
+ auto result = SelectSettings(); |
+ // kArbitraryDeviceID is invalid for device capture, but it is considered |
+ // valid for content capture. For content capture, validation of device |
+ // capture is performed by the getUserMedia() implementation. |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().device_id.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_EQ(kArbitraryDeviceID, result.device_id()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+// DeviceID tests check various ways to deal with the device_id constraint. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, IdealArbitraryDeviceID) { |
+ const std::string kArbitraryDeviceID = "arbitrary"; |
+ constraint_factory_.basic().device_id.SetIdeal( |
+ blink::WebString::FromASCII(kArbitraryDeviceID)); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ // kArbitraryDeviceID is invalid for device capture, but it is considered |
+ // valid for content capture. For content capture, validation of device |
+ // capture is performed by the getUserMedia() implementation. |
+ if (IsDeviceCapture()) |
+ CheckDeviceDefaults(result); |
+ else |
+ EXPECT_EQ(kArbitraryDeviceID, result.device_id()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactValidDeviceID) { |
+ for (const auto& device : capabilities_) { |
+ constraint_factory_.basic().device_id.SetExact( |
+ blink::WebString::FromASCII(device->device_id)); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckDevice(*device, result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), |
+ {&AudioProcessingProperties::enable_sw_echo_cancellation}, |
+ result); |
+ bool has_hw_echo_cancellation = |
+ device->parameters.effects() & media::AudioParameters::ECHO_CANCELLER; |
+ EXPECT_EQ(!has_hw_echo_cancellation, |
+ result.audio_processing_properties().enable_sw_echo_cancellation); |
+ if (&*device == geometry_device_) { |
+ EXPECT_EQ(kMicPositions, |
+ result.audio_processing_properties().goog_array_geometry); |
+ } else { |
+ CheckGeometryDefaults(result); |
+ } |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactValidSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetExact( |
+ media::AudioParameters::kTelephoneSampleRate); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ CheckDevice(*mono_phone_device_, result); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+// SampleRate, SampleSize, ChannelCount tests check that numeric device-related |
+// constraints are handled correctly. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactInvalidSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetExact(666); |
+ auto result = SelectSettings(); |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().sample_rate.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, MinValidSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetMin(80000); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one with a large-enough sample rate. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, MaxValidSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetMax(10000); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The mono device is the only one with a small-enough sample rate. |
+ CheckDevice(*mono_phone_device_, result); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, RangeValidSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetMin(1000); |
+ constraint_factory_.basic().sample_rate.SetMax(10000); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The mono device is the only one with a sample rate in the range. |
+ CheckDevice(*mono_phone_device_, result); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, InvalidRangeSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetMin(9000); |
+ constraint_factory_.basic().sample_rate.SetMax(10000); |
+ auto result = SelectSettings(); |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().sample_rate.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, IdealSampleRate) { |
+ constraint_factory_.basic().sample_rate.SetIdeal(10000); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The mono device is the one a sample rate closest to ideal. |
+ CheckDevice(*mono_phone_device_, result); |
+ } else { |
+ // Content capture ignores the sample_rate constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+// Sample size tests. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactValidSampleSize) { |
+ constraint_factory_.basic().sample_size.SetExact(8); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactInvalidSampleSize) { |
+ constraint_factory_.basic().sample_size.SetExact(666); |
+ auto result = SelectSettings(); |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().sample_size.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, MinValidSampleSize) { |
+ constraint_factory_.basic().sample_size.SetMin(20); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The device with echo canceller is the only one with a sample size that |
+ // is greater than the requested minimum. |
+ CheckDevice(*hw_echo_canceller_device_, result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), |
+ {&AudioProcessingProperties::enable_sw_echo_cancellation}, |
+ result); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ } |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, MaxValidSampleSize) { |
+ constraint_factory_.basic().sample_size.SetMax(10); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one with a small-enough sample size. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, RangeValidSampleSize) { |
+ constraint_factory_.basic().sample_size.SetMin(3); |
+ constraint_factory_.basic().sample_size.SetMax(15); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one with a sample size in the range. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, InvalidRangeSampleSize) { |
+ constraint_factory_.basic().sample_size.SetMin(10); |
+ constraint_factory_.basic().sample_size.SetMax(15); |
+ auto result = SelectSettings(); |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().sample_size.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, IdealSampleSize) { |
+ constraint_factory_.basic().sample_size.SetIdeal(10); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the one a sample size closest to ideal. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the sample_size constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+// ChannelCount tests. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactValidChannelCount) { |
+ constraint_factory_.basic().channel_count.SetExact(8); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ExactInvalidChannelCount) { |
+ constraint_factory_.basic().channel_count.SetExact(666); |
+ auto result = SelectSettings(); |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().channel_count.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, MinValidChannelCount) { |
+ constraint_factory_.basic().channel_count.SetMin(7); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The device with echo canceller is the only one with a channel count that |
+ // is greater than the requested minimum. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, MaxValidChannelCount) { |
+ constraint_factory_.basic().channel_count.SetMax(1); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one with a small-enough channel count. |
+ CheckDevice(*mono_phone_device_, result); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, RangeValidChannelCount) { |
+ constraint_factory_.basic().channel_count.SetMin(3); |
+ constraint_factory_.basic().channel_count.SetMax(15); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one with a channel count in the range. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, InvalidRangeChannelCount) { |
+ constraint_factory_.basic().channel_count.SetMin(3); |
+ constraint_factory_.basic().channel_count.SetMax(7); |
+ auto result = SelectSettings(); |
+ if (IsDeviceCapture()) { |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(std::string(constraint_factory_.basic().channel_count.GetName()), |
+ std::string(result.failed_constraint_name())); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_TRUE(result.device_id().empty()); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+ } |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, IdealChannelCount) { |
+ constraint_factory_.basic().channel_count.SetIdeal(6); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the one the number of channels closest to ideal. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores the channel_count constraint. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+// Tests the echoCancellation constraint with a device without hardware echo |
+// cancellation. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, EchoCancellationWithSw) { |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (bool value : kBoolValues) { |
+ ResetFactory(); |
+ ((constraint_factory_.*accessor)().echo_cancellation.* |
+ set_function)(value); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ const AudioProcessingProperties& properties = |
+ result.audio_processing_properties(); |
+ // With device capture, the echo_cancellation constraint |
+ // enables/disables all audio processing by default. |
+ // With content capture, the echo_cancellation constraint controls |
+ // only the echo_cancellation properties. The other audio processing |
+ // properties default to false. |
+ bool enable_sw_audio_processing = IsDeviceCapture() ? value : false; |
+ EXPECT_EQ(value, properties.enable_sw_echo_cancellation); |
+ EXPECT_EQ(!value, properties.disable_hw_echo_cancellation); |
+ EXPECT_EQ(enable_sw_audio_processing, |
+ properties.goog_auto_gain_control); |
+ CheckGoogExperimentalEchoCancellationDefault( |
+ properties, enable_sw_audio_processing); |
+ EXPECT_EQ(enable_sw_audio_processing, |
+ properties.goog_typing_noise_detection); |
+ EXPECT_EQ(enable_sw_audio_processing, |
+ properties.goog_noise_suppression); |
+ EXPECT_EQ(enable_sw_audio_processing, |
+ properties.goog_experimental_noise_suppression); |
+ EXPECT_EQ(enable_sw_audio_processing, properties.goog_beamforming); |
+ EXPECT_EQ(enable_sw_audio_processing, properties.goog_highpass_filter); |
+ EXPECT_EQ(enable_sw_audio_processing, |
+ properties.goog_experimental_auto_gain_control); |
+ |
+ // The following are not audio processing. |
+ EXPECT_FALSE(properties.goog_audio_mirroring); |
+ EXPECT_FALSE(result.hotword_enabled()); |
+ EXPECT_EQ(GetMediaStreamSource() != kMediaStreamSourceDesktop, |
+ result.disable_local_echo()); |
+ EXPECT_FALSE(result.render_to_associated_sink()); |
+ if (IsDeviceCapture()) { |
+ CheckDevice(*default_device_, result); |
+ } else { |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+// Tests the echoCancellation constraint with a device with hardware echo |
+// cancellation. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, EchoCancellationWithHw) { |
+ // With content capture, there is no hardware echo cancellation, so |
+ // nothing to test. |
+ if (!IsDeviceCapture()) |
+ return; |
+ |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (bool value : kBoolValues) { |
+ ResetFactory(); |
+ constraint_factory_.basic().device_id.SetExact( |
+ blink::WebString::FromASCII(hw_echo_canceller_device_->device_id)); |
+ ((constraint_factory_.*accessor)().echo_cancellation.* |
+ set_function)(value); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ const AudioProcessingProperties& properties = |
+ result.audio_processing_properties(); |
+ // With hardware echo cancellation, the echo_cancellation constraint |
+ // enables/disables all audio processing by default, software echo |
+ // cancellation is always disabled, and hardware echo cancellation is |
+ // disabled if the echo_cancellation constraint is false. |
+ EXPECT_FALSE(properties.enable_sw_echo_cancellation); |
+ EXPECT_EQ(!value, properties.disable_hw_echo_cancellation); |
+ EXPECT_EQ(value, properties.goog_auto_gain_control); |
+ CheckGoogExperimentalEchoCancellationDefault(properties, value); |
+ EXPECT_EQ(value, properties.goog_typing_noise_detection); |
+ EXPECT_EQ(value, properties.goog_noise_suppression); |
+ EXPECT_EQ(value, properties.goog_experimental_noise_suppression); |
+ EXPECT_EQ(value, properties.goog_beamforming); |
+ EXPECT_EQ(value, properties.goog_highpass_filter); |
+ EXPECT_EQ(value, properties.goog_experimental_auto_gain_control); |
+ |
+ // The following are not audio processing. |
+ EXPECT_FALSE(properties.goog_audio_mirroring); |
+ EXPECT_FALSE(result.hotword_enabled()); |
+ EXPECT_EQ(GetMediaStreamSource() != kMediaStreamSourceDesktop, |
+ result.disable_local_echo()); |
+ EXPECT_FALSE(result.render_to_associated_sink()); |
+ CheckDevice(*hw_echo_canceller_device_, result); |
+ } |
+ } |
+ } |
+} |
+ |
+// Tests the googEchoCancellation constraint with a device without hardware echo |
+// cancellation. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, GoogEchoCancellationWithSw) { |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (bool value : kBoolValues) { |
+ ResetFactory(); |
+ ((constraint_factory_.*accessor)().goog_echo_cancellation.* |
+ set_function)(value); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ const AudioProcessingProperties& properties = |
+ result.audio_processing_properties(); |
+ // The goog_echo_cancellation constraint controls only the |
+ // echo_cancellation properties. The other audio processing properties |
+ // use the default values. |
+ EXPECT_EQ(value, properties.enable_sw_echo_cancellation); |
+ EXPECT_EQ(!value, properties.disable_hw_echo_cancellation); |
+ CheckBoolDefaults( |
+ AudioSettingsBoolMembers(), |
+ { |
+ &AudioProcessingProperties::enable_sw_echo_cancellation, |
+ &AudioProcessingProperties::disable_hw_echo_cancellation, |
+ }, |
+ result); |
+ if (IsDeviceCapture()) { |
+ CheckDevice(*default_device_, result); |
+ } else { |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+// Tests the googEchoCancellation constraint with a device without hardware echo |
+// cancellation. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, GoogEchoCancellationWithHw) { |
+ // With content capture, there is no hardware echo cancellation, so |
+ // nothing to test. |
+ if (!IsDeviceCapture()) |
+ return; |
+ |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (bool value : kBoolValues) { |
+ ResetFactory(); |
+ constraint_factory_.basic().device_id.SetExact( |
+ blink::WebString::FromASCII(hw_echo_canceller_device_->device_id)); |
+ ((constraint_factory_.*accessor)().goog_echo_cancellation.* |
+ set_function)(value); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ const AudioProcessingProperties& properties = |
+ result.audio_processing_properties(); |
+ // With hardware echo cancellation, software echo cancellation is always |
+ // disabled, and hardware echo cancellation is disabled if |
+ // goog_echo_cancellation is false. |
+ EXPECT_FALSE(properties.enable_sw_echo_cancellation); |
+ EXPECT_EQ(!value, properties.disable_hw_echo_cancellation); |
+ CheckBoolDefaults( |
+ AudioSettingsBoolMembers(), |
+ { |
+ &AudioProcessingProperties::enable_sw_echo_cancellation, |
+ &AudioProcessingProperties::disable_hw_echo_cancellation, |
+ }, |
+ result); |
+ CheckDevice(*hw_echo_canceller_device_, result); |
+ } |
+ } |
+ } |
+} |
+ |
+// Test that having differing mandatory values for echoCancellation and |
+// googEchoCancellation fails. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ContradictoryEchoCancellation) { |
+ for (bool value : kBoolValues) { |
+ constraint_factory_.basic().echo_cancellation.SetExact(value); |
+ constraint_factory_.basic().goog_echo_cancellation.SetExact(!value); |
+ auto result = SelectSettings(); |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_EQ(result.failed_constraint_name(), |
+ constraint_factory_.basic().echo_cancellation.GetName()); |
+ } |
+} |
+ |
+// Tests that individual boolean audio-processing constraints override the |
+// default value set by the echoCancellation constraint. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, |
+ EchoCancellationAndSingleBoolConstraint) { |
+ const AudioPropertiesBoolMembers kAudioProcessingProperties = { |
+ &AudioProcessingProperties::goog_audio_mirroring, |
+ &AudioProcessingProperties::goog_auto_gain_control, |
+ &AudioProcessingProperties::goog_experimental_echo_cancellation, |
+ &AudioProcessingProperties::goog_typing_noise_detection, |
+ &AudioProcessingProperties::goog_noise_suppression, |
+ &AudioProcessingProperties::goog_experimental_noise_suppression, |
+ &AudioProcessingProperties::goog_beamforming, |
+ &AudioProcessingProperties::goog_highpass_filter, |
+ &AudioProcessingProperties::goog_experimental_auto_gain_control}; |
+ |
+ const std::vector< |
+ blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*> |
+ kAudioProcessingConstraints = { |
+ &blink::WebMediaTrackConstraintSet::goog_audio_mirroring, |
+ &blink::WebMediaTrackConstraintSet::goog_auto_gain_control, |
+ &blink::WebMediaTrackConstraintSet:: |
+ goog_experimental_echo_cancellation, |
+ &blink::WebMediaTrackConstraintSet::goog_typing_noise_detection, |
+ &blink::WebMediaTrackConstraintSet::goog_noise_suppression, |
+ &blink::WebMediaTrackConstraintSet:: |
+ goog_experimental_noise_suppression, |
+ &blink::WebMediaTrackConstraintSet::goog_beamforming, |
+ &blink::WebMediaTrackConstraintSet::goog_highpass_filter, |
+ &blink::WebMediaTrackConstraintSet:: |
+ goog_experimental_auto_gain_control, |
+ }; |
+ |
+ ASSERT_EQ(kAudioProcessingProperties.size(), |
+ kAudioProcessingConstraints.size()); |
+ for (auto set_function : kBoolSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == &blink::BooleanConstraint::SetIdeal && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ for (size_t i = 0; i < kAudioProcessingProperties.size(); ++i) { |
+ ResetFactory(); |
+ ((constraint_factory_.*accessor)().echo_cancellation.* |
+ set_function)(false); |
+ (((constraint_factory_.*accessor)().*kAudioProcessingConstraints[i]).* |
+ set_function)(true); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ EXPECT_FALSE( |
+ result.audio_processing_properties().enable_sw_echo_cancellation); |
+ EXPECT_TRUE( |
+ result.audio_processing_properties().disable_hw_echo_cancellation); |
+ EXPECT_TRUE(result.audio_processing_properties().* |
+ kAudioProcessingProperties[i]); |
+ for (size_t j = 0; j < kAudioProcessingProperties.size(); ++j) { |
+ if (i == j) |
+ continue; |
+ EXPECT_FALSE(result.audio_processing_properties().* |
+ kAudioProcessingProperties[j]); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+// Test advanced constraints sets that can be satisfied. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, AdvancedCompatibleConstraints) { |
+ constraint_factory_.AddAdvanced().sample_size.SetExact(8); |
+ constraint_factory_.AddAdvanced().render_to_associated_sink.SetExact(true); |
+ constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one that matches the first advanced |
+ // constraint set. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores device-related constraints. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults({&AudioCaptureSettings::render_to_associated_sink}, |
+ {&AudioProcessingProperties::goog_audio_mirroring}, result); |
+ CheckGeometryDefaults(result); |
+ EXPECT_TRUE(result.render_to_associated_sink()); |
+ EXPECT_TRUE(result.audio_processing_properties().goog_audio_mirroring); |
+} |
+ |
+// Test that an advanced constraint set that cannot be satisfied is ignored. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, AdvancedSelfConflictingConstraint) { |
+ auto& advanced = constraint_factory_.AddAdvanced(); |
+ advanced.sample_size.SetExact(8); |
+ advanced.sample_rate.SetExact(8); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ // The advanced constraint is self conflicting and ignored. The default |
+ // device is selected. |
+ CheckDeviceDefaults(result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+// Test that an advanced constraint set that contradicts a previous constraint |
+// set with a device-related constraint is ignored. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, |
+ AdvancedConflictingDeviceConstraint) { |
+ constraint_factory_.AddAdvanced().sample_size.SetExact(8); |
+ constraint_factory_.AddAdvanced().sample_size.SetExact( |
+ media::AudioParameters::kAudioCDSampleRate); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one that matches the first advanced |
+ // constraint set. The second set is ignored. |
+ CheckDevice(*octagonal_device_, result); |
+ EXPECT_NE(media::AudioParameters::kAudioCDSampleRate, |
+ result.device_parameters().sample_rate()); |
+ } else { |
+ // Content capture ignores device-related constraints. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ CheckGeometryDefaults(result); |
+} |
+ |
+// Test that an advanced constraint set that contradicts a previous constraint |
+// set is ignored, but that further constraint sets that can be satisfied are |
+// applied. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, |
+ AdvancedConflictingMiddleConstraints) { |
+ constraint_factory_.AddAdvanced().sample_size.SetExact(8); |
+ auto& advanced2 = constraint_factory_.AddAdvanced(); |
+ advanced2.sample_rate.SetExact(123456); |
+ advanced2.hotword_enabled.SetExact(true); |
+ constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one that matches the first advanced |
+ // constraint set. |
+ CheckDevice(*octagonal_device_, result); |
+ // Second advanced set is discarded because no device has the requested |
+ // sample rate. |
+ EXPECT_NE(123456, result.device_parameters().sample_rate()); |
+ EXPECT_FALSE(result.hotword_enabled()); |
+ } else { |
+ // Content capture ignores device-related constraints. Thus, it does not |
+ // discard the second advanced set. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ EXPECT_TRUE(result.hotword_enabled()); |
+ } |
+ CheckBoolDefaults({&AudioCaptureSettings::render_to_associated_sink, |
+ &AudioCaptureSettings::hotword_enabled}, |
+ {&AudioProcessingProperties::goog_audio_mirroring}, result); |
+ CheckGeometryDefaults(result); |
+ EXPECT_TRUE(result.audio_processing_properties().goog_audio_mirroring); |
+} |
+ |
+// Test that an advanced constraint set that contradicts a previous constraint |
+// set with a boolean constraint is ignored. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, AdvancedConflictingLastConstraint) { |
+ constraint_factory_.AddAdvanced().sample_size.SetExact(8); |
+ constraint_factory_.AddAdvanced().hotword_enabled.SetExact(true); |
+ constraint_factory_.AddAdvanced().goog_audio_mirroring.SetExact(true); |
+ constraint_factory_.AddAdvanced().hotword_enabled.SetExact(false); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ if (IsDeviceCapture()) { |
+ // The octagonal device is the only one that matches the first advanced |
+ // constraint set. |
+ CheckDevice(*octagonal_device_, result); |
+ } else { |
+ // Content capture ignores device-related constraints. |
+ EXPECT_TRUE(result.device_id().empty()); |
+ } |
+ CheckBoolDefaults({&AudioCaptureSettings::hotword_enabled}, |
+ {&AudioProcessingProperties::goog_audio_mirroring}, result); |
+ CheckGeometryDefaults(result); |
+ // The fourth advanced set is ignored because it contradicts the second set. |
+ EXPECT_TRUE(result.hotword_enabled()); |
+ EXPECT_TRUE(result.audio_processing_properties().goog_audio_mirroring); |
+} |
+ |
+// Test that a valid geometry is interpreted correctly in all the ways it can |
+// be set. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, ValidGeometry) { |
+ const blink::WebString kGeometry = |
+ blink::WebString::FromASCII("-0.02 0 0 0.02 0 1.01"); |
+ |
+ for (auto set_function : kStringSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ // Using kStringSetFunctions[1] instead of |
+ // static_cast<StringSetFunction>(&blink::StringConstraint::SetIdeal) |
+ // because the equality comparison provides the wrong result in the |
+ // Windows Debug build, making the test fail. |
hbos_chromium
2017/06/14 08:12:12
lol wtf
|
+ if (set_function == kStringSetFunctions[1] && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ ResetFactory(); |
+ ((constraint_factory_.*accessor)().goog_array_geometry.* |
+ set_function)(kGeometry); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckDeviceDefaults(result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), |
+ AudioPropertiesBoolMembers(), result); |
+ const std::vector<media::Point>& geometry = |
+ result.audio_processing_properties().goog_array_geometry; |
+ EXPECT_EQ(2u, geometry.size()); |
+ EXPECT_EQ(media::Point(-0.02, 0, 0), geometry[0]); |
+ EXPECT_EQ(media::Point(0.02, 0, 1.01), geometry[1]); |
+ } |
+ } |
+} |
+ |
+// Test that an invalid geometry is interpreted as empty in all the ways it can |
+// be set. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, InvalidGeometry) { |
+ const blink::WebString kGeometry = |
+ blink::WebString::FromASCII("1 1 1 invalid"); |
+ |
+ for (auto set_function : kStringSetFunctions) { |
+ for (auto accessor : kFactoryAccessors) { |
+ // Ideal advanced is ignored by the SelectSettings algorithm. |
+ if (set_function == static_cast<StringSetFunction>( |
+ &blink::StringConstraint::SetIdeal) && |
+ accessor == &MockConstraintFactory::AddAdvanced) { |
+ continue; |
+ } |
+ ResetFactory(); |
+ ((constraint_factory_.*accessor)().goog_array_geometry.* |
+ set_function)(kGeometry); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckDeviceDefaults(result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), |
+ AudioPropertiesBoolMembers(), result); |
+ const std::vector<media::Point>& geometry = |
+ result.audio_processing_properties().goog_array_geometry; |
+ EXPECT_EQ(0u, geometry.size()); |
+ } |
+ } |
+} |
+ |
+// Test that an invalid geometry is interpreted as empty in all the ways it can |
+// be set. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, DeviceGeometry) { |
+ if (!IsDeviceCapture()) |
+ return; |
+ |
+ constraint_factory_.basic().device_id.SetExact( |
+ blink::WebString::FromASCII(geometry_device_->device_id)); |
+ |
+ { |
+ const blink::WebString kValidGeometry = |
+ blink::WebString::FromASCII("-0.02 0 0 0.02 0 1.01"); |
+ constraint_factory_.basic().goog_array_geometry.SetExact(kValidGeometry); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckDevice(*geometry_device_, result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ // Constraints geometry should be preferred over device geometry. |
+ const std::vector<media::Point>& geometry = |
+ result.audio_processing_properties().goog_array_geometry; |
+ EXPECT_EQ(2u, geometry.size()); |
+ EXPECT_EQ(media::Point(-0.02, 0, 0), geometry[0]); |
+ EXPECT_EQ(media::Point(0.02, 0, 1.01), geometry[1]); |
+ } |
+ |
+ { |
+ constraint_factory_.basic().goog_array_geometry.SetExact( |
+ blink::WebString()); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckDevice(*geometry_device_, result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ // Empty geometry is valid and should be preferred over device geometry. |
+ EXPECT_TRUE( |
+ result.audio_processing_properties().goog_array_geometry.empty()); |
+ } |
+ |
+ { |
+ const blink::WebString kInvalidGeometry = |
+ blink::WebString::FromASCII("1 1 1 invalid"); |
+ constraint_factory_.basic().goog_array_geometry.SetExact(kInvalidGeometry); |
+ auto result = SelectSettings(); |
+ EXPECT_TRUE(result.HasValue()); |
+ CheckDevice(*geometry_device_, result); |
+ CheckBoolDefaults(AudioSettingsBoolMembers(), AudioPropertiesBoolMembers(), |
+ result); |
+ // Device geometry should be preferred over invalid constraints geometry. |
+ EXPECT_EQ(kMicPositions, |
+ result.audio_processing_properties().goog_array_geometry); |
+ } |
+} |
+ |
+// NoDevices tests verify that the case with no devices is handled correctly. |
+TEST_P(MediaStreamConstraintsUtilAudioTest, NoDevicesNoConstraints) { |
+ // This test makes sense only for device capture. |
+ if (!IsDeviceCapture()) |
+ return; |
+ |
+ AudioDeviceCaptureCapabilities capabilities; |
+ auto result = SelectSettingsAudioCapture( |
+ capabilities, constraint_factory_.CreateWebMediaConstraints()); |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_TRUE(std::string(result.failed_constraint_name()).empty()); |
+} |
+ |
+TEST_P(MediaStreamConstraintsUtilAudioTest, NoDevicesWithConstraints) { |
+ // This test makes sense only for device capture. |
+ if (!IsDeviceCapture()) |
+ return; |
+ |
+ AudioDeviceCaptureCapabilities capabilities; |
+ constraint_factory_.basic().sample_size.SetExact(16); |
+ auto result = SelectSettingsAudioCapture( |
+ capabilities, constraint_factory_.CreateWebMediaConstraints()); |
+ EXPECT_FALSE(result.HasValue()); |
+ EXPECT_TRUE(std::string(result.failed_constraint_name()).empty()); |
+} |
+ |
+INSTANTIATE_TEST_CASE_P(, |
+ MediaStreamConstraintsUtilAudioTest, |
+ testing::Values("", |
+ kMediaStreamSourceTab, |
+ kMediaStreamSourceSystem, |
+ kMediaStreamSourceDesktop)); |
+ |
+} // namespace content |