1 // Copyright (c) 2013 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 "chromeos/audio/cras_audio_handler.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <algorithm>
11 #include <cmath>
12 #include <set>
13 #include <utility>
14 #include <vector>
15
16 #include "base/bind.h"
17 #include "base/callback_helpers.h"
18 #include "base/logging.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/system/sys_info.h"
22 #include "base/system/system_monitor.h"
23 #include "base/threading/thread_task_runner_handle.h"
24 #include "chromeos/audio/audio_device.h"
25 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
26 #include "chromeos/constants/chromeos_features.h"
27
28 using std::max;
29 using std::min;
30
31 namespace chromeos {
32
33 namespace {
34
35 // Default value for unmuting, as a percent in the range [0, 100].
36 // Used when sound is unmuted, but volume was less than kMuteThresholdPercent.
37 const int kDefaultUnmuteVolumePercent = 4;
38
39 // Volume value which should be considered as muted in range [0, 100].
40 const int kMuteThresholdPercent = 1;
41
42 // Mixer matrix, [0.5, 0.5; 0.5, 0.5]
43 const double kStereoToMono[] = {0.5, 0.5, 0.5, 0.5};
44 // Mixer matrix, [1, 0; 0, 1]
45 const double kStereoToStereo[] = {1, 0, 0, 1};
46
47 CrasAudioHandler* g_cras_audio_handler = nullptr;
48
IsSameAudioDevice(const AudioDevice & a,const AudioDevice & b)49 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) {
50 return a.stable_device_id == b.stable_device_id && a.is_input == b.is_input &&
51 a.type == b.type && a.device_name == b.device_name;
52 }
53
IsDeviceInList(const AudioDevice & device,const AudioNodeList & node_list)54 bool IsDeviceInList(const AudioDevice& device, const AudioNodeList& node_list) {
55 for (const AudioNode& node : node_list) {
56 if (device.stable_device_id == node.StableDeviceId())
57 return true;
58 }
59 return false;
60 }
61
62 } // namespace
63
64 CrasAudioHandler::AudioObserver::AudioObserver() = default;
65
66 CrasAudioHandler::AudioObserver::~AudioObserver() = default;
67
OnOutputNodeVolumeChanged(uint64_t,int)68 void CrasAudioHandler::AudioObserver::OnOutputNodeVolumeChanged(
69 uint64_t /* node_id */,
70 int /* volume */) {
71 }
72
OnInputNodeGainChanged(uint64_t,int)73 void CrasAudioHandler::AudioObserver::OnInputNodeGainChanged(
74 uint64_t /* node_id */,
75 int /* gain */) {
76 }
77
OnOutputMuteChanged(bool)78 void CrasAudioHandler::AudioObserver::OnOutputMuteChanged(bool /* mute_on */) {}
79
OnInputMuteChanged(bool)80 void CrasAudioHandler::AudioObserver::OnInputMuteChanged(bool /* mute_on */) {}
81
OnAudioNodesChanged()82 void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() {}
83
OnActiveOutputNodeChanged()84 void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() {}
85
OnActiveInputNodeChanged()86 void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() {}
87
OnOutputChannelRemixingChanged(bool)88 void CrasAudioHandler::AudioObserver::OnOutputChannelRemixingChanged(
89 bool /* mono_on */) {}
90
OnHotwordTriggered(uint64_t,uint64_t)91 void CrasAudioHandler::AudioObserver::OnHotwordTriggered(
92 uint64_t /* tv_sec */,
93 uint64_t /* tv_nsec */) {}
94
OnBluetoothBatteryChanged(const std::string &,uint32_t)95 void CrasAudioHandler::AudioObserver::OnBluetoothBatteryChanged(
96 const std::string& /* address */,
97 uint32_t /* level */) {}
98
OnOutputStarted()99 void CrasAudioHandler::AudioObserver::OnOutputStarted() {}
100
OnOutputStopped()101 void CrasAudioHandler::AudioObserver::OnOutputStopped() {}
102
103 // static
Initialize(mojo::PendingRemote<media_session::mojom::MediaControllerManager> media_controller_manager,scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler)104 void CrasAudioHandler::Initialize(
105 mojo::PendingRemote<media_session::mojom::MediaControllerManager>
106 media_controller_manager,
107 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler) {
108 g_cras_audio_handler = new CrasAudioHandler(
109 std::move(media_controller_manager), audio_pref_handler);
110 }
111
112 // static
InitializeForTesting()113 void CrasAudioHandler::InitializeForTesting() {
114 // Make sure CrasAudioClient has been initialized.
115 if (!CrasAudioClient::Get())
116 CrasAudioClient::InitializeFake();
117 CrasAudioHandler::Initialize(mojo::NullRemote(),
118 new AudioDevicesPrefHandlerStub());
119 }
120
121 // static
Shutdown()122 void CrasAudioHandler::Shutdown() {
123 delete g_cras_audio_handler;
124 g_cras_audio_handler = nullptr;
125 }
126
127 // static
Get()128 CrasAudioHandler* CrasAudioHandler::Get() {
129 return g_cras_audio_handler;
130 }
131
OnVideoCaptureStarted(media::VideoFacingMode facing)132 void CrasAudioHandler::OnVideoCaptureStarted(media::VideoFacingMode facing) {
133 DCHECK(main_task_runner_);
134 if (!main_task_runner_->BelongsToCurrentThread()) {
135 main_task_runner_->PostTask(
136 FROM_HERE,
137 base::BindOnce(&CrasAudioHandler::OnVideoCaptureStartedOnMainThread,
138 weak_ptr_factory_.GetWeakPtr(), facing));
139 return;
140 }
141 // Unittest may call this from the main thread.
142 OnVideoCaptureStartedOnMainThread(facing);
143 }
144
OnVideoCaptureStopped(media::VideoFacingMode facing)145 void CrasAudioHandler::OnVideoCaptureStopped(media::VideoFacingMode facing) {
146 DCHECK(main_task_runner_);
147 if (!main_task_runner_->BelongsToCurrentThread()) {
148 main_task_runner_->PostTask(
149 FROM_HERE,
150 base::BindOnce(&CrasAudioHandler::OnVideoCaptureStoppedOnMainThread,
151 weak_ptr_factory_.GetWeakPtr(), facing));
152 return;
153 }
154 // Unittest may call this from the main thread.
155 OnVideoCaptureStoppedOnMainThread(facing);
156 }
157
OnVideoCaptureStartedOnMainThread(media::VideoFacingMode facing)158 void CrasAudioHandler::OnVideoCaptureStartedOnMainThread(
159 media::VideoFacingMode facing) {
160 DCHECK(main_task_runner_->BelongsToCurrentThread());
161 // Do nothing if the device doesn't have both front and rear microphones.
162 if (!HasDualInternalMic())
163 return;
164
165 bool camera_is_already_on = IsCameraOn();
166 switch (facing) {
167 case media::MEDIA_VIDEO_FACING_USER:
168 front_camera_on_ = true;
169 break;
170 case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
171 rear_camera_on_ = true;
172 break;
173 default:
174 LOG_IF(WARNING, facing == media::NUM_MEDIA_VIDEO_FACING_MODES)
175 << "On the device with dual microphone, got video capture "
176 << "notification with invalid camera facing mode value";
177 return;
178 }
179
180 // If the camera is already on before this notification, don't change active
181 // input. In the case that both cameras are turned on at the same time, we
182 // won't change the active input after the first camera is turned on. We only
183 // support the use case of one camera on at a time. The third party
184 // developer can turn on/off both microphones with extension api if they like
185 // to.
186 if (camera_is_already_on)
187 return;
188
189 // If the current active input is an external device, keep it.
190 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_);
191 if (active_input && active_input->IsExternalDevice())
192 return;
193
194 // Activate the correct mic for the current active camera.
195 ActivateMicForCamera(facing);
196 }
197
OnVideoCaptureStoppedOnMainThread(media::VideoFacingMode facing)198 void CrasAudioHandler::OnVideoCaptureStoppedOnMainThread(
199 media::VideoFacingMode facing) {
200 DCHECK(main_task_runner_->BelongsToCurrentThread());
201 // Do nothing if the device doesn't have both front and rear microphones.
202 if (!HasDualInternalMic())
203 return;
204
205 switch (facing) {
206 case media::MEDIA_VIDEO_FACING_USER:
207 front_camera_on_ = false;
208 break;
209 case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
210 rear_camera_on_ = false;
211 break;
212 default:
213 LOG_IF(WARNING, facing == media::NUM_MEDIA_VIDEO_FACING_MODES)
214 << "On the device with dual microphone, got video capture "
215 << "notification with invalid camera facing mode value";
216 return;
217 }
218
219 // If not all cameras are turned off, don't change active input. In the case
220 // that both cameras are turned on at the same time before one of them is
221 // stopped, we won't change active input until all of them are stopped.
222 // We only support the use case of one camera on at a time. The third party
223 // developer can turn on/off both microphones with extension api if they like
224 // to.
225 if (IsCameraOn())
226 return;
227
228 // If the current active input is an external device, keep it.
229 const AudioDevice* active_input = GetDeviceFromId(active_input_node_id_);
230 if (active_input && active_input->IsExternalDevice())
231 return;
232
233 // Switch to front mic properly.
234 DeviceActivateType activated_by =
235 HasExternalDevice(true) ? ACTIVATE_BY_USER : ACTIVATE_BY_PRIORITY;
236 SwitchToDevice(*GetDeviceByType(AUDIO_TYPE_FRONT_MIC), true, activated_by);
237 }
238
HandleMediaSessionMetadataReset()239 void CrasAudioHandler::HandleMediaSessionMetadataReset() {
240 const std::map<std::string, std::string> empty_metadata_map = {
241 {"title", ""}, {"artist", ""}, {"album", ""}};
242
243 CrasAudioClient::Get()->SetPlayerMetadata(empty_metadata_map);
244 CrasAudioClient::Get()->SetPlayerIdentity("");
245 CrasAudioClient::Get()->SetPlayerPlaybackStatus("stopped");
246 }
247
MediaSessionInfoChanged(media_session::mojom::MediaSessionInfoPtr session_info)248 void CrasAudioHandler::MediaSessionInfoChanged(
249 media_session::mojom::MediaSessionInfoPtr session_info) {
250 if (!session_info)
251 return;
252
253 std::string state;
254
255 switch (session_info->state) {
256 case media_session::mojom::MediaSessionInfo::SessionState::kActive:
257 case media_session::mojom::MediaSessionInfo::SessionState::kDucking:
258 state = "playing";
259 break;
260 case media_session::mojom::MediaSessionInfo::SessionState::kSuspended:
261 state = "paused";
262 break;
263 case media_session::mojom::MediaSessionInfo::SessionState::kInactive:
264 state = "stopped";
265 break;
266 }
267
268 CrasAudioClient::Get()->SetPlayerPlaybackStatus(state);
269 }
270
MediaSessionMetadataChanged(const base::Optional<media_session::MediaMetadata> & metadata)271 void CrasAudioHandler::MediaSessionMetadataChanged(
272 const base::Optional<media_session::MediaMetadata>& metadata) {
273 if (!metadata || metadata->IsEmpty()) {
274 HandleMediaSessionMetadataReset();
275 return;
276 }
277
278 const std::map<std::string, std::string> metadata_map = {
279 {"title", base::UTF16ToUTF8(metadata->title)},
280 {"artist", base::UTF16ToUTF8(metadata->artist)},
281 {"album", base::UTF16ToUTF8(metadata->album)}};
282 const std::string source_title = base::UTF16ToUTF8(metadata->source_title);
283
284 // Assume media duration/length should always change with new metadata.
285 fetch_media_session_duration_ = true;
286 CrasAudioClient::Get()->SetPlayerMetadata(metadata_map);
287 CrasAudioClient::Get()->SetPlayerIdentity(source_title);
288 }
289
MediaSessionPositionChanged(const base::Optional<media_session::MediaPosition> & position)290 void CrasAudioHandler::MediaSessionPositionChanged(
291 const base::Optional<media_session::MediaPosition>& position) {
292 if (!position)
293 return;
294
295 int64_t duration = 0;
296 if (fetch_media_session_duration_) {
297 duration = position->duration().InMicroseconds();
298 if (duration > 0) {
299 CrasAudioClient::Get()->SetPlayerDuration(duration);
300 fetch_media_session_duration_ = false;
301 }
302 }
303
304 int64_t current_position = position->GetPosition().InMicroseconds();
305 if (current_position < 0 || (duration > 0 && current_position > duration))
306 return;
307
308 CrasAudioClient::Get()->SetPlayerPosition(current_position);
309 }
310
AddAudioObserver(AudioObserver * observer)311 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) {
312 observers_.AddObserver(observer);
313 }
314
RemoveAudioObserver(AudioObserver * observer)315 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) {
316 observers_.RemoveObserver(observer);
317 }
318
HasKeyboardMic()319 bool CrasAudioHandler::HasKeyboardMic() {
320 return GetKeyboardMic() != nullptr;
321 }
322
HasHotwordDevice()323 bool CrasAudioHandler::HasHotwordDevice() {
324 return GetHotwordDevice() != nullptr;
325 }
326
IsOutputMuted()327 bool CrasAudioHandler::IsOutputMuted() {
328 return output_mute_on_;
329 }
330
IsOutputMutedForDevice(uint64_t device_id)331 bool CrasAudioHandler::IsOutputMutedForDevice(uint64_t device_id) {
332 const AudioDevice* device = GetDeviceFromId(device_id);
333 if (!device)
334 return false;
335 DCHECK(!device->is_input);
336 return audio_pref_handler_->GetMuteValue(*device);
337 }
338
IsOutputVolumeBelowDefaultMuteLevel()339 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLevel() {
340 return output_volume_ <= kMuteThresholdPercent;
341 }
342
IsInputMuted()343 bool CrasAudioHandler::IsInputMuted() {
344 return input_mute_on_;
345 }
346
IsInputMutedForDevice(uint64_t device_id)347 bool CrasAudioHandler::IsInputMutedForDevice(uint64_t device_id) {
348 const AudioDevice* device = GetDeviceFromId(device_id);
349 if (!device)
350 return false;
351 DCHECK(device->is_input);
352 // We don't record input mute state for each device in the prefs,
353 // for any non-active input device, we assume mute is off.
354 if (device->id == active_input_node_id_)
355 return input_mute_on_;
356 return false;
357 }
358
GetOutputDefaultVolumeMuteThreshold()359 int CrasAudioHandler::GetOutputDefaultVolumeMuteThreshold() {
360 return kMuteThresholdPercent;
361 }
362
GetOutputVolumePercent()363 int CrasAudioHandler::GetOutputVolumePercent() {
364 return output_volume_;
365 }
366
GetOutputVolumePercentForDevice(uint64_t device_id)367 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64_t device_id) {
368 if (device_id == active_output_node_id_)
369 return output_volume_;
370 const AudioDevice* device = GetDeviceFromId(device_id);
371 return static_cast<int>(audio_pref_handler_->GetOutputVolumeValue(device));
372 }
373
GetInputGainPercent()374 int CrasAudioHandler::GetInputGainPercent() {
375 return input_gain_;
376 }
377
GetInputGainPercentForDevice(uint64_t device_id)378 int CrasAudioHandler::GetInputGainPercentForDevice(uint64_t device_id) {
379 if (device_id == active_input_node_id_)
380 return input_gain_;
381 const AudioDevice* device = GetDeviceFromId(device_id);
382 return static_cast<int>(audio_pref_handler_->GetInputGainValue(device));
383 }
384
GetPrimaryActiveOutputNode() const385 uint64_t CrasAudioHandler::GetPrimaryActiveOutputNode() const {
386 return active_output_node_id_;
387 }
388
GetPrimaryActiveInputNode() const389 uint64_t CrasAudioHandler::GetPrimaryActiveInputNode() const {
390 return active_input_node_id_;
391 }
392
GetAudioDevices(AudioDeviceList * device_list) const393 void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const {
394 device_list->clear();
395 for (const auto& item : audio_devices_) {
396 const AudioDevice& device = item.second;
397 device_list->push_back(device);
398 }
399 }
400
GetPrimaryActiveOutputDevice(AudioDevice * device) const401 bool CrasAudioHandler::GetPrimaryActiveOutputDevice(AudioDevice* device) const {
402 const AudioDevice* active_device = GetDeviceFromId(active_output_node_id_);
403 if (!active_device || !device)
404 return false;
405 *device = *active_device;
406 return true;
407 }
408
GetDeviceByType(AudioDeviceType type)409 const AudioDevice* CrasAudioHandler::GetDeviceByType(AudioDeviceType type) {
410 for (const auto& item : audio_devices_) {
411 const AudioDevice& device = item.second;
412 if (device.type == type)
413 return &device;
414 }
415 return nullptr;
416 }
417
GetDefaultOutputBufferSize(int32_t * buffer_size) const418 void CrasAudioHandler::GetDefaultOutputBufferSize(int32_t* buffer_size) const {
419 *buffer_size = default_output_buffer_size_;
420 }
421
SetKeyboardMicActive(bool active)422 void CrasAudioHandler::SetKeyboardMicActive(bool active) {
423 const AudioDevice* keyboard_mic = GetKeyboardMic();
424 if (!keyboard_mic)
425 return;
426 // Keyboard mic is invisible to chromeos users. It is always added or removed
427 // as additional active node.
428 DCHECK(active_input_node_id_ && active_input_node_id_ != keyboard_mic->id);
429 if (active)
430 AddActiveNode(keyboard_mic->id, true);
431 else
432 RemoveActiveNodeInternal(keyboard_mic->id, true);
433 }
434
AddActiveNode(uint64_t node_id,bool notify)435 void CrasAudioHandler::AddActiveNode(uint64_t node_id, bool notify) {
436 const AudioDevice* device = GetDeviceFromId(node_id);
437 if (!device) {
438 VLOG(1) << "AddActiveInputNode: Cannot find device id="
439 << "0x" << std::hex << node_id;
440 return;
441 }
442
443 // If there is no primary active device, set |node_id| to primary active node.
444 if ((device->is_input && !active_input_node_id_) ||
445 (!device->is_input && !active_output_node_id_)) {
446 SwitchToDevice(*device, notify, ACTIVATE_BY_USER);
447 return;
448 }
449
450 AddAdditionalActiveNode(node_id, notify);
451 }
452
ChangeActiveNodes(const NodeIdList & new_active_ids)453 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) {
454 AudioDeviceList input_devices;
455 AudioDeviceList output_devices;
456
457 for (uint64_t id : new_active_ids) {
458 const AudioDevice* device = GetDeviceFromId(id);
459 if (!device)
460 continue;
461 if (device->is_input)
462 input_devices.push_back(*device);
463 else
464 output_devices.push_back(*device);
465 }
466 if (!input_devices.empty())
467 SetActiveDevices(input_devices, true /* is_input */);
468 if (!output_devices.empty())
469 SetActiveDevices(output_devices, false /* is_input */);
470 }
471
SetActiveInputNodes(const NodeIdList & node_ids)472 bool CrasAudioHandler::SetActiveInputNodes(const NodeIdList& node_ids) {
473 return SetActiveNodes(node_ids, true /* is_input */);
474 }
475
SetActiveOutputNodes(const NodeIdList & node_ids)476 bool CrasAudioHandler::SetActiveOutputNodes(const NodeIdList& node_ids) {
477 return SetActiveNodes(node_ids, false /* is_input */);
478 }
479
SetActiveNodes(const NodeIdList & node_ids,bool is_input)480 bool CrasAudioHandler::SetActiveNodes(const NodeIdList& node_ids,
481 bool is_input) {
482 AudioDeviceList devices;
483 for (uint64_t id : node_ids) {
484 const AudioDevice* device = GetDeviceFromId(id);
485 if (!device || device->is_input != is_input)
486 return false;
487
488 devices.push_back(*device);
489 }
490
491 SetActiveDevices(devices, is_input);
492 return true;
493 }
494
SetActiveDevices(const AudioDeviceList & devices,bool is_input)495 void CrasAudioHandler::SetActiveDevices(const AudioDeviceList& devices,
496 bool is_input) {
497 std::set<uint64_t> new_active_ids;
498 for (const auto& active_device : devices) {
499 CHECK_EQ(is_input, active_device.is_input);
500 new_active_ids.insert(active_device.id);
501 }
502
503 bool active_devices_changed = false;
504
505 // If primary active node has to be switched, do that before adding or
506 // removing any other active devices. Switching to a device can change
507 // activity state of other devices - final device activity may end up being
508 // unintended if it is set before active device switches.
509 uint64_t primary_active =
510 is_input ? active_input_node_id_ : active_output_node_id_;
511 if (!new_active_ids.count(primary_active) && !devices.empty()) {
512 active_devices_changed = true;
513 SwitchToDevice(devices[0], false /* notify */, ACTIVATE_BY_USER);
514 }
515
516 AudioDeviceList existing_devices;
517 GetAudioDevices(&existing_devices);
518 for (const auto& existing_device : existing_devices) {
519 if (existing_device.is_input != is_input)
520 continue;
521
522 bool should_be_active = new_active_ids.count(existing_device.id);
523 if (existing_device.active == should_be_active)
524 continue;
525 active_devices_changed = true;
526
527 if (should_be_active)
528 AddActiveNode(existing_device.id, false /* notify */);
529 else
530 RemoveActiveNodeInternal(existing_device.id, false /* notify */);
531 }
532
533 if (active_devices_changed)
534 NotifyActiveNodeChanged(is_input);
535 }
536
SetHotwordModel(uint64_t node_id,const std::string & hotword_model,VoidCrasAudioHandlerCallback callback)537 void CrasAudioHandler::SetHotwordModel(uint64_t node_id,
538 const std::string& hotword_model,
539 VoidCrasAudioHandlerCallback callback) {
540 CrasAudioClient::Get()->SetHotwordModel(node_id, hotword_model,
541 std::move(callback));
542 }
543
SwapInternalSpeakerLeftRightChannel(bool swap)544 void CrasAudioHandler::SwapInternalSpeakerLeftRightChannel(bool swap) {
545 for (const auto& item : audio_devices_) {
546 const AudioDevice& device = item.second;
547 if (!device.is_input && device.type == AUDIO_TYPE_INTERNAL_SPEAKER) {
548 CrasAudioClient::Get()->SwapLeftRight(device.id, swap);
549 break;
550 }
551 }
552 }
553
SetOutputMonoEnabled(bool enabled)554 void CrasAudioHandler::SetOutputMonoEnabled(bool enabled) {
555 if (output_mono_enabled_ == enabled)
556 return;
557 output_mono_enabled_ = enabled;
558 if (enabled) {
559 CrasAudioClient::Get()->SetGlobalOutputChannelRemix(
560 output_channels_,
561 std::vector<double>(kStereoToMono, std::end(kStereoToMono)));
562 } else {
563 CrasAudioClient::Get()->SetGlobalOutputChannelRemix(
564 output_channels_,
565 std::vector<double>(kStereoToStereo, std::end(kStereoToStereo)));
566 }
567
568 for (auto& observer : observers_)
569 observer.OnOutputChannelRemixingChanged(enabled);
570 }
571
has_alternative_input() const572 bool CrasAudioHandler::has_alternative_input() const {
573 return has_alternative_input_;
574 }
575
has_alternative_output() const576 bool CrasAudioHandler::has_alternative_output() const {
577 return has_alternative_output_;
578 }
579
SetOutputVolumePercent(int volume_percent)580 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) {
581 // Set all active devices to the same volume.
582 for (const auto& item : audio_devices_) {
583 const AudioDevice& device = item.second;
584 if (!device.is_input && device.active)
585 SetOutputNodeVolumePercent(device.id, volume_percent);
586 }
587 }
588
589 // TODO: Rename the 'Percent' to something more meaningful.
SetInputGainPercent(int gain_percent)590 void CrasAudioHandler::SetInputGainPercent(int gain_percent) {
591 // TODO(jennyz): Should we set all input devices' gain to the same level?
592 for (const auto& item : audio_devices_) {
593 const AudioDevice& device = item.second;
594 if (device.is_input && device.active)
595 SetInputNodeGainPercent(active_input_node_id_, gain_percent);
596 }
597 }
598
AdjustOutputVolumeByPercent(int adjust_by_percent)599 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) {
600 SetOutputVolumePercent(output_volume_ + adjust_by_percent);
601 }
602
SetOutputMute(bool mute_on)603 void CrasAudioHandler::SetOutputMute(bool mute_on) {
604 if (!SetOutputMuteInternal(mute_on))
605 return;
606
607 // Save the mute state for all active output audio devices.
608 for (const auto& item : audio_devices_) {
609 const AudioDevice& device = item.second;
610 if (!device.is_input && device.active) {
611 audio_pref_handler_->SetMuteValue(device, output_mute_on_);
612 }
613 }
614
615 for (auto& observer : observers_)
616 observer.OnOutputMuteChanged(output_mute_on_);
617 }
618
AdjustOutputVolumeToAudibleLevel()619 void CrasAudioHandler::AdjustOutputVolumeToAudibleLevel() {
620 if (output_volume_ <= kMuteThresholdPercent) {
621 // Avoid the situation when sound has been unmuted, but the volume
622 // is set to a very low value, so user still can't hear any sound.
623 SetOutputVolumePercent(kDefaultUnmuteVolumePercent);
624 }
625 }
626
SetInputMute(bool mute_on)627 void CrasAudioHandler::SetInputMute(bool mute_on) {
628 SetInputMuteInternal(mute_on);
629 for (auto& observer : observers_)
630 observer.OnInputMuteChanged(input_mute_on_);
631 }
632
SetActiveDevice(const AudioDevice & active_device,bool notify,DeviceActivateType activate_by)633 void CrasAudioHandler::SetActiveDevice(const AudioDevice& active_device,
634 bool notify,
635 DeviceActivateType activate_by) {
636 if (active_device.is_input)
637 CrasAudioClient::Get()->SetActiveInputNode(active_device.id);
638 else
639 CrasAudioClient::Get()->SetActiveOutputNode(active_device.id);
640
641 if (notify)
642 NotifyActiveNodeChanged(active_device.is_input);
643
644 // Save active state for the nodes.
645 for (const auto& item : audio_devices_) {
646 const AudioDevice& device = item.second;
647 if (device.is_input != active_device.is_input)
648 continue;
649 SaveDeviceState(device, device.active, activate_by);
650 }
651 }
652
SaveDeviceState(const AudioDevice & device,bool active,DeviceActivateType activate_by)653 void CrasAudioHandler::SaveDeviceState(const AudioDevice& device,
654 bool active,
655 DeviceActivateType activate_by) {
656 // Don't save the active state for non-simple usage device, which is invisible
657 // to end users.
658 if (!device.is_for_simple_usage())
659 return;
660
661 if (!active) {
662 audio_pref_handler_->SetDeviceActive(device, false, false);
663 } else {
664 switch (activate_by) {
665 case ACTIVATE_BY_USER:
666 audio_pref_handler_->SetDeviceActive(device, true, true);
667 break;
668 case ACTIVATE_BY_PRIORITY:
669 audio_pref_handler_->SetDeviceActive(device, true, false);
670 break;
671 default:
672 // The device is made active due to its previous active state in prefs,
673 // don't change its active state settings in prefs.
674 break;
675 }
676 }
677 }
678
SetVolumeGainPercentForDevice(uint64_t device_id,int value)679 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64_t device_id,
680 int value) {
681 const AudioDevice* device = GetDeviceFromId(device_id);
682 if (!device)
683 return;
684
685 if (device->is_input)
686 SetInputNodeGainPercent(device_id, value);
687 else
688 SetOutputNodeVolumePercent(device_id, value);
689 }
690
SetMuteForDevice(uint64_t device_id,bool mute_on)691 void CrasAudioHandler::SetMuteForDevice(uint64_t device_id, bool mute_on) {
692 if (device_id == active_output_node_id_) {
693 SetOutputMute(mute_on);
694 return;
695 }
696 if (device_id == active_input_node_id_) {
697 VLOG(1) << "SetMuteForDevice sets active input device id="
698 << "0x" << std::hex << device_id << " mute=" << mute_on;
699 SetInputMute(mute_on);
700 return;
701 }
702
703 const AudioDevice* device = GetDeviceFromId(device_id);
704 // Input device's mute state is not recorded in the pref. crbug.com/365050.
705 if (device && !device->is_input)
706 audio_pref_handler_->SetMuteValue(*device, mute_on);
707 }
708
709 // If the HDMI device is the active output device, when the device enters/exits
710 // docking mode, or HDMI display changes resolution, or chromeos device
711 // suspends/resumes, cras will lose the HDMI output node for a short period of
712 // time, then rediscover it. This hotplug behavior will cause the audio output
713 // be leaked to the alternatvie active audio output during HDMI re-discovering
714 // period. See crbug.com/503667.
SetActiveHDMIOutoutRediscoveringIfNecessary(bool force_rediscovering)715 void CrasAudioHandler::SetActiveHDMIOutoutRediscoveringIfNecessary(
716 bool force_rediscovering) {
717 if (!GetDeviceFromId(active_output_node_id_))
718 return;
719
720 // Marks the start of the HDMI re-discovering grace period, during which we
721 // will mute the audio output to prevent it to be be leaked to the
722 // alternative output device.
723 if ((hdmi_rediscovering_ && force_rediscovering) ||
724 (!hdmi_rediscovering_ && IsHDMIPrimaryOutputDevice())) {
725 StartHDMIRediscoverGracePeriod();
726 }
727 }
728
CrasAudioHandler(mojo::PendingRemote<media_session::mojom::MediaControllerManager> media_controller_manager,scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler)729 CrasAudioHandler::CrasAudioHandler(
730 mojo::PendingRemote<media_session::mojom::MediaControllerManager>
731 media_controller_manager,
732 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler)
733 : media_controller_manager_(std::move(media_controller_manager)),
734 audio_pref_handler_(audio_pref_handler) {
735 DCHECK(audio_pref_handler);
736 DCHECK(CrasAudioClient::Get());
737 CrasAudioClient::Get()->AddObserver(this);
738 audio_pref_handler_->AddAudioPrefObserver(this);
739 BindMediaControllerObserver();
740 InitializeAudioState();
741 // Unittest may not have the task runner for the current thread.
742 if (base::ThreadTaskRunnerHandle::IsSet())
743 main_task_runner_ = base::ThreadTaskRunnerHandle::Get();
744
745 DCHECK(!g_cras_audio_handler);
746 g_cras_audio_handler = this;
747 }
748
~CrasAudioHandler()749 CrasAudioHandler::~CrasAudioHandler() {
750 hdmi_rediscover_timer_.Stop();
751 DCHECK(CrasAudioClient::Get());
752 CrasAudioClient::Get()->RemoveObserver(this);
753 audio_pref_handler_->RemoveAudioPrefObserver(this);
754
755 DCHECK(g_cras_audio_handler);
756 g_cras_audio_handler = nullptr;
757 }
758
BindMediaControllerObserver()759 void CrasAudioHandler::BindMediaControllerObserver() {
760 if (!media_controller_manager_)
761 return;
762 media_controller_manager_->CreateActiveMediaController(
763 media_session_controller_remote_.BindNewPipeAndPassReceiver());
764 media_session_controller_remote_->AddObserver(
765 media_controller_observer_receiver_.BindNewPipeAndPassRemote());
766 }
767
AudioClientRestarted()768 void CrasAudioHandler::AudioClientRestarted() {
769 InitializeAudioState();
770 }
771
NodesChanged()772 void CrasAudioHandler::NodesChanged() {
773 if (cras_service_available_)
774 GetNodes();
775 }
776
OutputNodeVolumeChanged(uint64_t node_id,int volume)777 void CrasAudioHandler::OutputNodeVolumeChanged(uint64_t node_id, int volume) {
778 const AudioDevice* device = this->GetDeviceFromId(node_id);
779
780 // If this is not an active output node, ignore this event. Because when this
781 // node set to active, it will be applied with the volume value stored in
782 // preference.
783 if (!device || !device->active || device->is_input) {
784 LOG(ERROR) << "Unexpexted OutputNodeVolumeChanged received on node: 0x"
785 << std::hex << node_id;
786 return;
787 }
788
789 // Sync internal volume state and notify UI for the change. We trust cras
790 // signal to report the volume state of the device, no matter which source
791 // set the volume, i.e., volume could be set from non-chrome source, like
792 // Bluetooth headset, etc. Assume all active output devices share a single
793 // volume.
794 output_volume_ = volume;
795 audio_pref_handler_->SetVolumeGainValue(*device, volume);
796
797 if (initializing_audio_state_) {
798 // Do not notify the observers for volume changed event if CrasAudioHandler
799 // is initializing its state, i.e., the volume change event is in responding
800 // to SetOutputNodeVolume request from intializaing audio state, not
801 // from user action, no need to notify UI to pop uo the volume slider bar.
802 if (init_node_id_ == node_id && init_volume_ == volume) {
803 --init_volume_count_;
804 if (!init_volume_count_)
805 initializing_audio_state_ = false;
806 return;
807 } else {
808 // Reset the initializing_audio_state_ in case SetOutputNodeVolume request
809 // is lost by cras due to cras is not ready when CrasAudioHandler is being
810 // initialized.
811 initializing_audio_state_ = false;
812 init_volume_count_ = 0;
813 }
814 }
815
816 for (auto& observer : observers_)
817 observer.OnOutputNodeVolumeChanged(node_id, volume);
818 }
819
ActiveOutputNodeChanged(uint64_t node_id)820 void CrasAudioHandler::ActiveOutputNodeChanged(uint64_t node_id) {
821 if (active_output_node_id_ == node_id)
822 return;
823
824 // Active audio output device should always be changed by chrome.
825 // During system boot, cras may change active input to unknown device 0x1,
826 // we don't need to log it, since it is not an valid device.
827 if (GetDeviceFromId(node_id)) {
828 LOG(WARNING) << "Active output node changed unexpectedly by system node_id="
829 << "0x" << std::hex << node_id;
830 }
831 }
832
ActiveInputNodeChanged(uint64_t node_id)833 void CrasAudioHandler::ActiveInputNodeChanged(uint64_t node_id) {
834 if (active_input_node_id_ == node_id)
835 return;
836
837 // Active audio input device should always be changed by chrome.
838 // During system boot, cras may change active input to unknown device 0x2,
839 // we don't need to log it, since it is not an valid device.
840 if (GetDeviceFromId(node_id)) {
841 LOG(WARNING) << "Active input node changed unexpectedly by system node_id="
842 << "0x" << std::hex << node_id;
843 }
844 }
845
HotwordTriggered(uint64_t tv_sec,uint64_t tv_nsec)846 void CrasAudioHandler::HotwordTriggered(uint64_t tv_sec, uint64_t tv_nsec) {
847 for (auto& observer : observers_)
848 observer.OnHotwordTriggered(tv_sec, tv_nsec);
849 }
850
NumberOfActiveStreamsChanged()851 void CrasAudioHandler::NumberOfActiveStreamsChanged() {
852 GetNumberOfOutputStreams();
853 }
854
BluetoothBatteryChanged(const std::string & address,uint32_t level)855 void CrasAudioHandler::BluetoothBatteryChanged(const std::string& address,
856 uint32_t level) {
857 for (auto& observer : observers_)
858 observer.OnBluetoothBatteryChanged(address, level);
859 }
860
ResendBluetoothBattery()861 void CrasAudioHandler::ResendBluetoothBattery() {
862 CrasAudioClient::Get()->ResendBluetoothBattery();
863 }
864
OnAudioPolicyPrefChanged()865 void CrasAudioHandler::OnAudioPolicyPrefChanged() {
866 ApplyAudioPolicy();
867 }
868
GetDeviceFromId(uint64_t device_id) const869 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64_t device_id) const {
870 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id);
871 if (it == audio_devices_.end())
872 return nullptr;
873 return &it->second;
874 }
875
ConvertAudioNodeWithModifiedPriority(const AudioNode & node)876 AudioDevice CrasAudioHandler::ConvertAudioNodeWithModifiedPriority(
877 const AudioNode& node) {
878 AudioDevice device(node);
879 if (deprioritize_bt_wbs_mic_ && device.is_input &&
880 (device.type == AUDIO_TYPE_BLUETOOTH))
881 device.priority = 0;
882 return device;
883 }
884
GetDeviceFromStableDeviceId(uint64_t stable_device_id) const885 const AudioDevice* CrasAudioHandler::GetDeviceFromStableDeviceId(
886 uint64_t stable_device_id) const {
887 for (const auto& item : audio_devices_) {
888 const AudioDevice& device = item.second;
889 if (device.stable_device_id == stable_device_id)
890 return &device;
891 }
892 return nullptr;
893 }
894
GetKeyboardMic() const895 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const {
896 for (const auto& item : audio_devices_) {
897 const AudioDevice& device = item.second;
898 if (device.is_input && device.type == AUDIO_TYPE_KEYBOARD_MIC)
899 return &device;
900 }
901 return nullptr;
902 }
903
GetHotwordDevice() const904 const AudioDevice* CrasAudioHandler::GetHotwordDevice() const {
905 for (const auto& item : audio_devices_) {
906 const AudioDevice& device = item.second;
907 if (device.is_input && device.type == AUDIO_TYPE_HOTWORD)
908 return &device;
909 }
910 return nullptr;
911 }
912
SetupAudioInputState()913 void CrasAudioHandler::SetupAudioInputState() {
914 // Set the initial audio state to the ones read from audio prefs.
915 const AudioDevice* device = GetDeviceFromId(active_input_node_id_);
916 if (!device) {
917 LOG(ERROR) << "Can't set up audio state for unknown input device id ="
918 << "0x" << std::hex << active_input_node_id_;
919 return;
920 }
921 input_gain_ = audio_pref_handler_->GetInputGainValue(device);
922 VLOG(1) << "SetupAudioInputState for active device id="
923 << "0x" << std::hex << device->id << " mute=" << input_mute_on_;
924 SetInputMuteInternal(input_mute_on_);
925
926 SetInputNodeGain(active_input_node_id_, input_gain_);
927 }
928
SetupAudioOutputState()929 void CrasAudioHandler::SetupAudioOutputState() {
930 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
931 if (!device) {
932 LOG(ERROR) << "Can't set up audio state for unknown output device id ="
933 << "0x" << std::hex << active_output_node_id_;
934 return;
935 }
936 DCHECK(!device->is_input);
937 // Mute the output during HDMI re-discovering grace period.
938 if (hdmi_rediscovering_ && !IsHDMIPrimaryOutputDevice()) {
939 VLOG(1) << "Mute the output during HDMI re-discovering grace period";
940 output_mute_on_ = true;
941 } else {
942 output_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
943 }
944 output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device);
945
946 SetOutputMuteInternal(output_mute_on_);
947
948 if (initializing_audio_state_) {
949 // During power up, InitializeAudioState() could be called twice, first
950 // by CrasAudioHandler constructor, then by cras server restarting signal,
951 // both sending SetOutputNodeVolume requests, and could lead to two
952 // OutputNodeVolumeChanged signals.
953 ++init_volume_count_;
954 init_node_id_ = active_output_node_id_;
955 init_volume_ = output_volume_;
956 }
957 SetOutputNodeVolume(active_output_node_id_, output_volume_);
958 }
959
960 // This sets up the state of an additional active node.
SetupAdditionalActiveAudioNodeState(uint64_t node_id)961 void CrasAudioHandler::SetupAdditionalActiveAudioNodeState(uint64_t node_id) {
962 const AudioDevice* device = GetDeviceFromId(node_id);
963 if (!device) {
964 VLOG(1) << "Can't set up audio state for unknown device id ="
965 << "0x" << std::hex << node_id;
966 return;
967 }
968
969 DCHECK(node_id != active_output_node_id_ && node_id != active_input_node_id_);
970
971 // Note: The mute state is a system wide state, we don't set mute per device,
972 // but just keep the mute state consistent for the active node in prefs.
973 // The output volume should be set to the same value for all active output
974 // devices. For input devices, we don't restore their gain value so far.
975 // TODO(jennyz): crbug.com/417418, track the status for the decison if
976 // we should persist input gain value in prefs.
977 if (!device->is_input) {
978 audio_pref_handler_->SetMuteValue(*device, IsOutputMuted());
979 SetOutputNodeVolumePercent(node_id, GetOutputVolumePercent());
980 }
981 }
982
InitializeAudioState()983 void CrasAudioHandler::InitializeAudioState() {
984 initializing_audio_state_ = true;
985 ApplyAudioPolicy();
986
987 // Defer querying cras for GetNodes until cras service becomes available.
988 cras_service_available_ = false;
989 CrasAudioClient::Get()->WaitForServiceToBeAvailable(base::BindOnce(
990 &CrasAudioHandler::InitializeAudioAfterCrasServiceAvailable,
991 weak_ptr_factory_.GetWeakPtr()));
992 }
993
InitializeAudioAfterCrasServiceAvailable(bool service_is_available)994 void CrasAudioHandler::InitializeAudioAfterCrasServiceAvailable(
995 bool service_is_available) {
996 if (!service_is_available) {
997 LOG(ERROR) << "Cras service is not available";
998 cras_service_available_ = false;
999 return;
1000 }
1001
1002 cras_service_available_ = true;
1003 GetDefaultOutputBufferSizeInternal();
1004 GetSystemAecSupported();
1005 GetSystemAecGroupId();
1006 GetNodes();
1007 GetNumberOfOutputStreams();
1008 CrasAudioClient::Get()->SetFixA2dpPacketSize(base::FeatureList::IsEnabled(
1009 chromeos::features::kBluetoothFixA2dpPacketSize));
1010
1011 // When the BluetoothWbsDogfood feature flag is enabled, don't bother
1012 // calling GetDeprioritizeBtWbsMic().
1013 // Otherwise override the Bluetooth WBS mic's priority according to the
1014 // |deprioritize_bt_wbs_mic| value returned by CRAS.
1015 if (!base::FeatureList::IsEnabled(chromeos::features::kBluetoothWbsDogfood)) {
1016 CrasAudioClient::Get()->GetDeprioritizeBtWbsMic(
1017 base::BindOnce(&CrasAudioHandler::HandleGetDeprioritizeBtWbsMic,
1018 weak_ptr_factory_.GetWeakPtr()));
1019 }
1020 }
1021
ApplyAudioPolicy()1022 void CrasAudioHandler::ApplyAudioPolicy() {
1023 output_mute_locked_ = false;
1024 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) {
1025 // Mute the device, but do not update the preference.
1026 SetOutputMuteInternal(true);
1027 output_mute_locked_ = true;
1028 } else {
1029 // Restore the mute state.
1030 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
1031 if (device)
1032 SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device));
1033 }
1034
1035 // Policy for audio input is handled by kAudioCaptureAllowed in the Chrome
1036 // media system.
1037 }
1038
SetOutputNodeVolume(uint64_t node_id,int volume)1039 void CrasAudioHandler::SetOutputNodeVolume(uint64_t node_id, int volume) {
1040 CrasAudioClient::Get()->SetOutputNodeVolume(node_id, volume);
1041 }
1042
SetOutputNodeVolumePercent(uint64_t node_id,int volume_percent)1043 void CrasAudioHandler::SetOutputNodeVolumePercent(uint64_t node_id,
1044 int volume_percent) {
1045 const AudioDevice* device = GetDeviceFromId(node_id);
1046 if (!device || device->is_input)
1047 return;
1048
1049 volume_percent = min(max(volume_percent, 0), 100);
1050 if (volume_percent <= kMuteThresholdPercent)
1051 volume_percent = 0;
1052
1053 // Save the volume setting in pref in case this is called on non-active
1054 // node for configuration.
1055 audio_pref_handler_->SetVolumeGainValue(*device, volume_percent);
1056
1057 if (device->active)
1058 SetOutputNodeVolume(node_id, volume_percent);
1059 }
1060
SetOutputMuteInternal(bool mute_on)1061 bool CrasAudioHandler::SetOutputMuteInternal(bool mute_on) {
1062 if (output_mute_locked_)
1063 return false;
1064
1065 output_mute_on_ = mute_on;
1066 CrasAudioClient::Get()->SetOutputUserMute(mute_on);
1067 return true;
1068 }
1069
SetInputNodeGain(uint64_t node_id,int gain)1070 void CrasAudioHandler::SetInputNodeGain(uint64_t node_id, int gain) {
1071 CrasAudioClient::Get()->SetInputNodeGain(node_id, gain);
1072 }
1073
SetInputNodeGainPercent(uint64_t node_id,int gain_percent)1074 void CrasAudioHandler::SetInputNodeGainPercent(uint64_t node_id,
1075 int gain_percent) {
1076 const AudioDevice* device = GetDeviceFromId(node_id);
1077 if (!device || !device->is_input)
1078 return;
1079
1080 // NOTE: We do not sanitize input gain values since the range is completely
1081 // dependent on the device.
1082 if (active_input_node_id_ == node_id)
1083 input_gain_ = gain_percent;
1084
1085 audio_pref_handler_->SetVolumeGainValue(*device, gain_percent);
1086
1087 if (device->active) {
1088 SetInputNodeGain(node_id, gain_percent);
1089 for (auto& observer : observers_)
1090 observer.OnInputNodeGainChanged(node_id, gain_percent);
1091 }
1092 }
1093
SetInputMuteInternal(bool mute_on)1094 void CrasAudioHandler::SetInputMuteInternal(bool mute_on) {
1095 input_mute_on_ = mute_on;
1096 CrasAudioClient::Get()->SetInputMute(mute_on);
1097 }
1098
GetNodes()1099 void CrasAudioHandler::GetNodes() {
1100 CrasAudioClient::Get()->GetNodes(base::BindOnce(
1101 &CrasAudioHandler::HandleGetNodes, weak_ptr_factory_.GetWeakPtr()));
1102 }
1103
GetNumberOfOutputStreams()1104 void CrasAudioHandler::GetNumberOfOutputStreams() {
1105 CrasAudioClient::Get()->GetNumberOfActiveOutputStreams(
1106 base::BindOnce(&CrasAudioHandler::HandleGetNumActiveOutputStreams,
1107 weak_ptr_factory_.GetWeakPtr()));
1108 }
1109
ChangeActiveDevice(const AudioDevice & new_active_device)1110 bool CrasAudioHandler::ChangeActiveDevice(
1111 const AudioDevice& new_active_device) {
1112 uint64_t& current_active_node_id = new_active_device.is_input
1113 ? active_input_node_id_
1114 : active_output_node_id_;
1115 // If the device we want to switch to is already the current active device,
1116 // do nothing.
1117 if (new_active_device.active &&
1118 new_active_device.id == current_active_node_id) {
1119 return false;
1120 }
1121
1122 bool found_new_active_device = false;
1123 // Reset all other input or output devices' active status. The active audio
1124 // device from the previous user session can be remembered by cras, but not
1125 // in chrome. see crbug.com/273271.
1126 for (auto& item : audio_devices_) {
1127 AudioDevice& device = item.second;
1128 if (device.is_input == new_active_device.is_input &&
1129 device.id != new_active_device.id) {
1130 device.active = false;
1131 } else if (device.is_input == new_active_device.is_input &&
1132 device.id == new_active_device.id) {
1133 found_new_active_device = true;
1134 }
1135 }
1136
1137 if (!found_new_active_device) {
1138 LOG(ERROR) << "Invalid new active device: " << new_active_device.ToString();
1139 return false;
1140 }
1141
1142 // Set the current active input/output device to the new_active_device.
1143 current_active_node_id = new_active_device.id;
1144 audio_devices_[current_active_node_id].active = true;
1145 return true;
1146 }
1147
SwitchToDevice(const AudioDevice & device,bool notify,DeviceActivateType activate_by)1148 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device,
1149 bool notify,
1150 DeviceActivateType activate_by) {
1151 if (!ChangeActiveDevice(device))
1152 return;
1153
1154 if (device.is_input)
1155 SetupAudioInputState();
1156 else
1157 SetupAudioOutputState();
1158
1159 SetActiveDevice(device, notify, activate_by);
1160
1161 // content::MediaStreamManager listens to
1162 // base::SystemMonitor::DevicesChangedObserver for audio devices,
1163 // and updates EnumerateDevices when OnDevicesChanged is called.
1164 base::SystemMonitor* monitor = base::SystemMonitor::Get();
1165 // In some unittest, |monitor| might be nullptr.
1166 if (!monitor)
1167 return;
1168 monitor->ProcessDevicesChanged(
1169 base::SystemMonitor::DeviceType::DEVTYPE_AUDIO);
1170 }
1171
HasDeviceChange(const AudioNodeList & new_nodes,bool is_input,AudioDevicePriorityQueue * new_discovered,bool * device_removed,bool * active_device_removed)1172 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes,
1173 bool is_input,
1174 AudioDevicePriorityQueue* new_discovered,
1175 bool* device_removed,
1176 bool* active_device_removed) {
1177 *device_removed = false;
1178 for (const auto& item : audio_devices_) {
1179 const AudioDevice& device = item.second;
1180 if (is_input != device.is_input)
1181 continue;
1182 if (!IsDeviceInList(device, new_nodes)) {
1183 *device_removed = true;
1184 if ((is_input && device.id == active_input_node_id_) ||
1185 (!is_input && device.id == active_output_node_id_)) {
1186 *active_device_removed = true;
1187 }
1188 }
1189 }
1190
1191 bool new_or_changed_device = false;
1192 while (!new_discovered->empty())
1193 new_discovered->pop();
1194
1195 for (const AudioNode& node : new_nodes) {
1196 if (is_input != node.is_input)
1197 continue;
1198 // Check if the new device is not in the old device list.
1199 AudioDevice device = ConvertAudioNodeWithModifiedPriority(node);
1200 DeviceStatus status = CheckDeviceStatus(device);
1201 if (status == NEW_DEVICE)
1202 new_discovered->push(device);
1203 if (status == NEW_DEVICE || status == CHANGED_DEVICE) {
1204 new_or_changed_device = true;
1205 }
1206 }
1207 return new_or_changed_device || *device_removed;
1208 }
1209
CheckDeviceStatus(const AudioDevice & device)1210 CrasAudioHandler::DeviceStatus CrasAudioHandler::CheckDeviceStatus(
1211 const AudioDevice& device) {
1212 const AudioDevice* device_found =
1213 GetDeviceFromStableDeviceId(device.stable_device_id);
1214 if (!device_found)
1215 return NEW_DEVICE;
1216
1217 if (!IsSameAudioDevice(device, *device_found)) {
1218 LOG(ERROR) << "Different Audio devices with same stable device id:"
1219 << " new device: " << device.ToString()
1220 << " old device: " << device_found->ToString();
1221 return CHANGED_DEVICE;
1222 }
1223 if (device.active != device_found->active)
1224 return CHANGED_DEVICE;
1225 return OLD_DEVICE;
1226 }
1227
NotifyActiveNodeChanged(bool is_input)1228 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) {
1229 if (is_input) {
1230 for (auto& observer : observers_)
1231 observer.OnActiveInputNodeChanged();
1232 } else {
1233 for (auto& observer : observers_)
1234 observer.OnActiveOutputNodeChanged();
1235 }
1236 }
1237
GetActiveDeviceFromUserPref(bool is_input,AudioDevice * active_device)1238 bool CrasAudioHandler::GetActiveDeviceFromUserPref(bool is_input,
1239 AudioDevice* active_device) {
1240 bool found_active_device = false;
1241 bool last_active_device_activate_by_user = false;
1242 for (const auto& item : audio_devices_) {
1243 const AudioDevice& device = item.second;
1244 if (device.is_input != is_input || !device.is_for_simple_usage())
1245 continue;
1246
1247 bool active = false;
1248 bool activate_by_user = false;
1249 // If the device entry is not found in prefs, it is likley a new audio
1250 // device plugged in after the cros is powered down. We should ignore the
1251 // previously saved active device, and select the active device by priority.
1252 // crbug.com/622045.
1253 if (!audio_pref_handler_->GetDeviceActive(device, &active,
1254 &activate_by_user)) {
1255 return false;
1256 }
1257
1258 if (!active)
1259 continue;
1260
1261 if (!found_active_device) {
1262 found_active_device = true;
1263 *active_device = device;
1264 last_active_device_activate_by_user = activate_by_user;
1265 continue;
1266 }
1267
1268 // Choose the best one among multiple active devices from prefs.
1269 if (activate_by_user) {
1270 if (last_active_device_activate_by_user) {
1271 // If there are more than one active devices activated by user in the
1272 // prefs, most likely, after the device was shut down, and before it
1273 // is rebooted, user has plugged in some previously unplugged audio
1274 // devices. For such case, it does not make sense to honor the active
1275 // states in the prefs.
1276 VLOG(1) << "Found more than one user activated devices in the prefs.";
1277 return false;
1278 }
1279 // Device activated by user has higher priority than the one
1280 // is not activated by user.
1281 *active_device = device;
1282 last_active_device_activate_by_user = true;
1283 } else if (!last_active_device_activate_by_user) {
1284 // If there are more than one active devices activated by priority in the
1285 // prefs, most likely, cras is still enumerating the audio devices
1286 // progressively. For such case, it does not make sense to honor the
1287 // active states in the prefs.
1288 VLOG(1) << "Found more than one active devices by priority in the prefs.";
1289 return false;
1290 }
1291 }
1292
1293 if (found_active_device && !active_device->is_for_simple_usage()) {
1294 // This is an odd case which is rare but possible to happen during cras
1295 // initialization depeneding the audio device enumation process. The only
1296 // audio node coming from cras is an internal audio device not visible
1297 // to user, such as AUDIO_TYPE_POST_MIX_LOOPBACK.
1298 return false;
1299 }
1300
1301 return found_active_device;
1302 }
1303
PauseAllStreams()1304 void CrasAudioHandler::PauseAllStreams() {
1305 if (media_controller_manager_)
1306 media_controller_manager_->SuspendAllSessions();
1307 }
1308
HandleNonHotplugNodesChange(bool is_input,const AudioDevicePriorityQueue & hotplug_nodes,bool has_device_change,bool has_device_removed,bool active_device_removed)1309 void CrasAudioHandler::HandleNonHotplugNodesChange(
1310 bool is_input,
1311 const AudioDevicePriorityQueue& hotplug_nodes,
1312 bool has_device_change,
1313 bool has_device_removed,
1314 bool active_device_removed) {
1315 bool has_current_active_node =
1316 is_input ? active_input_node_id_ : active_output_node_id_;
1317
1318 // No device change, extra NodesChanged signal received.
1319 if (!has_device_change && has_current_active_node)
1320 return;
1321
1322 if (hotplug_nodes.empty()) {
1323 if (has_device_removed) {
1324 if (!active_device_removed && has_current_active_node) {
1325 // Removed a non-active device, keep the current active device.
1326 return;
1327 }
1328
1329 if (active_device_removed) {
1330 // Pauses active streams when the active output device is
1331 // removed.
1332 if (!is_input)
1333 PauseAllStreams();
1334
1335 // Unplugged the current active device.
1336 SwitchToTopPriorityDevice(is_input);
1337
1338 return;
1339 }
1340 }
1341
1342 // Some unexpected error happens on cras side. See crbug.com/586026.
1343 // Either cras sent stale nodes to chrome again or cras triggered some
1344 // error. Restore the previously selected active.
1345 VLOG(1) << "Odd case from cras, the active node is lost unexpectedly.";
1346 SwitchToPreviousActiveDeviceIfAvailable(is_input);
1347 } else {
1348 // Looks like a new chrome session starts.
1349 SwitchToPreviousActiveDeviceIfAvailable(is_input);
1350 }
1351 }
1352
HandleHotPlugDevice(const AudioDevice & hotplug_device,const AudioDevicePriorityQueue & device_priority_queue)1353 void CrasAudioHandler::HandleHotPlugDevice(
1354 const AudioDevice& hotplug_device,
1355 const AudioDevicePriorityQueue& device_priority_queue) {
1356 // This most likely may happen during the transition period of cras
1357 // initialization phase, in which a non-simple-usage node may appear like
1358 // a hotplug node.
1359 if (!hotplug_device.is_for_simple_usage())
1360 return;
1361
1362 // Whenever 35mm headphone or mic is hot plugged, always pick it as the active
1363 // device.
1364 if (hotplug_device.type == AUDIO_TYPE_HEADPHONE ||
1365 hotplug_device.type == AUDIO_TYPE_MIC) {
1366 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_PRIORITY);
1367 return;
1368 }
1369
1370 bool last_state_active = false;
1371 bool last_activate_by_user = false;
1372 if (!audio_pref_handler_->GetDeviceActive(hotplug_device, &last_state_active,
1373 &last_activate_by_user)) {
1374 // |hotplug_device| is plugged in for the first time, activate it if it
1375 // is of the highest priority.
1376 if (device_priority_queue.top().id == hotplug_device.id) {
1377 VLOG(1) << "Hotplug a device for the first time: "
1378 << hotplug_device.ToString();
1379 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_PRIORITY);
1380 }
1381 } else if (last_state_active) {
1382 if (!last_activate_by_user &&
1383 device_priority_queue.top().id != hotplug_device.id) {
1384 // This handles crbug.com/698809. Before the device is powered off, unplug
1385 // the external output device, leave the internal audio device(such as
1386 // internal speaker) active. Then turn off the power, plug in the exteranl
1387 // device, turn on power. On some device, cras sends NodesChanged first
1388 // signal with only external device; then later it sends another
1389 // NodesChanged signal with internal audio device also discovered.
1390 // For such case, do not switch to the lower priority device which was
1391 // made active not by user's choice.
1392 return;
1393 }
1394
1395 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_RESTORE_PREVIOUS_STATE);
1396 } else {
1397 // The hot plugged device was not active last time it was plugged in.
1398 // Let's check how the current active device is activated, if it is not
1399 // activated by user choice, then select the hot plugged device it is of
1400 // higher priority.
1401 uint64_t& active_node_id = hotplug_device.is_input ? active_input_node_id_
1402 : active_output_node_id_;
1403 const AudioDevice* active_device = GetDeviceFromId(active_node_id);
1404 if (!active_device) {
1405 // Can't find any current active device.
1406 // This is an odd case, but if it happens, switch to hotplug device.
1407 LOG(ERROR) << "Can not find current active device when the device is"
1408 << " hot plugged: " << hotplug_device.ToString();
1409 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_PRIORITY);
1410 return;
1411 }
1412
1413 bool activate_by_user = false;
1414 bool state_active = false;
1415 bool found_active_state = audio_pref_handler_->GetDeviceActive(
1416 *active_device, &state_active, &activate_by_user);
1417 DCHECK(found_active_state && state_active);
1418 if (!found_active_state || !state_active) {
1419 LOG(ERROR) << "Cannot retrieve current active device's state in prefs: "
1420 << active_device->ToString();
1421 return;
1422 }
1423 if (!activate_by_user &&
1424 device_priority_queue.top().id == hotplug_device.id) {
1425 SwitchToDevice(hotplug_device, true, ACTIVATE_BY_PRIORITY);
1426 } else {
1427 // Do not active the hotplug device. Either the current device is
1428 // expliciltly activated by user, or the hotplug device is of lower
1429 // priority.
1430 VLOG(1) << "Hotplug device remains inactive as its previous state:"
1431 << hotplug_device.ToString();
1432 }
1433 }
1434 }
1435
SwitchToTopPriorityDevice(bool is_input)1436 void CrasAudioHandler::SwitchToTopPriorityDevice(bool is_input) {
1437 AudioDevice top_device =
1438 is_input ? input_devices_pq_.top() : output_devices_pq_.top();
1439 if (!top_device.is_for_simple_usage())
1440 return;
1441
1442 // For the dual camera and dual microphone case, choose microphone
1443 // that is consistent to the active camera.
1444 if (IsFrontOrRearMic(top_device) && HasDualInternalMic() && IsCameraOn()) {
1445 ActivateInternalMicForActiveCamera();
1446 return;
1447 }
1448
1449 SwitchToDevice(top_device, true, ACTIVATE_BY_PRIORITY);
1450 }
1451
SwitchToPreviousActiveDeviceIfAvailable(bool is_input)1452 void CrasAudioHandler::SwitchToPreviousActiveDeviceIfAvailable(bool is_input) {
1453 AudioDevice previous_active_device;
1454 if (GetActiveDeviceFromUserPref(is_input, &previous_active_device)) {
1455 DCHECK(previous_active_device.is_for_simple_usage());
1456 // Switch to previous active device stored in user prefs.
1457 SwitchToDevice(previous_active_device, true,
1458 ACTIVATE_BY_RESTORE_PREVIOUS_STATE);
1459 } else {
1460 // No previous active device, switch to the top priority device.
1461 SwitchToTopPriorityDevice(is_input);
1462 }
1463 }
1464
UpdateDevicesAndSwitchActive(const AudioNodeList & nodes)1465 void CrasAudioHandler::UpdateDevicesAndSwitchActive(
1466 const AudioNodeList& nodes) {
1467 size_t old_output_device_size = 0;
1468 size_t old_input_device_size = 0;
1469 for (const auto& item : audio_devices_) {
1470 const AudioDevice& device = item.second;
1471 if (device.is_input)
1472 ++old_input_device_size;
1473 else
1474 ++old_output_device_size;
1475 }
1476
1477 AudioDevicePriorityQueue hotplug_output_nodes;
1478 AudioDevicePriorityQueue hotplug_input_nodes;
1479 bool has_output_removed = false;
1480 bool has_input_removed = false;
1481 bool active_output_removed = false;
1482 bool active_input_removed = false;
1483 bool output_devices_changed =
1484 HasDeviceChange(nodes, false, &hotplug_output_nodes, &has_output_removed,
1485 &active_output_removed);
1486 bool input_devices_changed =
1487 HasDeviceChange(nodes, true, &hotplug_input_nodes, &has_input_removed,
1488 &active_input_removed);
1489 audio_devices_.clear();
1490 has_alternative_input_ = false;
1491 has_alternative_output_ = false;
1492
1493 while (!input_devices_pq_.empty())
1494 input_devices_pq_.pop();
1495 while (!output_devices_pq_.empty())
1496 output_devices_pq_.pop();
1497
1498 size_t new_output_device_size = 0;
1499 size_t new_input_device_size = 0;
1500 for (size_t i = 0; i < nodes.size(); ++i) {
1501 AudioDevice device = ConvertAudioNodeWithModifiedPriority(nodes[i]);
1502 audio_devices_[device.id] = device;
1503 if (!has_alternative_input_ && device.is_input &&
1504 device.IsExternalDevice()) {
1505 has_alternative_input_ = true;
1506 } else if (!has_alternative_output_ && !device.is_input &&
1507 device.IsExternalDevice()) {
1508 has_alternative_output_ = true;
1509 }
1510
1511 if (device.is_input) {
1512 input_devices_pq_.push(device);
1513 ++new_input_device_size;
1514 } else {
1515 output_devices_pq_.push(device);
1516 ++new_output_device_size;
1517 }
1518 }
1519
1520 // Handle output device changes.
1521 HandleAudioDeviceChange(false, output_devices_pq_, hotplug_output_nodes,
1522 output_devices_changed, has_output_removed,
1523 active_output_removed);
1524
1525 // Handle input device changes.
1526 HandleAudioDeviceChange(true, input_devices_pq_, hotplug_input_nodes,
1527 input_devices_changed, has_input_removed,
1528 active_input_removed);
1529
1530 // content::MediaStreamManager listens to
1531 // base::SystemMonitor::DevicesChangedObserver for audio devices,
1532 // and updates EnumerateDevices when OnDevicesChanged is called.
1533 base::SystemMonitor* monitor = base::SystemMonitor::Get();
1534 // In some unittest, |monitor| might be nullptr.
1535 if (!monitor)
1536 return;
1537 monitor->ProcessDevicesChanged(
1538 base::SystemMonitor::DeviceType::DEVTYPE_AUDIO);
1539 }
1540
HandleAudioDeviceChange(bool is_input,const AudioDevicePriorityQueue & devices_pq,const AudioDevicePriorityQueue & hotplug_nodes,bool has_device_change,bool has_device_removed,bool active_device_removed)1541 void CrasAudioHandler::HandleAudioDeviceChange(
1542 bool is_input,
1543 const AudioDevicePriorityQueue& devices_pq,
1544 const AudioDevicePriorityQueue& hotplug_nodes,
1545 bool has_device_change,
1546 bool has_device_removed,
1547 bool active_device_removed) {
1548 uint64_t& active_node_id =
1549 is_input ? active_input_node_id_ : active_output_node_id_;
1550
1551 // No audio devices found.
1552 if (devices_pq.empty()) {
1553 VLOG(1) << "No " << (is_input ? "input" : "output") << " devices found";
1554 active_node_id = 0;
1555 NotifyActiveNodeChanged(is_input);
1556 return;
1557 }
1558
1559 // If the previous active device is removed from the new node list,
1560 // or changed to inactive by cras, reset active_node_id.
1561 // See crbug.com/478968.
1562 const AudioDevice* active_device = GetDeviceFromId(active_node_id);
1563 if (!active_device || !active_device->active)
1564 active_node_id = 0;
1565
1566 if (!active_node_id || hotplug_nodes.empty() || hotplug_nodes.size() > 1) {
1567 HandleNonHotplugNodesChange(is_input, hotplug_nodes, has_device_change,
1568 has_device_removed, active_device_removed);
1569 } else {
1570 // Typical user hotplug case.
1571 HandleHotPlugDevice(hotplug_nodes.top(), devices_pq);
1572 }
1573 }
1574
HandleGetNodes(base::Optional<chromeos::AudioNodeList> node_list)1575 void CrasAudioHandler::HandleGetNodes(
1576 base::Optional<chromeos::AudioNodeList> node_list) {
1577 if (!node_list.has_value()) {
1578 LOG(ERROR) << "Failed to retrieve audio nodes data";
1579 return;
1580 }
1581
1582 if (node_list->empty())
1583 return;
1584
1585 UpdateDevicesAndSwitchActive(node_list.value());
1586 for (auto& observer : observers_)
1587 observer.OnAudioNodesChanged();
1588 }
1589
HandleGetNumActiveOutputStreams(base::Optional<int> new_output_streams_count)1590 void CrasAudioHandler::HandleGetNumActiveOutputStreams(
1591 base::Optional<int> new_output_streams_count) {
1592 if (!new_output_streams_count.has_value()) {
1593 LOG(ERROR) << "Failed to retrieve number of active output streams";
1594 return;
1595 }
1596
1597 DCHECK(*new_output_streams_count >= 0);
1598 if (*new_output_streams_count > 0 && num_active_output_streams_ == 0) {
1599 for (auto& observer : observers_)
1600 observer.OnOutputStarted();
1601 } else if (*new_output_streams_count == 0 && num_active_output_streams_ > 0) {
1602 for (auto& observer : observers_)
1603 observer.OnOutputStopped();
1604 }
1605 num_active_output_streams_ = *new_output_streams_count;
1606 }
1607
HandleGetDeprioritizeBtWbsMic(base::Optional<bool> deprioritize_bt_wbs_mic)1608 void CrasAudioHandler::HandleGetDeprioritizeBtWbsMic(
1609 base::Optional<bool> deprioritize_bt_wbs_mic) {
1610 if (!deprioritize_bt_wbs_mic.has_value()) {
1611 LOG(ERROR) << "Failed to retrieve WBS mic deprioritized flag";
1612 return;
1613 }
1614 deprioritize_bt_wbs_mic_ = *deprioritize_bt_wbs_mic;
1615 }
1616
AddAdditionalActiveNode(uint64_t node_id,bool notify)1617 void CrasAudioHandler::AddAdditionalActiveNode(uint64_t node_id, bool notify) {
1618 const AudioDevice* device = GetDeviceFromId(node_id);
1619 if (!device) {
1620 VLOG(1) << "AddActiveInputNode: Cannot find device id="
1621 << "0x" << std::hex << node_id;
1622 return;
1623 }
1624
1625 audio_devices_[node_id].active = true;
1626 SetupAdditionalActiveAudioNodeState(node_id);
1627
1628 if (device->is_input) {
1629 DCHECK(node_id != active_input_node_id_);
1630 CrasAudioClient::Get()->AddActiveInputNode(node_id);
1631 if (notify)
1632 NotifyActiveNodeChanged(true);
1633 } else {
1634 DCHECK(node_id != active_output_node_id_);
1635 CrasAudioClient::Get()->AddActiveOutputNode(node_id);
1636 if (notify)
1637 NotifyActiveNodeChanged(false);
1638 }
1639 }
1640
RemoveActiveNodeInternal(uint64_t node_id,bool notify)1641 void CrasAudioHandler::RemoveActiveNodeInternal(uint64_t node_id, bool notify) {
1642 const AudioDevice* device = GetDeviceFromId(node_id);
1643 if (!device) {
1644 VLOG(1) << "RemoveActiveInputNode: Cannot find device id="
1645 << "0x" << std::hex << node_id;
1646 return;
1647 }
1648
1649 audio_devices_[node_id].active = false;
1650 if (device->is_input) {
1651 if (node_id == active_input_node_id_)
1652 active_input_node_id_ = 0;
1653 CrasAudioClient::Get()->RemoveActiveInputNode(node_id);
1654 if (notify)
1655 NotifyActiveNodeChanged(true);
1656 } else {
1657 if (node_id == active_output_node_id_)
1658 active_output_node_id_ = 0;
1659 CrasAudioClient::Get()->RemoveActiveOutputNode(node_id);
1660 if (notify)
1661 NotifyActiveNodeChanged(false);
1662 }
1663 }
1664
UpdateAudioAfterHDMIRediscoverGracePeriod()1665 void CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod() {
1666 VLOG(1) << "HDMI output re-discover grace period ends.";
1667 hdmi_rediscovering_ = false;
1668 if (!IsOutputMutedForDevice(active_output_node_id_)) {
1669 // Unmute the audio output after the HDMI transition period.
1670 VLOG(1) << "Unmute output after HDMI rediscovering grace period.";
1671 SetOutputMuteInternal(false);
1672
1673 // Notify UI about the mute state change.
1674 for (auto& observer : observers_)
1675 observer.OnOutputMuteChanged(output_mute_on_);
1676 }
1677 }
1678
IsHDMIPrimaryOutputDevice() const1679 bool CrasAudioHandler::IsHDMIPrimaryOutputDevice() const {
1680 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
1681 return device && device->type == AUDIO_TYPE_HDMI;
1682 }
1683
StartHDMIRediscoverGracePeriod()1684 void CrasAudioHandler::StartHDMIRediscoverGracePeriod() {
1685 VLOG(1) << "Start HDMI rediscovering grace period.";
1686 hdmi_rediscovering_ = true;
1687 hdmi_rediscover_timer_.Stop();
1688 hdmi_rediscover_timer_.Start(
1689 FROM_HERE, base::TimeDelta::FromMilliseconds(
1690 hdmi_rediscover_grace_period_duration_in_ms_),
1691 this, &CrasAudioHandler::UpdateAudioAfterHDMIRediscoverGracePeriod);
1692 }
1693
SetHDMIRediscoverGracePeriodForTesting(int duration_in_ms)1694 void CrasAudioHandler::SetHDMIRediscoverGracePeriodForTesting(
1695 int duration_in_ms) {
1696 hdmi_rediscover_grace_period_duration_in_ms_ = duration_in_ms;
1697 }
1698
ActivateMicForCamera(media::VideoFacingMode camera_facing)1699 void CrasAudioHandler::ActivateMicForCamera(
1700 media::VideoFacingMode camera_facing) {
1701 const AudioDevice* mic = GetMicForCamera(camera_facing);
1702 if (!mic || mic->active)
1703 return;
1704
1705 SwitchToDevice(*mic, true, ACTIVATE_BY_CAMERA);
1706 }
1707
ActivateInternalMicForActiveCamera()1708 void CrasAudioHandler::ActivateInternalMicForActiveCamera() {
1709 DCHECK(IsCameraOn());
1710 if (HasDualInternalMic()) {
1711 media::VideoFacingMode facing = front_camera_on_
1712 ? media::MEDIA_VIDEO_FACING_USER
1713 : media::MEDIA_VIDEO_FACING_ENVIRONMENT;
1714 ActivateMicForCamera(facing);
1715 }
1716 }
1717
1718 // For the dual microphone case, from user point of view, they only see internal
1719 // microphone in UI. Chrome will make the best decision on which one to pick.
1720 // If the camera is off, the front microphone should be picked as the default
1721 // active microphone. Otherwise, it will switch to the microphone that
1722 // matches the active camera, i.e. front microphone for front camera and
1723 // rear microphone for rear camera.
SwitchToFrontOrRearMic()1724 void CrasAudioHandler::SwitchToFrontOrRearMic() {
1725 DCHECK(HasDualInternalMic());
1726 if (IsCameraOn()) {
1727 ActivateInternalMicForActiveCamera();
1728 } else {
1729 SwitchToDevice(*GetDeviceByType(AUDIO_TYPE_FRONT_MIC), true,
1730 ACTIVATE_BY_USER);
1731 }
1732 }
1733
GetMicForCamera(media::VideoFacingMode camera_facing)1734 const AudioDevice* CrasAudioHandler::GetMicForCamera(
1735 media::VideoFacingMode camera_facing) {
1736 switch (camera_facing) {
1737 case media::MEDIA_VIDEO_FACING_USER:
1738 return GetDeviceByType(AUDIO_TYPE_FRONT_MIC);
1739 case media::MEDIA_VIDEO_FACING_ENVIRONMENT:
1740 return GetDeviceByType(AUDIO_TYPE_REAR_MIC);
1741 default:
1742 NOTREACHED();
1743 }
1744 return nullptr;
1745 }
1746
HasDualInternalMic() const1747 bool CrasAudioHandler::HasDualInternalMic() const {
1748 bool has_front_mic = false;
1749 bool has_rear_mic = false;
1750 for (const auto& item : audio_devices_) {
1751 const AudioDevice& device = item.second;
1752 if (device.type == AUDIO_TYPE_FRONT_MIC)
1753 has_front_mic = true;
1754 else if (device.type == AUDIO_TYPE_REAR_MIC)
1755 has_rear_mic = true;
1756 if (has_front_mic && has_rear_mic)
1757 break;
1758 }
1759 return has_front_mic && has_rear_mic;
1760 }
1761
IsFrontOrRearMic(const AudioDevice & device) const1762 bool CrasAudioHandler::IsFrontOrRearMic(const AudioDevice& device) const {
1763 return device.is_input && (device.type == AUDIO_TYPE_FRONT_MIC ||
1764 device.type == AUDIO_TYPE_REAR_MIC);
1765 }
1766
IsCameraOn() const1767 bool CrasAudioHandler::IsCameraOn() const {
1768 return front_camera_on_ || rear_camera_on_;
1769 }
1770
HasExternalDevice(bool is_input) const1771 bool CrasAudioHandler::HasExternalDevice(bool is_input) const {
1772 for (const auto& item : audio_devices_) {
1773 const AudioDevice& device = item.second;
1774 if (is_input == device.is_input && device.IsExternalDevice())
1775 return true;
1776 }
1777 return false;
1778 }
1779
GetDefaultOutputBufferSizeInternal()1780 void CrasAudioHandler::GetDefaultOutputBufferSizeInternal() {
1781 CrasAudioClient::Get()->GetDefaultOutputBufferSize(
1782 base::BindOnce(&CrasAudioHandler::HandleGetDefaultOutputBufferSize,
1783 weak_ptr_factory_.GetWeakPtr()));
1784 }
1785
HandleGetDefaultOutputBufferSize(base::Optional<int> buffer_size)1786 void CrasAudioHandler::HandleGetDefaultOutputBufferSize(
1787 base::Optional<int> buffer_size) {
1788 if (!buffer_size.has_value()) {
1789 LOG(ERROR) << "Failed to retrieve output buffer size";
1790 return;
1791 }
1792
1793 default_output_buffer_size_ = buffer_size.value();
1794 }
1795
system_aec_supported() const1796 bool CrasAudioHandler::system_aec_supported() const {
1797 DCHECK(main_task_runner_->BelongsToCurrentThread());
1798 return system_aec_supported_;
1799 }
1800
1801 // GetSystemAecSupported() is only called in the same thread
1802 // as the CrasAudioHanler constructor. We are safe here without
1803 // thread check, because unittest may not have the task runner
1804 // for the current thread.
GetSystemAecSupported()1805 void CrasAudioHandler::GetSystemAecSupported() {
1806 CrasAudioClient::Get()->GetSystemAecSupported(
1807 base::BindOnce(&CrasAudioHandler::HandleGetSystemAecSupported,
1808 weak_ptr_factory_.GetWeakPtr()));
1809 }
1810
HandleGetSystemAecSupported(base::Optional<bool> system_aec_supported)1811 void CrasAudioHandler::HandleGetSystemAecSupported(
1812 base::Optional<bool> system_aec_supported) {
1813 if (!system_aec_supported.has_value()) {
1814 LOG(ERROR) << "Failed to retrieve system aec supported";
1815 return;
1816 }
1817 system_aec_supported_ = system_aec_supported.value();
1818 }
1819
system_aec_group_id() const1820 int32_t CrasAudioHandler::system_aec_group_id() const {
1821 DCHECK(main_task_runner_->BelongsToCurrentThread());
1822 return system_aec_group_id_;
1823 }
1824
1825 // GetSystemAecGroupId() is only called in the same thread
1826 // as the CrasAudioHanler constructor. We are safe here without
1827 // thread check, because unittest may not have the task runner
1828 // for the current thread.
GetSystemAecGroupId()1829 void CrasAudioHandler::GetSystemAecGroupId() {
1830 CrasAudioClient::Get()->GetSystemAecGroupId(
1831 base::BindOnce(&CrasAudioHandler::HandleGetSystemAecGroupId,
1832 weak_ptr_factory_.GetWeakPtr()));
1833 }
1834
HandleGetSystemAecGroupId(base::Optional<int32_t> system_aec_group_id)1835 void CrasAudioHandler::HandleGetSystemAecGroupId(
1836 base::Optional<int32_t> system_aec_group_id) {
1837 if (!system_aec_group_id.has_value()) {
1838 // If the group Id is not available, set the ID to reflect that.
1839 system_aec_group_id_ = kSystemAecGroupIdNotAvailable;
1840 return;
1841 }
1842 system_aec_group_id_ = system_aec_group_id.value();
1843 }
1844
1845 } // namespace chromeos
1846