Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: content/renderer/media/media_stream_constraints_util_audio.cc

Issue 2941553003: Reland "SelectSettings algorithm for audio constraints." (Closed)
Patch Set: fix test Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/media_stream_constraints_util_audio.h"
6
7 #include <algorithm>
8 #include <cmath>
9 #include <utility>
10 #include <vector>
11
12 #include "content/common/media/media_stream_options.h"
13 #include "content/renderer/media/media_stream_constraints_util_sets.h"
14 #include "content/renderer/media/media_stream_video_source.h"
15 #include "media/base/limits.h"
16 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
17 #include "third_party/WebKit/public/platform/WebString.h"
18
19 namespace content {
20
21 namespace {
22
23 // This class has the same data as ::mojom::AudioInputDeviceCapabilities, but
24 // adds extra operations to simplify the device-selection code.
25 class AudioDeviceInfo {
26 public:
27 // This constructor is intended for device capture.
28 explicit AudioDeviceInfo(
29 const ::mojom::AudioInputDeviceCapabilitiesPtr& device_info)
30 : device_id_(device_info->device_id),
31 parameters_(device_info->parameters) {
32 DCHECK(parameters_.IsValid());
33 }
34
35 // This constructor is intended for content capture, where constraints on
36 // audio parameters are not supported.
37 explicit AudioDeviceInfo(std::string device_id)
38 : device_id_(std::move(device_id)) {}
39
40 bool operator==(const AudioDeviceInfo& other) const {
41 return device_id_ == other.device_id_;
42 }
43
44 // Accessors
45 const std::string& device_id() const { return device_id_; }
46 const media::AudioParameters& parameters() const { return parameters_; }
47
48 // Convenience accessors
49 int SampleRate() const {
50 DCHECK(parameters_.IsValid());
51 return parameters_.sample_rate();
52 }
53 int SampleSize() const {
54 DCHECK(parameters_.IsValid());
55 return parameters_.bits_per_sample();
56 }
57 int ChannelCount() const {
58 DCHECK(parameters_.IsValid());
59 return parameters_.channels();
60 }
61 int Effects() const {
62 DCHECK(parameters_.IsValid());
63 return parameters_.effects();
64 }
65
66 private:
67 std::string device_id_;
68 media::AudioParameters parameters_;
69 };
70
71 using AudioDeviceSet = DiscreteSet<AudioDeviceInfo>;
72
73 AudioDeviceSet AudioDeviceSetForDeviceCapture(
74 const blink::WebMediaTrackConstraintSet& constraint_set,
75 const AudioDeviceCaptureCapabilities& capabilities,
76 const char** failed_constraint_name) {
77 std::vector<AudioDeviceInfo> result;
78 *failed_constraint_name = "";
79 for (auto& device_capabilities : capabilities) {
80 if (!constraint_set.device_id.Matches(
81 blink::WebString::FromASCII(device_capabilities->device_id))) {
82 if (failed_constraint_name)
83 *failed_constraint_name = constraint_set.device_id.GetName();
84 continue;
85 }
86 *failed_constraint_name =
87 IsOutsideConstraintRange(constraint_set.sample_rate,
88 device_capabilities->parameters.sample_rate());
89 if (*failed_constraint_name)
90 continue;
91
92 *failed_constraint_name = IsOutsideConstraintRange(
93 constraint_set.sample_size,
94 device_capabilities->parameters.bits_per_sample());
95 if (*failed_constraint_name)
96 continue;
97
98 *failed_constraint_name =
99 IsOutsideConstraintRange(constraint_set.channel_count,
100 device_capabilities->parameters.channels());
101 if (*failed_constraint_name)
102 continue;
103
104 result.push_back(AudioDeviceInfo(device_capabilities));
105 }
106
107 if (!result.empty())
108 *failed_constraint_name = nullptr;
109
110 return AudioDeviceSet(result);
111 }
112
113 AudioDeviceSet AudioDeviceSetForContentCapture(
114 const blink::WebMediaTrackConstraintSet& constraint_set,
115 const char** failed_constraint_name = nullptr) {
116 if (!constraint_set.device_id.HasExact())
117 return AudioDeviceSet::UniversalSet();
118
119 std::vector<AudioDeviceInfo> result;
120 for (auto& device_id : constraint_set.device_id.Exact())
121 result.push_back(AudioDeviceInfo(device_id.Utf8()));
122
123 return AudioDeviceSet(result);
124 }
125
126 // This class represents a set of possible candidate settings.
127 // The SelectSettings algorithm starts with a set containing all possible
128 // candidates based on hardware capabilities and/or allowed values for supported
129 // properties. The is then reduced progressively as the basic and advanced
130 // constraint sets are applied.
131 // In the end, if the set of candidates is empty, SelectSettings fails.
132 // If not, the ideal values (if any) or tie breaker rules are used to select
133 // the final settings based on the candidates that survived the application
134 // of the constraint sets.
135 // This class is implemented as a collection of more specific sets for the
136 // various supported properties. If any of the specific sets is empty, the
137 // whole AudioCaptureCandidates set is considered empty as well.
138 class AudioCaptureCandidates {
139 public:
140 enum BoolConstraint {
141 // Constraints not related to audio processing.
142 HOTWORD_ENABLED,
143 DISABLE_LOCAL_ECHO,
144 RENDER_TO_ASSOCIATED_SINK,
145
146 // Constraints that enable/disable audio processing.
147 ECHO_CANCELLATION,
148 GOOG_ECHO_CANCELLATION,
149
150 // Constraints that control audio-processing behavior.
151 GOOG_AUDIO_MIRRORING,
152 GOOG_AUTO_GAIN_CONTROL,
153 GOOG_EXPERIMENTAL_ECHO_CANCELLATION,
154 GOOG_TYPING_NOISE_DETECTION,
155 GOOG_NOISE_SUPPRESSION,
156 GOOG_EXPERIMENTAL_NOISE_SUPPRESSION,
157 GOOG_BEAMFORMING,
158 GOOG_HIGHPASS_FILTER,
159 GOOG_EXPERIMENTAL_AUTO_GAIN_CONTROL,
160 NUM_BOOL_CONSTRAINTS
161 };
162
163 AudioCaptureCandidates();
164
165 AudioCaptureCandidates(
166 const blink::WebMediaTrackConstraintSet& constraint_set,
167 const AudioDeviceCaptureCapabilities& capabilities,
168 bool is_device_capture);
169
170 // Set operations.
171 bool IsEmpty() const { return failed_constraint_name_ != nullptr; }
172 AudioCaptureCandidates Intersection(const AudioCaptureCandidates& other);
173
174 // Accessors.
175 const char* failed_constraint_name() const { return failed_constraint_name_; }
176 const AudioDeviceSet& audio_device_set() const { return audio_device_set_; }
177 const DiscreteSet<std::string>& goog_array_geometry_set() const {
178 return goog_array_geometry_set_;
179 }
180
181 // Accessor for boolean sets.
182 const DiscreteSet<bool>& GetBoolSet(BoolConstraint property) const {
183 DCHECK_GE(property, 0);
184 DCHECK_LT(property, NUM_BOOL_CONSTRAINTS);
185 return bool_sets_[property];
186 }
187
188 // Convenience accessors.
189 const DiscreteSet<bool>& hotword_enabled_set() const {
190 return bool_sets_[HOTWORD_ENABLED];
191 }
192 const DiscreteSet<bool>& disable_local_echo_set() const {
193 return bool_sets_[DISABLE_LOCAL_ECHO];
194 }
195 const DiscreteSet<bool>& render_to_associated_sink_set() const {
196 return bool_sets_[RENDER_TO_ASSOCIATED_SINK];
197 }
198 const DiscreteSet<bool>& echo_cancellation_set() const {
199 return bool_sets_[ECHO_CANCELLATION];
200 }
201 const DiscreteSet<bool>& goog_echo_cancellation_set() const {
202 return bool_sets_[GOOG_ECHO_CANCELLATION];
203 }
204 const DiscreteSet<bool>& goog_audio_mirroring_set() const {
205 return bool_sets_[GOOG_AUDIO_MIRRORING];
206 }
207
208 private:
209 void MaybeUpdateFailedNonDeviceConstraintName();
210 void CheckContradictoryEchoCancellation();
211
212 // Maps BoolConstraint values to fields in blink::WebMediaTrackConstraintSet.
213 static const blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*
214 kBlinkBoolConstraintFields[NUM_BOOL_CONSTRAINTS];
215
216 const char* failed_constraint_name_;
217
218 AudioDeviceSet audio_device_set_; // Device-related constraints.
219 std::array<DiscreteSet<bool>, NUM_BOOL_CONSTRAINTS> bool_sets_;
220 DiscreteSet<std::string> goog_array_geometry_set_;
221 };
222
223 const blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*
224 AudioCaptureCandidates::kBlinkBoolConstraintFields[NUM_BOOL_CONSTRAINTS] = {
225 &blink::WebMediaTrackConstraintSet::hotword_enabled,
226 &blink::WebMediaTrackConstraintSet::disable_local_echo,
227 &blink::WebMediaTrackConstraintSet::render_to_associated_sink,
228 &blink::WebMediaTrackConstraintSet::echo_cancellation,
229 &blink::WebMediaTrackConstraintSet::goog_echo_cancellation,
230 &blink::WebMediaTrackConstraintSet::goog_audio_mirroring,
231 &blink::WebMediaTrackConstraintSet::goog_auto_gain_control,
232 &blink::WebMediaTrackConstraintSet::goog_experimental_echo_cancellation,
233 &blink::WebMediaTrackConstraintSet::goog_typing_noise_detection,
234 &blink::WebMediaTrackConstraintSet::goog_noise_suppression,
235 &blink::WebMediaTrackConstraintSet::goog_experimental_noise_suppression,
236 &blink::WebMediaTrackConstraintSet::goog_beamforming,
237 &blink::WebMediaTrackConstraintSet::goog_highpass_filter,
238 &blink::WebMediaTrackConstraintSet::
239 goog_experimental_auto_gain_control};
240
241 // directly mapped boolean sets to audio properties
242 struct BoolSetPropertyEntry {
243 DiscreteSet<bool> AudioCaptureCandidates::*bool_set;
244 bool AudioProcessingProperties::*bool_field;
245 bool default_value;
246 };
247
248 AudioCaptureCandidates::AudioCaptureCandidates()
249 : failed_constraint_name_(nullptr) {}
250
251 AudioCaptureCandidates::AudioCaptureCandidates(
252 const blink::WebMediaTrackConstraintSet& constraint_set,
253 const AudioDeviceCaptureCapabilities& capabilities,
254 bool is_device_capture)
255 : failed_constraint_name_(nullptr),
256 audio_device_set_(
257 is_device_capture
258 ? AudioDeviceSetForDeviceCapture(constraint_set,
259 capabilities,
260 &failed_constraint_name_)
261 : AudioDeviceSetForContentCapture(constraint_set,
262 &failed_constraint_name_)),
263 goog_array_geometry_set_(
264 StringSetFromConstraint(constraint_set.goog_array_geometry)) {
265 for (size_t i = 0; i < NUM_BOOL_CONSTRAINTS; ++i) {
266 bool_sets_[i] =
267 BoolSetFromConstraint(constraint_set.*kBlinkBoolConstraintFields[i]);
268 }
269 MaybeUpdateFailedNonDeviceConstraintName();
270 }
271
272 AudioCaptureCandidates AudioCaptureCandidates::Intersection(
273 const AudioCaptureCandidates& other) {
274 AudioCaptureCandidates intersection;
275 intersection.audio_device_set_ =
276 audio_device_set_.Intersection(other.audio_device_set_);
277 if (intersection.audio_device_set_.IsEmpty()) {
278 // To mark the intersection as empty, it is necessary to assign a
279 // a non-null value to |failed_constraint_name_|. The specific value
280 // for an intersection does not actually matter, since the intersection
281 // is discarded if empty.
282 intersection.failed_constraint_name_ = "some device constraint";
283 return intersection;
284 }
285 for (size_t i = 0; i < NUM_BOOL_CONSTRAINTS; ++i) {
286 intersection.bool_sets_[i] =
287 bool_sets_[i].Intersection(other.bool_sets_[i]);
288 }
289 intersection.goog_array_geometry_set_ =
290 goog_array_geometry_set_.Intersection(other.goog_array_geometry_set_);
291 intersection.MaybeUpdateFailedNonDeviceConstraintName();
292
293 return intersection;
294 }
295
296 void AudioCaptureCandidates::MaybeUpdateFailedNonDeviceConstraintName() {
297 blink::WebMediaTrackConstraintSet constraint_set;
298 for (size_t i = 0; i < NUM_BOOL_CONSTRAINTS; ++i) {
299 if (bool_sets_[i].IsEmpty()) {
300 failed_constraint_name_ =
301 (constraint_set.*kBlinkBoolConstraintFields[i]).GetName();
302 }
303 }
304 if (goog_array_geometry_set_.IsEmpty())
305 failed_constraint_name_ = constraint_set.goog_array_geometry.GetName();
306
307 CheckContradictoryEchoCancellation();
308 }
309
310 void AudioCaptureCandidates::CheckContradictoryEchoCancellation() {
311 DiscreteSet<bool> echo_cancellation_intersection =
312 bool_sets_[ECHO_CANCELLATION].Intersection(
313 bool_sets_[GOOG_ECHO_CANCELLATION]);
314 // echoCancellation and googEchoCancellation constraints should not
315 // contradict each other. Mark the set as empty if they do.
316 if (echo_cancellation_intersection.IsEmpty()) {
317 failed_constraint_name_ =
318 blink::WebMediaTrackConstraintSet().echo_cancellation.GetName();
319 }
320 }
321
322 // Fitness function for constraints involved in device selection.
323 // Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance
324 double DeviceInfoFitness(
325 bool is_device_capture,
326 const AudioDeviceInfo& device_info,
327 const blink::WebMediaTrackConstraintSet& basic_constraint_set) {
328 double fitness = 0.0;
329 fitness += StringConstraintFitnessDistance(
330 blink::WebString::FromASCII(device_info.device_id()),
331 basic_constraint_set.device_id);
332
333 if (!is_device_capture)
334 return fitness;
335
336 if (basic_constraint_set.sample_rate.HasIdeal()) {
337 fitness += NumericConstraintFitnessDistance(
338 device_info.SampleRate(), basic_constraint_set.sample_rate.Ideal());
339 }
340
341 if (basic_constraint_set.sample_size.HasIdeal()) {
342 fitness += NumericConstraintFitnessDistance(
343 device_info.SampleSize(), basic_constraint_set.sample_size.Ideal());
344 }
345
346 if (basic_constraint_set.channel_count.HasIdeal()) {
347 fitness += NumericConstraintFitnessDistance(
348 device_info.ChannelCount(), basic_constraint_set.channel_count.Ideal());
349 }
350
351 return fitness;
352 }
353
354 AudioDeviceInfo SelectDevice(
355 const AudioDeviceSet& audio_device_set,
356 const blink::WebMediaTrackConstraintSet& basic_constraint_set,
357 const std::string& default_device_id,
358 bool is_device_capture) {
359 DCHECK(!audio_device_set.IsEmpty());
360 if (audio_device_set.is_universal()) {
361 DCHECK(!is_device_capture);
362 std::string device_id;
363 if (basic_constraint_set.device_id.HasIdeal()) {
364 device_id = basic_constraint_set.device_id.Ideal().begin()->Utf8();
365 }
366 return AudioDeviceInfo(std::move(device_id));
367 }
368
369 std::vector<double> best_fitness({HUGE_VAL, HUGE_VAL});
370 auto best_candidate = audio_device_set.elements().end();
371 for (auto it = audio_device_set.elements().begin();
372 it != audio_device_set.elements().end(); ++it) {
373 std::vector<double> fitness;
374 // First criterion is spec-based fitness function. Second criterion is
375 // being the default device.
376 fitness.push_back(
377 DeviceInfoFitness(is_device_capture, *it, basic_constraint_set));
378 fitness.push_back(it->device_id() == default_device_id ? 0.0 : HUGE_VAL);
379 if (fitness < best_fitness) {
380 best_fitness = std::move(fitness);
381 best_candidate = it;
382 }
383 }
384 DCHECK(best_candidate != audio_device_set.elements().end());
385 return *best_candidate;
386 }
387
388 bool SelectBool(const DiscreteSet<bool>& set,
389 const blink::BooleanConstraint& constraint,
390 bool default_value) {
391 DCHECK(!set.IsEmpty());
392 if (constraint.HasIdeal() && set.Contains(constraint.Ideal())) {
393 return constraint.Ideal();
394 }
395
396 // Return default value if unconstrained.
397 if (set.is_universal()) {
398 return default_value;
399 }
400 DCHECK_EQ(set.elements().size(), 1U);
401 return set.FirstElement();
402 }
403
404 base::Optional<bool> SelectOptionalBool(
405 const DiscreteSet<bool>& set,
406 const blink::BooleanConstraint& constraint) {
407 DCHECK(!set.IsEmpty());
408 if (constraint.HasIdeal() && set.Contains(constraint.Ideal())) {
409 return constraint.Ideal();
410 }
411
412 // Return no value if unconstrained.
413 if (set.is_universal()) {
414 return base::Optional<bool>();
415 }
416 DCHECK_EQ(set.elements().size(), 1U);
417 return set.FirstElement();
418 }
419
420 base::Optional<std::string> SelectOptionalString(
421 const DiscreteSet<std::string>& set,
422 const blink::StringConstraint& constraint) {
423 DCHECK(!set.IsEmpty());
424 if (constraint.HasIdeal()) {
425 for (const auto& ideal_candidate : constraint.Ideal()) {
426 std::string candidate = ideal_candidate.Utf8();
427 if (set.Contains(candidate)) {
428 return candidate;
429 }
430 }
431 }
432
433 // Return no value if unconstrained.
434 if (set.is_universal()) {
435 return base::Optional<std::string>();
436 }
437 return set.FirstElement();
438 }
439
440 bool SelectEnableSwEchoCancellation(
441 base::Optional<bool> echo_cancellation,
442 base::Optional<bool> goog_echo_cancellation,
443 const media::AudioParameters& audio_parameters,
444 bool default_audio_processing_value) {
445 // If there is hardware echo cancellation, return false.
446 if (audio_parameters.IsValid() &&
447 (audio_parameters.effects() & media::AudioParameters::ECHO_CANCELLER))
448 return false;
449 DCHECK(echo_cancellation && goog_echo_cancellation
450 ? *echo_cancellation == *goog_echo_cancellation
451 : true);
452 if (echo_cancellation)
453 return *echo_cancellation;
454 if (goog_echo_cancellation)
455 return *goog_echo_cancellation;
456
457 return default_audio_processing_value;
458 }
459
460 struct AudioPropertyConstraintPair {
461 bool AudioProcessingProperties::*audio_property;
462 AudioCaptureCandidates::BoolConstraint bool_set_index;
463 blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*constraint;
464 };
465
466 // Boolean audio properties that are mapped directly to a boolean constraint
467 // and which are subject to the same processing.
468 const AudioPropertyConstraintPair kAudioPropertyConstraintMap[] = {
469 {&AudioProcessingProperties::goog_auto_gain_control,
470 AudioCaptureCandidates::GOOG_AUTO_GAIN_CONTROL,
471 &blink::WebMediaTrackConstraintSet::goog_auto_gain_control},
472 {&AudioProcessingProperties::goog_experimental_echo_cancellation,
473 AudioCaptureCandidates::GOOG_EXPERIMENTAL_ECHO_CANCELLATION,
474 &blink::WebMediaTrackConstraintSet::goog_experimental_echo_cancellation},
475 {&AudioProcessingProperties::goog_typing_noise_detection,
476 AudioCaptureCandidates::GOOG_TYPING_NOISE_DETECTION,
477 &blink::WebMediaTrackConstraintSet::goog_typing_noise_detection},
478 {&AudioProcessingProperties::goog_noise_suppression,
479 AudioCaptureCandidates::GOOG_NOISE_SUPPRESSION,
480 &blink::WebMediaTrackConstraintSet::goog_noise_suppression},
481 {&AudioProcessingProperties::goog_experimental_noise_suppression,
482 AudioCaptureCandidates::GOOG_EXPERIMENTAL_NOISE_SUPPRESSION,
483 &blink::WebMediaTrackConstraintSet::goog_experimental_noise_suppression},
484 {&AudioProcessingProperties::goog_beamforming,
485 AudioCaptureCandidates::GOOG_BEAMFORMING,
486 &blink::WebMediaTrackConstraintSet::goog_beamforming},
487 {&AudioProcessingProperties::goog_highpass_filter,
488 AudioCaptureCandidates::GOOG_HIGHPASS_FILTER,
489 &blink::WebMediaTrackConstraintSet::goog_highpass_filter},
490 {&AudioProcessingProperties::goog_experimental_auto_gain_control,
491 AudioCaptureCandidates::GOOG_EXPERIMENTAL_AUTO_GAIN_CONTROL,
492 &blink::WebMediaTrackConstraintSet::goog_experimental_auto_gain_control}};
493
494 AudioProcessingProperties SelectAudioProcessingProperties(
495 const AudioCaptureCandidates& candidates,
496 const blink::WebMediaTrackConstraintSet& basic_constraint_set,
497 const media::AudioParameters& audio_parameters,
498 bool is_device_capture) {
499 DCHECK(!candidates.IsEmpty());
500 base::Optional<bool> echo_cancellation =
501 SelectOptionalBool(candidates.echo_cancellation_set(),
502 basic_constraint_set.echo_cancellation);
503 // Audio-processing properties are disabled by default for content capture, or
504 // if the |echo_cancellation| constraint is false.
505 bool default_audio_processing_value = true;
506 if (!is_device_capture || (echo_cancellation && !*echo_cancellation))
507 default_audio_processing_value = false;
508
509 base::Optional<bool> goog_echo_cancellation =
510 SelectOptionalBool(candidates.goog_echo_cancellation_set(),
511 basic_constraint_set.goog_echo_cancellation);
512
513 AudioProcessingProperties properties;
514 properties.enable_sw_echo_cancellation = SelectEnableSwEchoCancellation(
515 echo_cancellation, goog_echo_cancellation, audio_parameters,
516 default_audio_processing_value);
517 properties.disable_hw_echo_cancellation =
518 (echo_cancellation && !*echo_cancellation) ||
519 (goog_echo_cancellation && !*goog_echo_cancellation);
520
521 properties.goog_audio_mirroring =
522 SelectBool(candidates.goog_audio_mirroring_set(),
523 basic_constraint_set.goog_audio_mirroring,
524 properties.goog_audio_mirroring);
525
526 for (auto& entry : kAudioPropertyConstraintMap) {
527 properties.*entry.audio_property = SelectBool(
528 candidates.GetBoolSet(entry.bool_set_index),
529 basic_constraint_set.*entry.constraint,
530 default_audio_processing_value && properties.*entry.audio_property);
531 }
532
533 base::Optional<std::string> array_geometry =
534 SelectOptionalString(candidates.goog_array_geometry_set(),
535 basic_constraint_set.goog_array_geometry);
536 std::vector<media::Point> parsed_positions;
537 if (array_geometry)
538 parsed_positions = media::ParsePointsFromString(*array_geometry);
539 bool are_valid_parsed_positions =
540 !parsed_positions.empty() || (array_geometry && array_geometry->empty());
541 properties.goog_array_geometry = are_valid_parsed_positions
542 ? std::move(parsed_positions)
543 : audio_parameters.mic_positions();
544
545 return properties;
546 }
547
548 AudioCaptureSettings SelectResult(
549 const AudioCaptureCandidates& candidates,
550 const blink::WebMediaTrackConstraintSet& basic_constraint_set,
551 const std::string& default_device_id,
552 const std::string& media_stream_source) {
553 bool is_device_capture = media_stream_source.empty();
554 AudioDeviceInfo device_info =
555 SelectDevice(candidates.audio_device_set(), basic_constraint_set,
556 default_device_id, is_device_capture);
557 bool hotword_enabled =
558 SelectBool(candidates.hotword_enabled_set(),
559 basic_constraint_set.hotword_enabled, false);
560 bool disable_local_echo_default =
561 media_stream_source != kMediaStreamSourceDesktop;
562 bool disable_local_echo = SelectBool(candidates.disable_local_echo_set(),
563 basic_constraint_set.disable_local_echo,
564 disable_local_echo_default);
565 bool render_to_associated_sink =
566 SelectBool(candidates.render_to_associated_sink_set(),
567 basic_constraint_set.render_to_associated_sink, false);
568
569 AudioProcessingProperties audio_processing_properties =
570 SelectAudioProcessingProperties(candidates, basic_constraint_set,
571 device_info.parameters(),
572 is_device_capture);
573
574 return AudioCaptureSettings(device_info.device_id(), device_info.parameters(),
575 hotword_enabled, disable_local_echo,
576 render_to_associated_sink,
577 audio_processing_properties);
578 }
579
580 } // namespace
581
582 AudioCaptureSettings SelectSettingsAudioCapture(
583 const AudioDeviceCaptureCapabilities& capabilities,
584 const blink::WebMediaConstraints& constraints) {
585 std::string media_stream_source = GetMediaStreamSource(constraints);
586 bool is_device_capture = media_stream_source.empty();
587 if (is_device_capture && capabilities.empty())
588 return AudioCaptureSettings();
589
590 AudioCaptureCandidates candidates(constraints.Basic(), capabilities,
591 is_device_capture);
592 if (candidates.IsEmpty()) {
593 return AudioCaptureSettings(candidates.failed_constraint_name());
594 }
595
596 for (const auto& advanced_set : constraints.Advanced()) {
597 AudioCaptureCandidates advanced_candidates(advanced_set, capabilities,
598 is_device_capture);
599 AudioCaptureCandidates intersection =
600 candidates.Intersection(advanced_candidates);
601 if (!intersection.IsEmpty())
602 candidates = std::move(intersection);
603 }
604 DCHECK(!candidates.IsEmpty());
605
606 std::string default_device_id;
607 if (!capabilities.empty())
608 default_device_id = (*capabilities.begin())->device_id;
609
610 return SelectResult(candidates, constraints.Basic(), default_device_id,
611 media_stream_source);
612 }
613
614 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698