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