Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / chromeos / audio / cras_audio_handler.cc
blob295f28089aa04e3dcde7e20bba82a36b855aed6f
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.
5 #include "chromeos/audio/cras_audio_handler.h"
7 #include <algorithm>
8 #include <cmath>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/logging.h"
13 #include "chromeos/audio/audio_devices_pref_handler.h"
14 #include "chromeos/audio/audio_devices_pref_handler_stub.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
17 using std::max;
18 using std::min;
20 namespace chromeos {
22 namespace {
24 // Default value for unmuting, as a percent in the range [0, 100].
25 // Used when sound is unmuted, but volume was less than kMuteThresholdPercent.
26 const int kDefaultUnmuteVolumePercent = 4;
28 // Volume value which should be considered as muted in range [0, 100].
29 const int kMuteThresholdPercent = 1;
31 static CrasAudioHandler* g_cras_audio_handler = NULL;
33 bool IsSameAudioDevice(const AudioDevice& a, const AudioDevice& b) {
34 return a.id == b.id && a.is_input == b.is_input && a.type == b.type
35 && a.device_name == b.device_name;
38 } // namespace
40 CrasAudioHandler::AudioObserver::AudioObserver() {
43 CrasAudioHandler::AudioObserver::~AudioObserver() {
46 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() {
49 void CrasAudioHandler::AudioObserver::OnInputGainChanged() {
52 void CrasAudioHandler::AudioObserver::OnOutputMuteChanged() {
55 void CrasAudioHandler::AudioObserver::OnInputMuteChanged() {
58 void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() {
61 void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() {
64 void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() {
67 // static
68 void CrasAudioHandler::Initialize(
69 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler) {
70 CHECK(!g_cras_audio_handler);
71 g_cras_audio_handler = new CrasAudioHandler(audio_pref_handler);
74 // static
75 void CrasAudioHandler::InitializeForTesting() {
76 CHECK(!g_cras_audio_handler);
77 CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub());
80 // static
81 void CrasAudioHandler::Shutdown() {
82 CHECK(g_cras_audio_handler);
83 delete g_cras_audio_handler;
84 g_cras_audio_handler = NULL;
87 // static
88 bool CrasAudioHandler::IsInitialized() {
89 return g_cras_audio_handler != NULL;
92 // static
93 CrasAudioHandler* CrasAudioHandler::Get() {
94 CHECK(g_cras_audio_handler)
95 << "CrasAudioHandler::Get() called before Initialize().";
96 return g_cras_audio_handler;
99 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) {
100 observers_.AddObserver(observer);
103 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) {
104 observers_.RemoveObserver(observer);
107 bool CrasAudioHandler::HasKeyboardMic() {
108 return GetKeyboardMic() != NULL;
111 bool CrasAudioHandler::IsOutputMuted() {
112 return output_mute_on_;
115 bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id) {
116 const AudioDevice* device = GetDeviceFromId(device_id);
117 if (!device)
118 return false;
119 DCHECK(!device->is_input);
120 return audio_pref_handler_->GetMuteValue(*device);
123 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLevel() {
124 return output_volume_ <= kMuteThresholdPercent;
127 bool CrasAudioHandler::IsInputMuted() {
128 return input_mute_on_;
131 bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) {
132 const AudioDevice* device = GetDeviceFromId(device_id);
133 if (!device)
134 return false;
135 DCHECK(device->is_input);
136 // We don't record input mute state for each device in the prefs,
137 // for any non-active input device, we assume mute is off.
138 if (device->id == active_input_node_id_)
139 return input_mute_on_;
140 return false;
143 int CrasAudioHandler::GetOutputDefaultVolumeMuteThreshold() {
144 return kMuteThresholdPercent;
147 int CrasAudioHandler::GetOutputVolumePercent() {
148 return output_volume_;
151 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64 device_id) {
152 if (device_id == active_output_node_id_) {
153 return output_volume_;
154 } else {
155 const AudioDevice* device = GetDeviceFromId(device_id);
156 return static_cast<int>(audio_pref_handler_->GetOutputVolumeValue(device));
160 int CrasAudioHandler::GetInputGainPercent() {
161 return input_gain_;
164 int CrasAudioHandler::GetInputGainPercentForDevice(uint64 device_id) {
165 if (device_id == active_input_node_id_) {
166 return input_gain_;
167 } else {
168 const AudioDevice* device = GetDeviceFromId(device_id);
169 return static_cast<int>(audio_pref_handler_->GetInputGainValue(device));
173 uint64 CrasAudioHandler::GetActiveOutputNode() const {
174 return active_output_node_id_;
177 uint64 CrasAudioHandler::GetActiveInputNode() const {
178 return active_input_node_id_;
181 void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const {
182 device_list->clear();
183 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
184 it != audio_devices_.end(); ++it)
185 device_list->push_back(it->second);
188 bool CrasAudioHandler::GetActiveOutputDevice(AudioDevice* device) const {
189 const AudioDevice* active_device = GetDeviceFromId(active_output_node_id_);
190 if (!active_device || !device)
191 return false;
192 *device = *active_device;
193 return true;
196 void CrasAudioHandler::SetKeyboardMicActive(bool active) {
197 const AudioDevice* keyboard_mic = GetKeyboardMic();
198 if (!keyboard_mic)
199 return;
200 if (active) {
201 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
202 AddActiveInputNode(keyboard_mic->id);
203 } else {
204 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
205 RemoveActiveInputNode(keyboard_mic->id);
209 bool CrasAudioHandler::has_alternative_input() const {
210 return has_alternative_input_;
213 bool CrasAudioHandler::has_alternative_output() const {
214 return has_alternative_output_;
217 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) {
218 volume_percent = min(max(volume_percent, 0), 100);
219 if (volume_percent <= kMuteThresholdPercent)
220 volume_percent = 0;
221 output_volume_ = volume_percent;
223 if (const AudioDevice* device = GetDeviceFromId(active_output_node_id_))
224 audio_pref_handler_->SetVolumeGainValue(*device, output_volume_);
226 SetOutputNodeVolume(active_output_node_id_, output_volume_);
227 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged());
230 // TODO: Rename the 'Percent' to something more meaningful.
231 void CrasAudioHandler::SetInputGainPercent(int gain_percent) {
232 // NOTE: We do not sanitize input gain values since the range is completely
233 // dependent on the device.
234 input_gain_ = gain_percent;
236 if (const AudioDevice* device = GetDeviceFromId(active_input_node_id_))
237 audio_pref_handler_->SetVolumeGainValue(*device, input_gain_);
239 SetInputNodeGain(active_input_node_id_, input_gain_);
240 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputGainChanged());
243 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) {
244 SetOutputVolumePercent(output_volume_ + adjust_by_percent);
247 void CrasAudioHandler::SetOutputMute(bool mute_on) {
248 if (!SetOutputMuteInternal(mute_on))
249 return;
251 if (const AudioDevice* device = GetDeviceFromId(active_output_node_id_)) {
252 DCHECK(!device->is_input);
253 audio_pref_handler_->SetMuteValue(*device, output_mute_on_);
256 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged());
259 void CrasAudioHandler::AdjustOutputVolumeToAudibleLevel() {
260 if (output_volume_ <= kMuteThresholdPercent) {
261 // Avoid the situation when sound has been unmuted, but the volume
262 // is set to a very low value, so user still can't hear any sound.
263 SetOutputVolumePercent(kDefaultUnmuteVolumePercent);
267 void CrasAudioHandler::SetInputMute(bool mute_on) {
268 if (!SetInputMuteInternal(mute_on))
269 return;
271 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputMuteChanged());
274 void CrasAudioHandler::SetActiveOutputNode(uint64 node_id) {
275 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
276 SetActiveOutputNode(node_id);
277 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged());
280 void CrasAudioHandler::SetActiveInputNode(uint64 node_id) {
281 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
282 SetActiveInputNode(node_id);
283 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged());
286 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64 device_id,
287 int value) {
288 if (device_id == active_output_node_id_) {
289 SetOutputVolumePercent(value);
290 return;
291 } else if (device_id == active_input_node_id_) {
292 SetInputGainPercent(value);
293 return;
296 if (const AudioDevice* device = GetDeviceFromId(device_id)) {
297 if (!device->is_input) {
298 value = min(max(value, 0), 100);
299 if (value <= kMuteThresholdPercent)
300 value = 0;
302 audio_pref_handler_->SetVolumeGainValue(*device, value);
306 void CrasAudioHandler::SetMuteForDevice(uint64 device_id, bool mute_on) {
307 if (device_id == active_output_node_id_) {
308 SetOutputMute(mute_on);
309 return;
310 } else if (device_id == active_input_node_id_) {
311 VLOG(1) << "SetMuteForDevice sets active input device id="
312 << "0x" << std::hex << device_id << " mute=" << mute_on;
313 SetInputMute(mute_on);
314 return;
317 const AudioDevice* device = GetDeviceFromId(device_id);
318 // Input device's mute state is not recorded in the pref. crbug.com/365050.
319 if (device && !device->is_input)
320 audio_pref_handler_->SetMuteValue(*device, mute_on);
323 void CrasAudioHandler::LogErrors() {
324 log_errors_ = true;
327 CrasAudioHandler::CrasAudioHandler(
328 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler)
329 : audio_pref_handler_(audio_pref_handler),
330 weak_ptr_factory_(this),
331 output_mute_on_(false),
332 input_mute_on_(false),
333 output_volume_(0),
334 input_gain_(0),
335 active_output_node_id_(0),
336 active_input_node_id_(0),
337 has_alternative_input_(false),
338 has_alternative_output_(false),
339 output_mute_locked_(false),
340 input_mute_locked_(false),
341 log_errors_(false) {
342 if (!audio_pref_handler.get())
343 return;
344 // If the DBusThreadManager or the CrasAudioClient aren't available, there
345 // isn't much we can do. This should only happen when running tests.
346 if (!chromeos::DBusThreadManager::IsInitialized() ||
347 !chromeos::DBusThreadManager::Get() ||
348 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
349 return;
350 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this);
351 audio_pref_handler_->AddAudioPrefObserver(this);
352 if (chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) {
353 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
354 AddObserver(this);
356 InitializeAudioState();
359 CrasAudioHandler::~CrasAudioHandler() {
360 if (!chromeos::DBusThreadManager::IsInitialized() ||
361 !chromeos::DBusThreadManager::Get() ||
362 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
363 return;
364 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
365 RemoveObserver(this);
366 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
367 RemoveObserver(this);
368 if (audio_pref_handler_.get())
369 audio_pref_handler_->RemoveAudioPrefObserver(this);
370 audio_pref_handler_ = NULL;
373 void CrasAudioHandler::AudioClientRestarted() {
374 // Make sure the logging is enabled in case cras server
375 // restarts after crashing.
376 LogErrors();
377 InitializeAudioState();
380 void CrasAudioHandler::NodesChanged() {
381 // Refresh audio nodes data.
382 GetNodes();
385 void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id) {
386 if (active_output_node_id_ == node_id)
387 return;
389 // Active audio output device should always be changed by chrome.
390 // During system boot, cras may change active input to unknown device 0x1,
391 // we don't need to log it, since it is not an valid device.
392 if (GetDeviceFromId(node_id)) {
393 LOG_IF(WARNING, log_errors_)
394 << "Active output node changed unexpectedly by system node_id="
395 << "0x" << std::hex << node_id;
399 void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id) {
400 if (active_input_node_id_ == node_id)
401 return;
403 // Active audio input device should always be changed by chrome.
404 // During system boot, cras may change active input to unknown device 0x2,
405 // we don't need to log it, since it is not an valid device.
406 if (GetDeviceFromId(node_id)) {
407 LOG_IF(WARNING, log_errors_)
408 << "Active input node changed unexpectedly by system node_id="
409 << "0x" << std::hex << node_id;
413 void CrasAudioHandler::OnAudioPolicyPrefChanged() {
414 ApplyAudioPolicy();
417 void CrasAudioHandler::EmitLoginPromptVisibleCalled() {
418 // Enable logging after cras server is started, which will be after
419 // EmitLoginPromptVisible.
420 LogErrors();
423 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64 device_id) const {
424 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id);
425 if (it == audio_devices_.end())
426 return NULL;
428 return &(it->second);
431 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const {
432 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
433 it != audio_devices_.end(); it++) {
434 if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC)
435 return &(it->second);
437 return NULL;
440 void CrasAudioHandler::SetupAudioInputState() {
441 // Set the initial audio state to the ones read from audio prefs.
442 const AudioDevice* device = GetDeviceFromId(active_input_node_id_);
443 if (!device) {
444 LOG_IF(ERROR, log_errors_)
445 << "Can't set up audio state for unknown input device id ="
446 << "0x" << std::hex << active_input_node_id_;
447 return;
449 input_gain_ = audio_pref_handler_->GetInputGainValue(device);
450 VLOG(1) << "SetupAudioInputState for active device id="
451 << "0x" << std::hex << device->id << " mute=" << input_mute_on_;
452 SetInputMuteInternal(input_mute_on_);
453 // TODO(rkc,jennyz): Set input gain once we decide on how to store
454 // the gain values since the range and step are both device specific.
457 void CrasAudioHandler::SetupAudioOutputState() {
458 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
459 if (!device) {
460 LOG_IF(ERROR, log_errors_)
461 << "Can't set up audio state for unknown output device id ="
462 << "0x" << std::hex << active_output_node_id_;
463 return;
465 DCHECK(!device->is_input);
466 output_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
467 output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device);
469 SetOutputMuteInternal(output_mute_on_);
470 SetOutputNodeVolume(active_output_node_id_, output_volume_);
473 void CrasAudioHandler::InitializeAudioState() {
474 ApplyAudioPolicy();
475 GetNodes();
478 void CrasAudioHandler::ApplyAudioPolicy() {
479 output_mute_locked_ = false;
480 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) {
481 // Mute the device, but do not update the preference.
482 SetOutputMuteInternal(true);
483 output_mute_locked_ = true;
484 } else {
485 // Restore the mute state.
486 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
487 if (device)
488 SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device));
491 input_mute_locked_ = false;
492 if (audio_pref_handler_->GetAudioCaptureAllowedValue()) {
493 VLOG(1) << "Audio input allowed by policy, sets input id="
494 << "0x" << std::hex << active_input_node_id_ << " mute=false";
495 SetInputMuteInternal(false);
496 } else {
497 VLOG(0) << "Audio input NOT allowed by policy, sets input id="
498 << "0x" << std::hex << active_input_node_id_ << " mute=true";
499 SetInputMuteInternal(true);
500 input_mute_locked_ = true;
504 void CrasAudioHandler::SetOutputNodeVolume(uint64 node_id, int volume) {
505 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
506 SetOutputNodeVolume(node_id, volume);
509 bool CrasAudioHandler::SetOutputMuteInternal(bool mute_on) {
510 if (output_mute_locked_)
511 return false;
513 output_mute_on_ = mute_on;
514 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
515 SetOutputUserMute(mute_on);
516 return true;
519 void CrasAudioHandler::SetInputNodeGain(uint64 node_id, int gain) {
520 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
521 SetInputNodeGain(node_id, gain);
524 bool CrasAudioHandler::SetInputMuteInternal(bool mute_on) {
525 if (input_mute_locked_)
526 return false;
528 VLOG(1) << "SetInputMuteInternal sets active input device id="
529 << "0x" << std::hex << active_input_node_id_ << " mute=" << mute_on;
530 input_mute_on_ = mute_on;
531 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
532 SetInputMute(mute_on);
533 return true;
536 void CrasAudioHandler::GetNodes() {
537 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes(
538 base::Bind(&CrasAudioHandler::HandleGetNodes,
539 weak_ptr_factory_.GetWeakPtr()),
540 base::Bind(&CrasAudioHandler::HandleGetNodesError,
541 weak_ptr_factory_.GetWeakPtr()));
544 bool CrasAudioHandler::ChangeActiveDevice(const AudioDevice& new_active_device,
545 uint64* current_active_node_id) {
546 // If the device we want to switch to is already the current active device,
547 // do nothing.
548 if (new_active_device.active &&
549 new_active_device.id == *current_active_node_id) {
550 return false;
553 // Reset all other input or output devices' active status. The active audio
554 // device from the previous user session can be remembered by cras, but not
555 // in chrome. see crbug.com/273271.
556 for (AudioDeviceMap::iterator it = audio_devices_.begin();
557 it != audio_devices_.end(); ++it) {
558 if (it->second.is_input == new_active_device.is_input &&
559 it->second.id != new_active_device.id)
560 it->second.active = false;
563 // Set the current active input/output device to the new_active_device.
564 *current_active_node_id = new_active_device.id;
565 audio_devices_[*current_active_node_id].active = true;
566 return true;
569 bool CrasAudioHandler::NonActiveDeviceUnplugged(
570 size_t old_devices_size,
571 size_t new_devices_size,
572 uint64 current_active_node) {
573 return (new_devices_size < old_devices_size &&
574 GetDeviceFromId(current_active_node));
577 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device) {
578 if (device.is_input) {
579 if (!ChangeActiveDevice(device, &active_input_node_id_))
580 return;
581 SetupAudioInputState();
582 SetActiveInputNode(active_input_node_id_);
583 } else {
584 if (!ChangeActiveDevice(device, &active_output_node_id_))
585 return;
586 SetupAudioOutputState();
587 SetActiveOutputNode(active_output_node_id_);
591 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes,
592 bool is_input) {
593 size_t num_old_devices = 0;
594 size_t num_new_devices = 0;
595 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
596 it != audio_devices_.end(); ++it) {
597 if (is_input == it->second.is_input)
598 ++num_old_devices;
601 for (AudioNodeList::const_iterator it = new_nodes.begin();
602 it != new_nodes.end(); ++it) {
603 if (is_input == it->is_input) {
604 ++num_new_devices;
605 // Look to see if the new device not in the old device list.
606 AudioDevice device(*it);
607 if (FoundNewDevice(device))
608 return true;
611 return num_old_devices != num_new_devices;
614 bool CrasAudioHandler::FoundNewDevice(const AudioDevice& device) {
615 const AudioDevice* device_found = GetDeviceFromId(device.id);
616 if (!device_found)
617 return true;
619 if (!IsSameAudioDevice(device, *device_found)) {
620 LOG(WARNING) << "Different Audio devices with same id:"
621 << " new device: " << device.ToString()
622 << " old device: " << device_found->ToString();
623 return true;
625 return false;
628 // Sanitize the audio node data. When a device is plugged in or unplugged, there
629 // should be only one NodesChanged signal from cras. However, we've observed
630 // the case that multiple NodesChanged signals being sent from cras. After the
631 // first NodesChanged being processed, chrome sets the active node properly.
632 // However, the NodesChanged received after the first one, can return stale
633 // nodes data in GetNodes call, the staled nodes data does not reflect the
634 // latest active node state. Since active audio node should only be set by
635 // chrome, the inconsistent data from cras could be the result of stale data
636 // described above and sanitized.
637 AudioDevice CrasAudioHandler::GetSanitizedAudioDevice(const AudioNode& node) {
638 AudioDevice device(node);
639 if (device.is_input) {
640 if (device.active && device.id != active_input_node_id_) {
641 LOG(WARNING) << "Stale audio device data, should not be active: "
642 << " device = " << device.ToString()
643 << " current active input node id = 0x" << std::hex
644 << active_input_node_id_;
645 device.active = false;
646 } else if (device.id == active_input_node_id_ && !device.active) {
647 LOG(WARNING) << "Stale audio device data, should be active:"
648 << " device = " << device.ToString()
649 << " current active input node id = 0x" << std::hex
650 << active_input_node_id_;
651 device.active = true;
653 } else {
654 if (device.active && device.id != active_output_node_id_) {
655 LOG(WARNING) << "Stale audio device data, should not be active: "
656 << " device = " << device.ToString()
657 << " current active output node id = 0x" << std::hex
658 << active_output_node_id_;
659 device.active = false;
660 } else if (device.id == active_output_node_id_ && !device.active) {
661 LOG(WARNING) << "Stale audio device data, should be active:"
662 << " device = " << device.ToString()
663 << " current active output node id = 0x" << std::hex
664 << active_output_node_id_;
665 device.active = true;
668 return device;
671 void CrasAudioHandler::UpdateDevicesAndSwitchActive(
672 const AudioNodeList& nodes) {
673 size_t old_audio_devices_size = audio_devices_.size();
674 bool output_devices_changed = HasDeviceChange(nodes, false);
675 bool input_devices_changed = HasDeviceChange(nodes, true);
676 audio_devices_.clear();
677 has_alternative_input_ = false;
678 has_alternative_output_ = false;
680 while (!input_devices_pq_.empty())
681 input_devices_pq_.pop();
682 while (!output_devices_pq_.empty())
683 output_devices_pq_.pop();
685 for (size_t i = 0; i < nodes.size(); ++i) {
686 AudioDevice device = GetSanitizedAudioDevice(nodes[i]);
687 audio_devices_[device.id] = device;
689 if (!has_alternative_input_ &&
690 device.is_input &&
691 device.type != AUDIO_TYPE_INTERNAL_MIC &&
692 device.type != AUDIO_TYPE_KEYBOARD_MIC) {
693 has_alternative_input_ = true;
694 } else if (!has_alternative_output_ &&
695 !device.is_input &&
696 device.type != AUDIO_TYPE_INTERNAL_SPEAKER) {
697 has_alternative_output_ = true;
700 if (device.is_input)
701 input_devices_pq_.push(device);
702 else
703 output_devices_pq_.push(device);
706 // If audio nodes change is caused by unplugging some non-active audio
707 // devices, the previously set active audio device will stay active.
708 // Otherwise, switch to a new active audio device according to their priority.
709 if (input_devices_changed &&
710 !NonActiveDeviceUnplugged(old_audio_devices_size,
711 audio_devices_.size(),
712 active_input_node_id_) &&
713 !input_devices_pq_.empty())
714 SwitchToDevice(input_devices_pq_.top());
715 if (output_devices_changed &&
716 !NonActiveDeviceUnplugged(old_audio_devices_size,
717 audio_devices_.size(),
718 active_output_node_id_) &&
719 !output_devices_pq_.empty()) {
720 SwitchToDevice(output_devices_pq_.top());
724 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list,
725 bool success) {
726 if (!success) {
727 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data";
728 return;
731 UpdateDevicesAndSwitchActive(node_list);
732 FOR_EACH_OBSERVER(AudioObserver, observers_, OnAudioNodesChanged());
735 void CrasAudioHandler::HandleGetNodesError(const std::string& error_name,
736 const std::string& error_msg) {
737 LOG_IF(ERROR, log_errors_) << "Failed to call GetNodes: "
738 << error_name << ": " << error_msg;
740 } // namespace chromeos