blob: 80cce4b79a4197d339d87cd89d1fd66b93907c63 [file] [log] [blame]
// 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/stream/media_stream_constraints_util_audio.h"
#include <algorithm>
#include <cmath>
#include <utility>
#include <vector>
#include "base/strings/string_number_conversions.h"
#include "content/common/media/media_stream_controls.h"
#include "content/renderer/media/stream/media_stream_audio_source.h"
#include "content/renderer/media/stream/media_stream_constraints_util_sets.h"
#include "content/renderer/media/stream/media_stream_video_source.h"
#include "content/renderer/media/stream/processed_local_audio_source.h"
#include "media/base/limits.h"
#include "third_party/blink/public/platform/web_media_constraints.h"
#include "third_party/blink/public/platform/web_string.h"
namespace content {
namespace {
enum BoolConstraint {
// Constraints not related to audio processing.
HOTWORD_ENABLED,
DISABLE_LOCAL_ECHO,
RENDER_TO_ASSOCIATED_SINK,
// Constraints that enable/disable audio processing.
ECHO_CANCELLATION,
GOOG_ECHO_CANCELLATION,
// Constraints that control audio-processing behavior.
GOOG_AUDIO_MIRRORING,
GOOG_AUTO_GAIN_CONTROL,
GOOG_EXPERIMENTAL_ECHO_CANCELLATION,
GOOG_TYPING_NOISE_DETECTION,
GOOG_NOISE_SUPPRESSION,
GOOG_EXPERIMENTAL_NOISE_SUPPRESSION,
GOOG_BEAMFORMING,
GOOG_HIGHPASS_FILTER,
GOOG_EXPERIMENTAL_AUTO_GAIN_CONTROL,
NUM_BOOL_CONSTRAINTS
};
// This struct groups related fields or entries from AudioProcessingProperties,
// SingleDeviceCandidateSet::bool_sets_ and blink::WebMediaTrackConstraintSet.
struct AudioPropertyConstraintPair {
bool AudioProcessingProperties::* audio_property;
BoolConstraint bool_set_index;
};
// Boolean audio properties that are mapped directly to a boolean constraint
// and which are subject to the same processing.
const AudioPropertyConstraintPair kAudioPropertyConstraintMap[] = {
{&AudioProcessingProperties::goog_auto_gain_control,
GOOG_AUTO_GAIN_CONTROL},
{&AudioProcessingProperties::goog_experimental_echo_cancellation,
GOOG_EXPERIMENTAL_ECHO_CANCELLATION},
{&AudioProcessingProperties::goog_typing_noise_detection,
GOOG_TYPING_NOISE_DETECTION},
{&AudioProcessingProperties::goog_noise_suppression,
GOOG_NOISE_SUPPRESSION},
{&AudioProcessingProperties::goog_experimental_noise_suppression,
GOOG_EXPERIMENTAL_NOISE_SUPPRESSION},
{&AudioProcessingProperties::goog_beamforming, GOOG_BEAMFORMING},
{&AudioProcessingProperties::goog_highpass_filter, GOOG_HIGHPASS_FILTER},
{&AudioProcessingProperties::goog_experimental_auto_gain_control,
GOOG_EXPERIMENTAL_AUTO_GAIN_CONTROL}};
// TODO(guidou): Remove this function. http://crbug.com/796955
std::string MediaPointToString(const media::Point& point) {
std::string point_string;
point_string.append(base::NumberToString(point.x()));
point_string.append(" ");
point_string.append(base::NumberToString(point.y()));
point_string.append(" ");
point_string.append(base::NumberToString(point.z()));
return point_string;
}
// TODO(guidou): Remove this function. http://crbug.com/796955
std::string MediaPointsToString(const std::vector<media::Point>& points) {
std::string points_string;
if (!points.empty()) {
for (size_t i = 0; i < points.size() - 1; ++i) {
points_string.append(MediaPointToString(points[i]));
points_string.append(" ");
}
points_string.append(MediaPointToString(points.back()));
}
return points_string;
}
// Selects the best value from the nonempty |set|, subject to |constraint|. The
// first selection criteria is equality to |constraint.Ideal()|, followed by
// equality to |default_value|. There is always a single best value.
bool SelectBool(const DiscreteSet<bool>& set,
const blink::BooleanConstraint& constraint,
bool default_value) {
DCHECK(!set.IsEmpty());
if (constraint.HasIdeal() && set.Contains(constraint.Ideal()))
return constraint.Ideal();
if (set.is_universal())
return default_value;
DCHECK_EQ(set.elements().size(), 1U);
return set.FirstElement();
}
// Selects the best value from the nonempty |set|, subject to |constraint|. The
// only decision criteria is equality to |constraint.Ideal()|. If there is no
// single best value in |set|, returns nullopt.
base::Optional<bool> SelectOptionalBool(
const DiscreteSet<bool>& set,
const blink::BooleanConstraint& constraint) {
DCHECK(!set.IsEmpty());
if (constraint.HasIdeal() && set.Contains(constraint.Ideal()))
return constraint.Ideal();
if (set.is_universal())
return base::Optional<bool>();
DCHECK_EQ(set.elements().size(), 1U);
return set.FirstElement();
}
// Selects the best value from the nonempty |set|, subject to |constraint|. The
// first selection criteria is inclusion in |constraint.Ideal()|, followed by
// equality to |default_value|. There is always a single best value.
std::string SelectString(const DiscreteSet<std::string>& set,
const blink::StringConstraint& constraint,
const std::string& default_value) {
DCHECK(!set.IsEmpty());
if (constraint.HasIdeal()) {
for (const blink::WebString& ideal_candidate : constraint.Ideal()) {
std::string candidate = ideal_candidate.Utf8();
if (set.Contains(candidate))
return candidate;
}
}
if (set.Contains(default_value))
return default_value;
return set.FirstElement();
}
// Selects the best value from the nonempty |set|, subject to |constraint|. The
// only decision criteria is inclusion in |constraint.Ideal()|. If there is no
// single best value in |set|, returns nullopt.
base::Optional<std::string> SelectOptionalString(
const DiscreteSet<std::string>& set,
const blink::StringConstraint& constraint) {
DCHECK(!set.IsEmpty());
if (constraint.HasIdeal()) {
for (const auto& ideal_candidate : constraint.Ideal()) {
std::string candidate = ideal_candidate.Utf8();
if (set.Contains(candidate))
return candidate;
}
}
if (set.is_universal())
return base::Optional<std::string>();
return set.FirstElement();
}
bool SelectEnableSwEchoCancellation(
base::Optional<bool> echo_cancellation,
base::Optional<bool> goog_echo_cancellation,
const media::AudioParameters& audio_parameters,
bool default_audio_processing_value,
bool should_enable_experimental_hw_echo_cancellation) {
// If there is hardware echo cancellation, return false.
const bool has_hw_echo_canceller =
(audio_parameters.effects() & media::AudioParameters::ECHO_CANCELLER);
const bool has_experimental_hw_echo_canceller =
(audio_parameters.effects() &
media::AudioParameters::EXPERIMENTAL_ECHO_CANCELLER);
if (audio_parameters.IsValid() &&
(has_hw_echo_canceller ||
(has_experimental_hw_echo_canceller &&
should_enable_experimental_hw_echo_cancellation)))
return false;
DCHECK(echo_cancellation && goog_echo_cancellation
? *echo_cancellation == *goog_echo_cancellation
: true);
if (echo_cancellation)
return *echo_cancellation;
if (goog_echo_cancellation)
return *goog_echo_cancellation;
return default_audio_processing_value;
}
// This class represents all the candidates settings for a single audio device.
class SingleDeviceCandidateSet {
public:
explicit SingleDeviceCandidateSet(
const AudioDeviceCaptureCapability& capability)
: parameters_(capability.Parameters()) {
// If empty, all values for the deviceId constraint are allowed and
// |device_id_set_| is the universal set. Otherwise, limit |device_id_set_|
// to the known device ID.
if (!capability.DeviceID().empty())
device_id_set_ = DiscreteSet<std::string>({capability.DeviceID()});
MediaStreamAudioSource* source = capability.source();
if (!source)
return;
// Properties not related to audio processing.
bool_sets_[HOTWORD_ENABLED] =
DiscreteSet<bool>({source->hotword_enabled()});
bool_sets_[DISABLE_LOCAL_ECHO] =
DiscreteSet<bool>({source->disable_local_echo()});
bool_sets_[RENDER_TO_ASSOCIATED_SINK] =
DiscreteSet<bool>({source->RenderToAssociatedSinkEnabled()});
// Properties related with audio processing.
AudioProcessingProperties properties;
if (ProcessedLocalAudioSource* processed_source =
ProcessedLocalAudioSource::From(source)) {
properties = processed_source->audio_processing_properties();
} else {
properties.DisableDefaultProperties();
}
bool echo_cancellation_enabled = false;
if (properties.enable_sw_echo_cancellation) {
echo_cancellation_enabled = true;
} else if (properties.disable_hw_echo_cancellation) {
// Software and hardware echo cancellation disabled.
echo_cancellation_enabled = false;
} else {
// Software echo cancellation disabled, but hardware echo cancellation
// allowed. In this case, look at device parameters.
echo_cancellation_enabled = source->device().input.effects() &
media::AudioParameters::ECHO_CANCELLER;
}
bool_sets_[ECHO_CANCELLATION] =
DiscreteSet<bool>({echo_cancellation_enabled});
bool_sets_[GOOG_ECHO_CANCELLATION] = bool_sets_[ECHO_CANCELLATION];
bool_sets_[GOOG_AUDIO_MIRRORING] =
DiscreteSet<bool>({properties.goog_audio_mirroring});
for (auto& entry : kAudioPropertyConstraintMap) {
bool_sets_[entry.bool_set_index] =
DiscreteSet<bool>({properties.*entry.audio_property});
}
#if DCHECK_IS_ON()
for (const auto& bool_set : bool_sets_) {
DCHECK(!bool_set.is_universal());
DCHECK(!bool_set.IsEmpty());
}
#endif
// This fails with input strings that are equivalent to
// |properties.goog_array_geometry|, but not exactly equal to the string
// returned by MediaPointsToString().
// TODO(guidou): Change |goog_array_geometry_set_| to be a set of vectors of
// points instead of a set of strings. http://crbug.com/796955
std::string mic_positions =
MediaPointsToString(properties.goog_array_geometry);
goog_array_geometry_set_ = DiscreteSet<std::string>({mic_positions});
}
// Accessors
const char* failed_constraint_name() const { return failed_constraint_name_; }
const DiscreteSet<std::string>& device_id_set() const {
return device_id_set_;
}
bool IsEmpty() const { return failed_constraint_name_ != nullptr; }
void ApplyConstraintSet(
const blink::WebMediaTrackConstraintSet& constraint_set) {
device_id_set_ = device_id_set_.Intersection(
StringSetFromConstraint(constraint_set.device_id));
if (device_id_set_.IsEmpty()) {
failed_constraint_name_ = constraint_set.device_id.GetName();
return;
}
goog_array_geometry_set_ = goog_array_geometry_set_.Intersection(
StringSetFromConstraint(constraint_set.goog_array_geometry));
if (goog_array_geometry_set_.IsEmpty()) {
failed_constraint_name_ = constraint_set.goog_array_geometry.GetName();
return;
}
for (size_t i = 0; i < NUM_BOOL_CONSTRAINTS; ++i) {
bool_sets_[i] = bool_sets_[i].Intersection(
BoolSetFromConstraint(constraint_set.*kBlinkBoolConstraintFields[i]));
if (bool_sets_[i].IsEmpty()) {
failed_constraint_name_ =
(constraint_set.*kBlinkBoolConstraintFields[i]).GetName();
return;
}
}
// echoCancellation and googEchoCancellation constraints should not
// contradict each other. Mark the set as empty if they do.
DiscreteSet<bool> echo_cancellation_intersection =
bool_sets_[ECHO_CANCELLATION].Intersection(
bool_sets_[GOOG_ECHO_CANCELLATION]);
if (echo_cancellation_intersection.IsEmpty()) {
failed_constraint_name_ =
blink::WebMediaTrackConstraintSet().echo_cancellation.GetName();
return;
}
}
// Fitness function to support device selection. Based on
// https://w3c.github.io/mediacapture-main/#dfn-fitness-distance
double Fitness(
const blink::WebMediaTrackConstraintSet& constraint_set) const {
double fitness = 0.0;
if (constraint_set.device_id.HasIdeal()) {
for (const blink::WebString& ideal_value :
constraint_set.device_id.Ideal()) {
if (device_id_set_.Contains(ideal_value.Utf8())) {
fitness += 1.0;
break;
}
}
}
for (size_t i = 0; i < NUM_BOOL_CONSTRAINTS; ++i) {
if ((constraint_set.*kBlinkBoolConstraintFields[i]).HasIdeal() &&
bool_sets_[i].Contains(
(constraint_set.*kBlinkBoolConstraintFields[i]).Ideal())) {
fitness += 1.0;
}
}
if (constraint_set.goog_array_geometry.HasIdeal()) {
for (const blink::WebString& ideal_value :
constraint_set.goog_array_geometry.Ideal()) {
if (goog_array_geometry_set_.Contains(ideal_value.Utf8())) {
fitness += 1.0;
break;
}
}
}
return fitness;
}
// Returns the settings supported by this SingleDeviceCandidateSet that best
// satisfy the ideal values in |basic_constraint_set|.
AudioCaptureSettings SelectBestSettings(
const blink::WebMediaTrackConstraintSet& basic_constraint_set,
const std::string& default_device_id,
const std::string& media_stream_source,
bool should_disable_hardware_noise_suppression,
bool should_enable_experimental_hw_echo_cancellation) const {
std::string device_id = SelectString(
device_id_set_, basic_constraint_set.device_id, default_device_id);
bool hotword_enabled =
SelectBool(bool_sets_[HOTWORD_ENABLED],
basic_constraint_set.hotword_enabled, false);
bool disable_local_echo_default =
media_stream_source != kMediaStreamSourceDesktop;
bool disable_local_echo = SelectBool(
bool_sets_[DISABLE_LOCAL_ECHO], basic_constraint_set.disable_local_echo,
disable_local_echo_default);
bool render_to_associated_sink =
SelectBool(bool_sets_[RENDER_TO_ASSOCIATED_SINK],
basic_constraint_set.render_to_associated_sink, false);
bool is_device_capture = media_stream_source.empty();
AudioProcessingProperties audio_processing_properties =
SelectAudioProcessingProperties(
basic_constraint_set, is_device_capture,
should_disable_hardware_noise_suppression,
should_enable_experimental_hw_echo_cancellation);
return AudioCaptureSettings(
std::move(device_id), parameters_, hotword_enabled, disable_local_echo,
render_to_associated_sink, audio_processing_properties);
}
private:
// Returns the audio-processing properties supported by this
// SingleDeviceCandidateSet that best satisfy the ideal values in
// |basic_constraint_set|.
AudioProcessingProperties SelectAudioProcessingProperties(
const blink::WebMediaTrackConstraintSet& basic_constraint_set,
bool is_device_capture,
bool should_disable_hardware_noise_suppression,
bool should_enable_experimental_hw_echo_cancellation) const {
DCHECK(!IsEmpty());
base::Optional<bool> echo_cancellation = SelectOptionalBool(
bool_sets_[ECHO_CANCELLATION], basic_constraint_set.echo_cancellation);
// Audio-processing properties are disabled by default for content capture,
// or if the |echo_cancellation| constraint is false.
bool default_audio_processing_value = true;
if (!is_device_capture || (echo_cancellation && !*echo_cancellation))
default_audio_processing_value = false;
base::Optional<bool> goog_echo_cancellation =
SelectOptionalBool(bool_sets_[GOOG_ECHO_CANCELLATION],
basic_constraint_set.goog_echo_cancellation);
AudioProcessingProperties properties;
properties.disable_hw_echo_cancellation =
(echo_cancellation && !*echo_cancellation) ||
(goog_echo_cancellation && !*goog_echo_cancellation);
properties.enable_experimental_hw_echo_cancellation =
should_enable_experimental_hw_echo_cancellation &&
!properties.disable_hw_echo_cancellation;
properties.enable_sw_echo_cancellation = SelectEnableSwEchoCancellation(
echo_cancellation, goog_echo_cancellation, parameters_,
default_audio_processing_value,
properties.enable_experimental_hw_echo_cancellation);
properties.disable_hw_noise_suppression =
should_disable_hardware_noise_suppression &&
!properties.disable_hw_echo_cancellation;
properties.goog_audio_mirroring =
SelectBool(bool_sets_[GOOG_AUDIO_MIRRORING],
basic_constraint_set.goog_audio_mirroring,
properties.goog_audio_mirroring);
for (auto& entry : kAudioPropertyConstraintMap) {
properties.*entry.audio_property = SelectBool(
bool_sets_[entry.bool_set_index],
basic_constraint_set.*
kBlinkBoolConstraintFields[entry.bool_set_index],
default_audio_processing_value && properties.*entry.audio_property);
}
base::Optional<std::string> array_geometry = SelectOptionalString(
goog_array_geometry_set_, basic_constraint_set.goog_array_geometry);
std::vector<media::Point> parsed_positions;
if (array_geometry)
parsed_positions = media::ParsePointsFromString(*array_geometry);
bool are_valid_parsed_positions =
!parsed_positions.empty() ||
(array_geometry && array_geometry->empty());
properties.goog_array_geometry = are_valid_parsed_positions
? std::move(parsed_positions)
: parameters_.mic_positions();
return properties;
}
static constexpr blink::BooleanConstraint
blink::WebMediaTrackConstraintSet::* const
kBlinkBoolConstraintFields[NUM_BOOL_CONSTRAINTS] = {
&blink::WebMediaTrackConstraintSet::hotword_enabled,
&blink::WebMediaTrackConstraintSet::disable_local_echo,
&blink::WebMediaTrackConstraintSet::render_to_associated_sink,
&blink::WebMediaTrackConstraintSet::echo_cancellation,
&blink::WebMediaTrackConstraintSet::goog_echo_cancellation,
&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};
const char* failed_constraint_name_ = nullptr;
DiscreteSet<std::string> device_id_set_;
std::array<DiscreteSet<bool>, NUM_BOOL_CONSTRAINTS> bool_sets_;
DiscreteSet<std::string> goog_array_geometry_set_;
media::AudioParameters parameters_;
};
constexpr blink::BooleanConstraint blink::WebMediaTrackConstraintSet::* const
SingleDeviceCandidateSet::kBlinkBoolConstraintFields[NUM_BOOL_CONSTRAINTS];
// This class represents a set of possible candidate settings.
// The SelectSettings algorithm starts with a set containing all possible
// candidates based on hardware capabilities and/or allowed values for supported
// properties. The set is then reduced progressively as the basic and advanced
// constraint sets are applied.
// In the end, if the set of candidates is empty, SelectSettings fails.
// If not, the ideal values (if any) or tie breaker rules are used to select
// the final settings based on the candidates that survived the application
// of the constraint sets.
// This class is implemented as a collection of more specific sets for the
// various supported properties. If any of the specific sets is empty, the
// whole AudioCaptureCandidates set is considered empty as well.
class AudioCaptureCandidates {
public:
AudioCaptureCandidates(
const blink::WebMediaTrackConstraintSet& constraint_set,
const AudioDeviceCaptureCapabilities& capabilities) {
for (const auto& capability : capabilities)
candidate_sets_.emplace_back(capability);
ApplyConstraintSet(constraint_set);
}
const char* failed_constraint_name() const { return failed_constraint_name_; }
bool IsEmpty() const { return failed_constraint_name_ != nullptr; }
void ApplyConstraintSet(
const blink::WebMediaTrackConstraintSet& constraint_set) {
for (auto& candidate_set : candidate_sets_)
candidate_set.ApplyConstraintSet(constraint_set);
const char* failed_constraint_name = nullptr;
for (auto it = candidate_sets_.begin(); it != candidate_sets_.end();) {
if (it->IsEmpty()) {
DCHECK(it->failed_constraint_name());
failed_constraint_name = it->failed_constraint_name();
it = candidate_sets_.erase(it);
} else {
++it;
}
}
if (candidate_sets_.empty())
failed_constraint_name_ = failed_constraint_name;
}
// Returns the settings that best satisfy the ideal values in
// |basic_constraint_set| subject to the limitations of this
// AudioCaptureCandidates object.
AudioCaptureSettings SelectBestSettings(
const blink::WebMediaTrackConstraintSet& basic_constraint_set,
const std::string& default_device_id,
const std::string& media_stream_source,
bool should_disable_hardware_noise_suppression,
bool should_enable_experimental_hw_echo_cancellation) const {
const SingleDeviceCandidateSet* device_candidate_set =
SelectBestDevice(basic_constraint_set, default_device_id);
DCHECK(!device_candidate_set->IsEmpty());
return device_candidate_set->SelectBestSettings(
basic_constraint_set, default_device_id, media_stream_source,
should_disable_hardware_noise_suppression,
should_enable_experimental_hw_echo_cancellation);
}
private:
// Selects the best device based on the fitness function.
// The returned pointer is valid as long as |candidate_sets_| is not mutated.
const SingleDeviceCandidateSet* SelectBestDevice(
const blink::WebMediaTrackConstraintSet& constraint_set,
const std::string& default_device_id) const {
DCHECK(!candidate_sets_.empty());
auto best_candidate = candidate_sets_.end();
std::vector<double> best_fitness({-1, -1});
for (auto it = candidate_sets_.begin(); it != candidate_sets_.end(); ++it) {
DCHECK(!it->IsEmpty());
std::vector<double> fitness;
fitness.push_back(it->Fitness(constraint_set));
// Second selection criterion is being the default device.
fitness.push_back(it->device_id_set().Contains(default_device_id) ? 1.0
: 0.0);
if (fitness > best_fitness) {
best_fitness = fitness;
best_candidate = it;
}
}
return &(*best_candidate);
}
const char* failed_constraint_name_ = nullptr;
std::vector<SingleDeviceCandidateSet> candidate_sets_;
};
} // namespace
AudioDeviceCaptureCapability::AudioDeviceCaptureCapability()
: parameters_(media::AudioParameters::UnavailableDeviceParams()) {}
AudioDeviceCaptureCapability::AudioDeviceCaptureCapability(
MediaStreamAudioSource* source)
: source_(source) {}
AudioDeviceCaptureCapability::AudioDeviceCaptureCapability(
std::string device_id,
const media::AudioParameters& parameters)
: device_id_(std::move(device_id)), parameters_(parameters) {
DCHECK(!device_id_.empty());
}
const std::string& AudioDeviceCaptureCapability::DeviceID() const {
return source_ ? source_->device().id : device_id_;
}
const media::AudioParameters& AudioDeviceCaptureCapability::Parameters() const {
return source_ ? source_->device().input : parameters_;
}
AudioCaptureSettings SelectSettingsAudioCapture(
const AudioDeviceCaptureCapabilities& capabilities,
const blink::WebMediaConstraints& constraints,
bool should_disable_hardware_noise_suppression,
bool should_enable_experimental_hw_echo_cancellation) {
std::string media_stream_source = GetMediaStreamSource(constraints);
bool is_device_capture = media_stream_source.empty();
if (capabilities.empty())
return AudioCaptureSettings();
AudioCaptureCandidates candidates(constraints.Basic(), capabilities);
if (candidates.IsEmpty())
return AudioCaptureSettings(candidates.failed_constraint_name());
for (const auto& advanced_set : constraints.Advanced()) {
AudioCaptureCandidates copy = candidates;
candidates.ApplyConstraintSet(advanced_set);
if (candidates.IsEmpty())
candidates = std::move(copy);
}
DCHECK(!candidates.IsEmpty());
std::string default_device_id;
if (is_device_capture)
default_device_id = capabilities.begin()->DeviceID();
return candidates.SelectBestSettings(
constraints.Basic(), default_device_id, media_stream_source,
should_disable_hardware_noise_suppression,
should_enable_experimental_hw_echo_cancellation);
}
AudioCaptureSettings CONTENT_EXPORT
SelectSettingsAudioCapture(MediaStreamAudioSource* source,
const blink::WebMediaConstraints& constraints) {
DCHECK(source);
if (source->device().type != MEDIA_DEVICE_AUDIO_CAPTURE &&
source->device().type != MEDIA_TAB_AUDIO_CAPTURE &&
source->device().type != MEDIA_DESKTOP_AUDIO_CAPTURE) {
return AudioCaptureSettings();
}
std::string media_stream_source = GetMediaStreamSource(constraints);
if (source->device().type == MEDIA_DEVICE_AUDIO_CAPTURE &&
!media_stream_source.empty()) {
return AudioCaptureSettings(
constraints.Basic().media_stream_source.GetName());
}
if (source->device().type == MEDIA_TAB_AUDIO_CAPTURE &&
!media_stream_source.empty() &&
media_stream_source != kMediaStreamSourceTab) {
return AudioCaptureSettings(
constraints.Basic().media_stream_source.GetName());
}
if (source->device().type == MEDIA_DESKTOP_AUDIO_CAPTURE &&
!media_stream_source.empty() &&
media_stream_source != kMediaStreamSourceSystem &&
media_stream_source != kMediaStreamSourceDesktop) {
return AudioCaptureSettings(
constraints.Basic().media_stream_source.GetName());
}
AudioDeviceCaptureCapabilities capabilities = {
AudioDeviceCaptureCapability(source)};
bool should_disable_hardware_noise_suppression =
!(source->device().input.effects() &
media::AudioParameters::NOISE_SUPPRESSION);
return SelectSettingsAudioCapture(
capabilities, constraints, should_disable_hardware_noise_suppression,
/* should_enable_experimental_hw_echo_cancellation */ false);
}
} // namespace content