Enable disabling WebCore::GraphicsContext in telemetry.
[chromium-blink-merge.git] / chromeos / audio / cras_audio_handler.cc
blobaeda0ebb37f0fc8f6d1fdf4f4dd728072af50c1e
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::IsOutputMuted() {
108 return output_mute_on_;
111 bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id) {
112 const AudioDevice* device = GetDeviceFromId(device_id);
113 if (!device)
114 return false;
115 DCHECK(!device->is_input);
116 return audio_pref_handler_->GetMuteValue(*device);
119 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLvel() {
120 return output_volume_ <= kMuteThresholdPercent;
123 bool CrasAudioHandler::IsInputMuted() {
124 return input_mute_on_;
127 bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) {
128 const AudioDevice* device = GetDeviceFromId(device_id);
129 if (!device)
130 return false;
131 DCHECK(device->is_input);
132 // We don't record input mute state for each device in the prefs,
133 // for any non-active input device, we assume mute is off.
134 if (device->id == active_input_node_id_)
135 return input_mute_on_;
136 return false;
139 int CrasAudioHandler::GetOutputDefaultVolumeMuteThreshold() {
140 return kMuteThresholdPercent;
143 int CrasAudioHandler::GetOutputVolumePercent() {
144 return output_volume_;
147 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64 device_id) {
148 if (device_id == active_output_node_id_) {
149 return output_volume_;
150 } else {
151 const AudioDevice* device = GetDeviceFromId(device_id);
152 return static_cast<int>(audio_pref_handler_->GetOutputVolumeValue(device));
156 int CrasAudioHandler::GetInputGainPercent() {
157 return input_gain_;
160 int CrasAudioHandler::GetInputGainPercentForDevice(uint64 device_id) {
161 if (device_id == active_input_node_id_) {
162 return input_gain_;
163 } else {
164 const AudioDevice* device = GetDeviceFromId(device_id);
165 return static_cast<int>(audio_pref_handler_->GetInputGainValue(device));
169 uint64 CrasAudioHandler::GetActiveOutputNode() const {
170 return active_output_node_id_;
173 uint64 CrasAudioHandler::GetActiveInputNode() const {
174 return active_input_node_id_;
177 void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const {
178 device_list->clear();
179 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
180 it != audio_devices_.end(); ++it)
181 device_list->push_back(it->second);
184 bool CrasAudioHandler::GetActiveOutputDevice(AudioDevice* device) const {
185 const AudioDevice* active_device = GetDeviceFromId(active_output_node_id_);
186 if (!active_device || !device)
187 return false;
188 *device = *active_device;
189 return true;
192 bool CrasAudioHandler::has_alternative_input() const {
193 return has_alternative_input_;
196 bool CrasAudioHandler::has_alternative_output() const {
197 return has_alternative_output_;
200 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) {
201 volume_percent = min(max(volume_percent, 0), 100);
202 if (volume_percent <= kMuteThresholdPercent)
203 volume_percent = 0;
204 output_volume_ = volume_percent;
206 if (const AudioDevice* device = GetDeviceFromId(active_output_node_id_))
207 audio_pref_handler_->SetVolumeGainValue(*device, output_volume_);
209 SetOutputNodeVolume(active_output_node_id_, output_volume_);
210 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged());
213 // TODO: Rename the 'Percent' to something more meaningful.
214 void CrasAudioHandler::SetInputGainPercent(int gain_percent) {
215 // NOTE: We do not sanitize input gain values since the range is completely
216 // dependent on the device.
217 input_gain_ = gain_percent;
219 if (const AudioDevice* device = GetDeviceFromId(active_input_node_id_))
220 audio_pref_handler_->SetVolumeGainValue(*device, input_gain_);
222 SetInputNodeGain(active_input_node_id_, input_gain_);
223 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputGainChanged());
226 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) {
227 SetOutputVolumePercent(output_volume_ + adjust_by_percent);
230 void CrasAudioHandler::SetOutputMute(bool mute_on) {
231 if (!SetOutputMuteInternal(mute_on))
232 return;
234 if (const AudioDevice* device = GetDeviceFromId(active_output_node_id_)) {
235 DCHECK(!device->is_input);
236 audio_pref_handler_->SetMuteValue(*device, output_mute_on_);
239 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged());
242 void CrasAudioHandler::AdjustOutputVolumeToAudibleLevel() {
243 if (output_volume_ <= kMuteThresholdPercent) {
244 // Avoid the situation when sound has been unmuted, but the volume
245 // is set to a very low value, so user still can't hear any sound.
246 SetOutputVolumePercent(kDefaultUnmuteVolumePercent);
250 void CrasAudioHandler::SetInputMute(bool mute_on) {
251 if (!SetInputMuteInternal(mute_on))
252 return;
254 // Audio input mute state is not saved in prefs, see crbug.com/365050.
255 LOG(WARNING) << "SetInputMute set active input id="
256 << "0x" << std::hex << active_input_node_id_
257 << " mute=" << mute_on;
259 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputMuteChanged());
262 void CrasAudioHandler::SetActiveOutputNode(uint64 node_id) {
263 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
264 SetActiveOutputNode(node_id);
265 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged());
268 void CrasAudioHandler::SetActiveInputNode(uint64 node_id) {
269 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
270 SetActiveInputNode(node_id);
271 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged());
274 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64 device_id,
275 int value) {
276 if (device_id == active_output_node_id_) {
277 SetOutputVolumePercent(value);
278 return;
279 } else if (device_id == active_input_node_id_) {
280 SetInputGainPercent(value);
281 return;
284 if (const AudioDevice* device = GetDeviceFromId(device_id)) {
285 if (!device->is_input) {
286 value = min(max(value, 0), 100);
287 if (value <= kMuteThresholdPercent)
288 value = 0;
290 audio_pref_handler_->SetVolumeGainValue(*device, value);
294 void CrasAudioHandler::SetMuteForDevice(uint64 device_id, bool mute_on) {
295 if (device_id == active_output_node_id_) {
296 SetOutputMute(mute_on);
297 return;
298 } else if (device_id == active_input_node_id_) {
299 LOG(WARNING) << "SetMuteForDevice sets active input device id="
300 << "0x" << std::hex << device_id << " mute=" << mute_on;
301 SetInputMute(mute_on);
302 return;
305 const AudioDevice* device = GetDeviceFromId(device_id);
306 // Input device's mute state is not recorded in the pref. crbug.com/365050.
307 if (device && !device->is_input)
308 audio_pref_handler_->SetMuteValue(*device, mute_on);
311 void CrasAudioHandler::LogErrors() {
312 log_errors_ = true;
315 CrasAudioHandler::CrasAudioHandler(
316 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler)
317 : audio_pref_handler_(audio_pref_handler),
318 weak_ptr_factory_(this),
319 output_mute_on_(false),
320 input_mute_on_(false),
321 output_volume_(0),
322 input_gain_(0),
323 active_output_node_id_(0),
324 active_input_node_id_(0),
325 has_alternative_input_(false),
326 has_alternative_output_(false),
327 output_mute_locked_(false),
328 input_mute_locked_(false),
329 log_errors_(false) {
330 if (!audio_pref_handler.get())
331 return;
332 // If the DBusThreadManager or the CrasAudioClient aren't available, there
333 // isn't much we can do. This should only happen when running tests.
334 if (!chromeos::DBusThreadManager::IsInitialized() ||
335 !chromeos::DBusThreadManager::Get() ||
336 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
337 return;
338 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this);
339 audio_pref_handler_->AddAudioPrefObserver(this);
340 if (chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) {
341 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
342 AddObserver(this);
344 InitializeAudioState();
347 CrasAudioHandler::~CrasAudioHandler() {
348 if (!chromeos::DBusThreadManager::IsInitialized() ||
349 !chromeos::DBusThreadManager::Get() ||
350 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
351 return;
352 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
353 RemoveObserver(this);
354 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
355 RemoveObserver(this);
356 if (audio_pref_handler_.get())
357 audio_pref_handler_->RemoveAudioPrefObserver(this);
358 audio_pref_handler_ = NULL;
361 void CrasAudioHandler::AudioClientRestarted() {
362 // Make sure the logging is enabled in case cras server
363 // restarts after crashing.
364 LogErrors();
365 InitializeAudioState();
368 void CrasAudioHandler::NodesChanged() {
369 // Refresh audio nodes data.
370 GetNodes();
373 void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id) {
374 if (active_output_node_id_ == node_id)
375 return;
377 // Active audio output device should always be changed by chrome.
378 // During system boot, cras may change active input to unknown device 0x1,
379 // we don't need to log it, since it is not an valid device.
380 if (GetDeviceFromId(node_id)) {
381 LOG_IF(WARNING, log_errors_)
382 << "Active output node changed unexpectedly by system node_id="
383 << "0x" << std::hex << node_id;
387 void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id) {
388 if (active_input_node_id_ == node_id)
389 return;
391 // Active audio input device should always be changed by chrome.
392 // During system boot, cras may change active input to unknown device 0x2,
393 // we don't need to log it, since it is not an valid device.
394 if (GetDeviceFromId(node_id)) {
395 LOG_IF(WARNING, log_errors_)
396 << "Active input node changed unexpectedly by system node_id="
397 << "0x" << std::hex << node_id;
401 void CrasAudioHandler::OnAudioPolicyPrefChanged() {
402 ApplyAudioPolicy();
405 void CrasAudioHandler::EmitLoginPromptVisibleCalled() {
406 // Enable logging after cras server is started, which will be after
407 // EmitLoginPromptVisible.
408 LogErrors();
411 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64 device_id) const {
412 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id);
413 if (it == audio_devices_.end())
414 return NULL;
416 return &(it->second);
419 void CrasAudioHandler::SetupAudioInputState() {
420 // Set the initial audio state to the ones read from audio prefs.
421 const AudioDevice* device = GetDeviceFromId(active_input_node_id_);
422 if (!device) {
423 LOG_IF(ERROR, log_errors_)
424 << "Can't set up audio state for unknown input device id ="
425 << "0x" << std::hex << active_input_node_id_;
426 return;
428 input_gain_ = audio_pref_handler_->GetInputGainValue(device);
429 LOG(WARNING) << "SetupAudioInputState for active device id="
430 << "0x" << std::hex << device->id << " mute=" << input_mute_on_;
431 SetInputMuteInternal(input_mute_on_);
432 // TODO(rkc,jennyz): Set input gain once we decide on how to store
433 // the gain values since the range and step are both device specific.
436 void CrasAudioHandler::SetupAudioOutputState() {
437 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
438 if (!device) {
439 LOG_IF(ERROR, log_errors_)
440 << "Can't set up audio state for unknown output device id ="
441 << "0x" << std::hex << active_output_node_id_;
442 return;
444 DCHECK(!device->is_input);
445 output_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
446 output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device);
448 SetOutputMuteInternal(output_mute_on_);
449 SetOutputNodeVolume(active_output_node_id_, output_volume_);
452 void CrasAudioHandler::InitializeAudioState() {
453 ApplyAudioPolicy();
454 GetNodes();
457 void CrasAudioHandler::ApplyAudioPolicy() {
458 output_mute_locked_ = false;
459 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) {
460 // Mute the device, but do not update the preference.
461 SetOutputMuteInternal(true);
462 output_mute_locked_ = true;
463 } else {
464 // Restore the mute state.
465 const AudioDevice* device = GetDeviceFromId(active_output_node_id_);
466 if (device)
467 SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device));
470 input_mute_locked_ = false;
471 if (audio_pref_handler_->GetAudioCaptureAllowedValue()) {
472 LOG(WARNING) << "Audio input allowed by policy, sets input id="
473 << "0x" << std::hex << active_input_node_id_
474 << " mute=false";
475 SetInputMuteInternal(false);
476 } else {
477 LOG(WARNING) << "Audio input NOT allowed by policy, sets input id="
478 << "0x" << std::hex << active_input_node_id_ << " mute=true";
479 SetInputMuteInternal(true);
480 input_mute_locked_ = true;
484 void CrasAudioHandler::SetOutputNodeVolume(uint64 node_id, int volume) {
485 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
486 SetOutputNodeVolume(node_id, volume);
489 bool CrasAudioHandler::SetOutputMuteInternal(bool mute_on) {
490 if (output_mute_locked_)
491 return false;
493 output_mute_on_ = mute_on;
494 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
495 SetOutputUserMute(mute_on);
496 return true;
499 void CrasAudioHandler::SetInputNodeGain(uint64 node_id, int gain) {
500 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
501 SetInputNodeGain(node_id, gain);
504 bool CrasAudioHandler::SetInputMuteInternal(bool mute_on) {
505 if (input_mute_locked_)
506 return false;
508 LOG(WARNING) << "SetInputMuteInternal sets active input device id="
509 << "0x" << std::hex << active_input_node_id_
510 << " mute=" << mute_on;
511 input_mute_on_ = mute_on;
512 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
513 SetInputMute(mute_on);
514 return true;
517 void CrasAudioHandler::GetNodes() {
518 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes(
519 base::Bind(&CrasAudioHandler::HandleGetNodes,
520 weak_ptr_factory_.GetWeakPtr()),
521 base::Bind(&CrasAudioHandler::HandleGetNodesError,
522 weak_ptr_factory_.GetWeakPtr()));
525 bool CrasAudioHandler::ChangeActiveDevice(const AudioDevice& new_active_device,
526 uint64* current_active_node_id) {
527 // If the device we want to switch to is already the current active device,
528 // do nothing.
529 if (new_active_device.active &&
530 new_active_device.id == *current_active_node_id) {
531 return false;
534 // Reset all other input or output devices' active status. The active audio
535 // device from the previous user session can be remembered by cras, but not
536 // in chrome. see crbug.com/273271.
537 for (AudioDeviceMap::iterator it = audio_devices_.begin();
538 it != audio_devices_.end(); ++it) {
539 if (it->second.is_input == new_active_device.is_input &&
540 it->second.id != new_active_device.id)
541 it->second.active = false;
544 // Set the current active input/output device to the new_active_device.
545 *current_active_node_id = new_active_device.id;
546 audio_devices_[*current_active_node_id].active = true;
547 return true;
550 bool CrasAudioHandler::NonActiveDeviceUnplugged(
551 size_t old_devices_size,
552 size_t new_devices_size,
553 uint64 current_active_node) {
554 return (new_devices_size < old_devices_size &&
555 GetDeviceFromId(current_active_node));
558 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device) {
559 if (device.is_input) {
560 if (!ChangeActiveDevice(device, &active_input_node_id_))
561 return;
562 SetupAudioInputState();
563 SetActiveInputNode(active_input_node_id_);
564 } else {
565 if (!ChangeActiveDevice(device, &active_output_node_id_))
566 return;
567 SetupAudioOutputState();
568 SetActiveOutputNode(active_output_node_id_);
572 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes,
573 bool is_input) {
574 size_t num_old_devices = 0;
575 size_t num_new_devices = 0;
576 for (AudioDeviceMap::const_iterator it = audio_devices_.begin();
577 it != audio_devices_.end(); ++it) {
578 if (is_input == it->second.is_input)
579 ++num_old_devices;
582 for (AudioNodeList::const_iterator it = new_nodes.begin();
583 it != new_nodes.end(); ++it) {
584 if (is_input == it->is_input) {
585 ++num_new_devices;
586 // Look to see if the new device not in the old device list.
587 AudioDevice device(*it);
588 if (FoundNewDevice(device))
589 return true;
592 return num_old_devices != num_new_devices;
595 bool CrasAudioHandler::FoundNewDevice(const AudioDevice& device) {
596 const AudioDevice* device_found = GetDeviceFromId(device.id);
597 if (!device_found)
598 return true;
600 if (!IsSameAudioDevice(device, *device_found)) {
601 LOG(WARNING) << "Different Audio devices with same id:"
602 << " new device: " << device.ToString()
603 << " old device: " << device_found->ToString();
604 return true;
606 return false;
609 // Sanitize the audio node data. When a device is plugged in or unplugged, there
610 // should be only one NodesChanged signal from cras. However, we've observed
611 // the case that multiple NodesChanged signals being sent from cras. After the
612 // first NodesChanged being processed, chrome sets the active node properly.
613 // However, the NodesChanged received after the first one, can return stale
614 // nodes data in GetNodes call, the staled nodes data does not reflect the
615 // latest active node state. Since active audio node should only be set by
616 // chrome, the inconsistent data from cras could be the result of stale data
617 // described above and sanitized.
618 AudioDevice CrasAudioHandler::GetSanitizedAudioDevice(const AudioNode& node) {
619 AudioDevice device(node);
620 if (device.is_input) {
621 if (device.active && device.id != active_input_node_id_) {
622 LOG(WARNING) << "Stale audio device data, should not be active: "
623 << " device = " << device.ToString()
624 << " current active input node id = 0x" << std::hex
625 << active_input_node_id_;
626 device.active = false;
627 } else if (device.id == active_input_node_id_ && !device.active) {
628 LOG(WARNING) << "Stale audio device data, should be active:"
629 << " device = " << device.ToString()
630 << " current active input node id = 0x" << std::hex
631 << active_input_node_id_;
632 device.active = true;
634 } else {
635 if (device.active && device.id != active_output_node_id_) {
636 LOG(WARNING) << "Stale audio device data, should not be active: "
637 << " device = " << device.ToString()
638 << " current active output node id = 0x" << std::hex
639 << active_output_node_id_;
640 device.active = false;
641 } else if (device.id == active_output_node_id_ && !device.active) {
642 LOG(WARNING) << "Stale audio device data, should be active:"
643 << " device = " << device.ToString()
644 << " current active output node id = 0x" << std::hex
645 << active_output_node_id_;
646 device.active = true;
649 return device;
652 void CrasAudioHandler::UpdateDevicesAndSwitchActive(
653 const AudioNodeList& nodes) {
654 size_t old_audio_devices_size = audio_devices_.size();
655 bool output_devices_changed = HasDeviceChange(nodes, false);
656 bool input_devices_changed = HasDeviceChange(nodes, true);
657 audio_devices_.clear();
658 has_alternative_input_ = false;
659 has_alternative_output_ = false;
661 while (!input_devices_pq_.empty())
662 input_devices_pq_.pop();
663 while (!output_devices_pq_.empty())
664 output_devices_pq_.pop();
666 for (size_t i = 0; i < nodes.size(); ++i) {
667 AudioDevice device = GetSanitizedAudioDevice(nodes[i]);
668 audio_devices_[device.id] = device;
670 if (!has_alternative_input_ &&
671 device.is_input &&
672 device.type != AUDIO_TYPE_INTERNAL_MIC) {
673 has_alternative_input_ = true;
674 } else if (!has_alternative_output_ &&
675 !device.is_input &&
676 device.type != AUDIO_TYPE_INTERNAL_SPEAKER) {
677 has_alternative_output_ = true;
680 if (device.is_input)
681 input_devices_pq_.push(device);
682 else
683 output_devices_pq_.push(device);
686 // If audio nodes change is caused by unplugging some non-active audio
687 // devices, the previously set active audio device will stay active.
688 // Otherwise, switch to a new active audio device according to their priority.
689 if (input_devices_changed &&
690 !NonActiveDeviceUnplugged(old_audio_devices_size,
691 audio_devices_.size(),
692 active_input_node_id_) &&
693 !input_devices_pq_.empty())
694 SwitchToDevice(input_devices_pq_.top());
695 if (output_devices_changed &&
696 !NonActiveDeviceUnplugged(old_audio_devices_size,
697 audio_devices_.size(),
698 active_output_node_id_) &&
699 !output_devices_pq_.empty()) {
700 SwitchToDevice(output_devices_pq_.top());
704 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list,
705 bool success) {
706 if (!success) {
707 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data";
708 return;
711 UpdateDevicesAndSwitchActive(node_list);
712 FOR_EACH_OBSERVER(AudioObserver, observers_, OnAudioNodesChanged());
715 void CrasAudioHandler::HandleGetNodesError(const std::string& error_name,
716 const std::string& error_msg) {
717 LOG_IF(ERROR, log_errors_) << "Failed to call GetNodes: "
718 << error_name << ": " << error_msg;
720 } // namespace chromeos