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 <algorithm> 8 #include <cmath> 9 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" 16 17 using std::max; 18 using std::min; 19 20 namespace chromeos { 21 22 namespace { 23 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; 27 28 // Volume value which should be considered as muted in range [0, 100]. 29 const int kMuteThresholdPercent = 1; 30 31 static CrasAudioHandler* g_cras_audio_handler = NULL; 32 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; 36 } 37 38 } // namespace 39 40 CrasAudioHandler::AudioObserver::AudioObserver() { 41 } 42 43 CrasAudioHandler::AudioObserver::~AudioObserver() { 44 } 45 46 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() { 47 } 48 49 void CrasAudioHandler::AudioObserver::OnInputGainChanged() { 50 } 51 52 void CrasAudioHandler::AudioObserver::OnOutputMuteChanged() { 53 } 54 55 void CrasAudioHandler::AudioObserver::OnInputMuteChanged() { 56 } 57 58 void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() { 59 } 60 61 void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() { 62 } 63 64 void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() { 65 } 66 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); 72 } 73 74 // static 75 void CrasAudioHandler::InitializeForTesting() { 76 CHECK(!g_cras_audio_handler); 77 CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub()); 78 } 79 80 // static 81 void CrasAudioHandler::Shutdown() { 82 CHECK(g_cras_audio_handler); 83 delete g_cras_audio_handler; 84 g_cras_audio_handler = NULL; 85 } 86 87 // static 88 bool CrasAudioHandler::IsInitialized() { 89 return g_cras_audio_handler != NULL; 90 } 91 92 // static 93 CrasAudioHandler* CrasAudioHandler::Get() { 94 CHECK(g_cras_audio_handler) 95 << "CrasAudioHandler::Get() called before Initialize()."; 96 return g_cras_audio_handler; 97 } 98 99 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) { 100 observers_.AddObserver(observer); 101 } 102 103 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) { 104 observers_.RemoveObserver(observer); 105 } 106 107 bool CrasAudioHandler::IsOutputMuted() { 108 return output_mute_on_; 109 } 110 111 bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id) { 112 const AudioDevice* device = GetDeviceFromId(device_id); 113 if (!device) 114 return false; 115 return audio_pref_handler_->GetMuteValue(*device); 116 } 117 118 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLvel() { 119 return output_volume_ <= kMuteThresholdPercent; 120 } 121 122 bool CrasAudioHandler::IsInputMuted() { 123 return input_mute_on_; 124 } 125 126 bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) { 127 const AudioDevice* device = GetDeviceFromId(device_id); 128 if (!device) 129 return false; 130 return audio_pref_handler_->GetMuteValue(*device); 131 } 132 133 int CrasAudioHandler::GetOutputVolumePercent() { 134 return output_volume_; 135 } 136 137 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64 device_id) { 138 if (device_id == active_output_node_id_) { 139 return output_volume_; 140 } else { 141 const AudioDevice* device = GetDeviceFromId(device_id); 142 return static_cast<int>(audio_pref_handler_->GetOutputVolumeValue(device)); 143 } 144 } 145 146 int CrasAudioHandler::GetInputGainPercent() { 147 return input_gain_; 148 } 149 150 int CrasAudioHandler::GetInputGainPercentForDevice(uint64 device_id) { 151 if (device_id == active_input_node_id_) { 152 return input_gain_; 153 } else { 154 const AudioDevice* device = GetDeviceFromId(device_id); 155 return static_cast<int>(audio_pref_handler_->GetInputGainValue(device)); 156 } 157 } 158 159 uint64 CrasAudioHandler::GetActiveOutputNode() const { 160 return active_output_node_id_; 161 } 162 163 uint64 CrasAudioHandler::GetActiveInputNode() const { 164 return active_input_node_id_; 165 } 166 167 void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const { 168 device_list->clear(); 169 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 170 it != audio_devices_.end(); ++it) 171 device_list->push_back(it->second); 172 } 173 174 bool CrasAudioHandler::GetActiveOutputDevice(AudioDevice* device) const { 175 const AudioDevice* active_device = GetDeviceFromId(active_output_node_id_); 176 if (!active_device || !device) 177 return false; 178 *device = *active_device; 179 return true; 180 } 181 182 bool CrasAudioHandler::has_alternative_input() const { 183 return has_alternative_input_; 184 } 185 186 bool CrasAudioHandler::has_alternative_output() const { 187 return has_alternative_output_; 188 } 189 190 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) { 191 volume_percent = min(max(volume_percent, 0), 100); 192 if (volume_percent <= kMuteThresholdPercent) 193 volume_percent = 0; 194 output_volume_ = volume_percent; 195 196 if (const AudioDevice* device = GetDeviceFromId(active_output_node_id_)) 197 audio_pref_handler_->SetVolumeGainValue(*device, output_volume_); 198 199 SetOutputNodeVolume(active_output_node_id_, output_volume_); 200 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged()); 201 } 202 203 // TODO: Rename the 'Percent' to something more meaningful. 204 void CrasAudioHandler::SetInputGainPercent(int gain_percent) { 205 // NOTE: We do not sanitize input gain values since the range is completely 206 // dependent on the device. 207 input_gain_ = gain_percent; 208 209 if (const AudioDevice* device = GetDeviceFromId(active_input_node_id_)) 210 audio_pref_handler_->SetVolumeGainValue(*device, input_gain_); 211 212 SetInputNodeGain(active_input_node_id_, input_gain_); 213 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputGainChanged()); 214 } 215 216 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) { 217 SetOutputVolumePercent(output_volume_ + adjust_by_percent); 218 } 219 220 void CrasAudioHandler::SetOutputMute(bool mute_on) { 221 if (!SetOutputMuteInternal(mute_on)) 222 return; 223 224 if (const AudioDevice* device = GetDeviceFromId(active_output_node_id_)) 225 audio_pref_handler_->SetMuteValue(*device, output_mute_on_); 226 227 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged()); 228 } 229 230 void CrasAudioHandler::AdjustOutputVolumeToAudibleLevel() { 231 if (output_volume_ <= kMuteThresholdPercent) { 232 // Avoid the situation when sound has been unmuted, but the volume 233 // is set to a very low value, so user still can't hear any sound. 234 SetOutputVolumePercent(kDefaultUnmuteVolumePercent); 235 } 236 } 237 238 void CrasAudioHandler::SetInputMute(bool mute_on) { 239 if (!SetInputMuteInternal(mute_on)) 240 return; 241 242 AudioDevice device; 243 if (const AudioDevice* device = GetDeviceFromId(active_input_node_id_)) 244 audio_pref_handler_->SetMuteValue(*device, input_mute_on_); 245 246 247 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputMuteChanged()); 248 } 249 250 void CrasAudioHandler::SetActiveOutputNode(uint64 node_id) { 251 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 252 SetActiveOutputNode(node_id); 253 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); 254 } 255 256 void CrasAudioHandler::SetActiveInputNode(uint64 node_id) { 257 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 258 SetActiveInputNode(node_id); 259 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); 260 } 261 262 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64 device_id, 263 int value) { 264 if (device_id == active_output_node_id_) { 265 SetOutputVolumePercent(value); 266 return; 267 } else if (device_id == active_input_node_id_) { 268 SetInputGainPercent(value); 269 return; 270 } 271 272 if (const AudioDevice* device = GetDeviceFromId(device_id)) { 273 if (!device->is_input) { 274 value = min(max(value, 0), 100); 275 if (value <= kMuteThresholdPercent) 276 value = 0; 277 } 278 audio_pref_handler_->SetVolumeGainValue(*device, value); 279 } 280 } 281 282 void CrasAudioHandler::SetMuteForDevice(uint64 device_id, bool mute_on) { 283 if (device_id == active_output_node_id_) { 284 SetOutputMute(mute_on); 285 return; 286 } else if (device_id == active_input_node_id_) { 287 SetInputMute(mute_on); 288 return; 289 } 290 291 AudioDevice device; 292 if (const AudioDevice* device = GetDeviceFromId(device_id)) 293 audio_pref_handler_->SetMuteValue(*device, mute_on); 294 } 295 296 void CrasAudioHandler::LogErrors() { 297 log_errors_ = true; 298 } 299 300 CrasAudioHandler::CrasAudioHandler( 301 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler) 302 : audio_pref_handler_(audio_pref_handler), 303 weak_ptr_factory_(this), 304 output_mute_on_(false), 305 input_mute_on_(false), 306 output_volume_(0), 307 input_gain_(0), 308 active_output_node_id_(0), 309 active_input_node_id_(0), 310 has_alternative_input_(false), 311 has_alternative_output_(false), 312 output_mute_locked_(false), 313 input_mute_locked_(false), 314 log_errors_(false) { 315 if (!audio_pref_handler.get()) 316 return; 317 // If the DBusThreadManager or the CrasAudioClient aren't available, there 318 // isn't much we can do. This should only happen when running tests. 319 if (!chromeos::DBusThreadManager::IsInitialized() || 320 !chromeos::DBusThreadManager::Get() || 321 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient()) 322 return; 323 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this); 324 audio_pref_handler_->AddAudioPrefObserver(this); 325 if (chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) { 326 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> 327 AddObserver(this); 328 } 329 InitializeAudioState(); 330 } 331 332 CrasAudioHandler::~CrasAudioHandler() { 333 if (!chromeos::DBusThreadManager::IsInitialized() || 334 !chromeos::DBusThreadManager::Get() || 335 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient()) 336 return; 337 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 338 RemoveObserver(this); 339 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> 340 RemoveObserver(this); 341 if (audio_pref_handler_.get()) 342 audio_pref_handler_->RemoveAudioPrefObserver(this); 343 audio_pref_handler_ = NULL; 344 } 345 346 void CrasAudioHandler::AudioClientRestarted() { 347 // Make sure the logging is enabled in case cras server 348 // restarts after crashing. 349 LogErrors(); 350 InitializeAudioState(); 351 } 352 353 void CrasAudioHandler::NodesChanged() { 354 // Refresh audio nodes data. 355 GetNodes(); 356 } 357 358 void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id) { 359 if (active_output_node_id_ == node_id) 360 return; 361 362 // Active audio output device should always be changed by chrome. 363 // During system boot, cras may change active input to unknown device 0x1, 364 // we don't need to log it, since it is not an valid device. 365 if (GetDeviceFromId(node_id)) { 366 LOG_IF(WARNING, log_errors_) 367 << "Active output node changed unexpectedly by system node_id=" 368 << "0x" << std::hex << node_id; 369 } 370 } 371 372 void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id) { 373 if (active_input_node_id_ == node_id) 374 return; 375 376 // Active audio input device should always be changed by chrome. 377 // During system boot, cras may change active input to unknown device 0x2, 378 // we don't need to log it, since it is not an valid device. 379 if (GetDeviceFromId(node_id)) { 380 LOG_IF(WARNING, log_errors_) 381 << "Active input node changed unexpectedly by system node_id=" 382 << "0x" << std::hex << node_id; 383 } 384 } 385 386 void CrasAudioHandler::OnAudioPolicyPrefChanged() { 387 ApplyAudioPolicy(); 388 } 389 390 void CrasAudioHandler::EmitLoginPromptVisibleCalled() { 391 // Enable logging after cras server is started, which will be after 392 // EmitLoginPromptVisible. 393 LogErrors(); 394 } 395 396 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64 device_id) const { 397 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id); 398 if (it == audio_devices_.end()) 399 return NULL; 400 401 return &(it->second); 402 } 403 404 void CrasAudioHandler::SetupAudioInputState() { 405 // Set the initial audio state to the ones read from audio prefs. 406 const AudioDevice* device = GetDeviceFromId(active_input_node_id_); 407 if (!device) { 408 LOG_IF(ERROR, log_errors_) 409 << "Can't set up audio state for unknown input device id =" 410 << "0x" << std::hex << active_input_node_id_; 411 return; 412 } 413 input_mute_on_ = audio_pref_handler_->GetMuteValue(*device); 414 input_gain_ = audio_pref_handler_->GetInputGainValue(device); 415 SetInputMuteInternal(input_mute_on_); 416 // TODO(rkc,jennyz): Set input gain once we decide on how to store 417 // the gain values since the range and step are both device specific. 418 } 419 420 void CrasAudioHandler::SetupAudioOutputState() { 421 const AudioDevice* device = GetDeviceFromId(active_output_node_id_); 422 if (!device) { 423 LOG_IF(ERROR, log_errors_) 424 << "Can't set up audio state for unknown output device id =" 425 << "0x" << std::hex << active_output_node_id_; 426 return; 427 } 428 output_mute_on_ = audio_pref_handler_->GetMuteValue(*device); 429 output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device); 430 431 SetOutputMuteInternal(output_mute_on_); 432 SetOutputNodeVolume(active_output_node_id_, output_volume_); 433 } 434 435 void CrasAudioHandler::InitializeAudioState() { 436 ApplyAudioPolicy(); 437 GetNodes(); 438 } 439 440 void CrasAudioHandler::ApplyAudioPolicy() { 441 output_mute_locked_ = false; 442 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) { 443 // Mute the device, but do not update the preference. 444 SetOutputMuteInternal(true); 445 output_mute_locked_ = true; 446 } else { 447 // Restore the mute state. 448 const AudioDevice* device = GetDeviceFromId(active_output_node_id_); 449 if (device) 450 SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device)); 451 } 452 453 input_mute_locked_ = false; 454 if (audio_pref_handler_->GetAudioCaptureAllowedValue()) { 455 // Set input mute if we have discovered active input device. 456 const AudioDevice* device = GetDeviceFromId(active_input_node_id_); 457 if (device) 458 SetInputMuteInternal(false); 459 } else { 460 SetInputMute(true); 461 input_mute_locked_ = true; 462 } 463 } 464 465 void CrasAudioHandler::SetOutputNodeVolume(uint64 node_id, int volume) { 466 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 467 SetOutputNodeVolume(node_id, volume); 468 } 469 470 bool CrasAudioHandler::SetOutputMuteInternal(bool mute_on) { 471 if (output_mute_locked_) 472 return false; 473 474 output_mute_on_ = mute_on; 475 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 476 SetOutputUserMute(mute_on); 477 return true; 478 } 479 480 void CrasAudioHandler::SetInputNodeGain(uint64 node_id, int gain) { 481 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 482 SetInputNodeGain(node_id, gain); 483 } 484 485 bool CrasAudioHandler::SetInputMuteInternal(bool mute_on) { 486 if (input_mute_locked_) 487 return false; 488 489 input_mute_on_ = mute_on; 490 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 491 SetInputMute(mute_on); 492 return true; 493 } 494 495 void CrasAudioHandler::GetNodes() { 496 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes( 497 base::Bind(&CrasAudioHandler::HandleGetNodes, 498 weak_ptr_factory_.GetWeakPtr()), 499 base::Bind(&CrasAudioHandler::HandleGetNodesError, 500 weak_ptr_factory_.GetWeakPtr())); 501 } 502 503 bool CrasAudioHandler::ChangeActiveDevice(const AudioDevice& new_active_device, 504 uint64* current_active_node_id) { 505 // If the device we want to switch to is already the current active device, 506 // do nothing. 507 if (new_active_device.active && 508 new_active_device.id == *current_active_node_id) { 509 return false; 510 } 511 512 // Reset all other input or output devices' active status. The active audio 513 // device from the previous user session can be remembered by cras, but not 514 // in chrome. see crbug.com/273271. 515 for (AudioDeviceMap::iterator it = audio_devices_.begin(); 516 it != audio_devices_.end(); ++it) { 517 if (it->second.is_input == new_active_device.is_input && 518 it->second.id != new_active_device.id) 519 it->second.active = false; 520 } 521 522 // Set the current active input/output device to the new_active_device. 523 *current_active_node_id = new_active_device.id; 524 audio_devices_[*current_active_node_id].active = true; 525 return true; 526 } 527 528 bool CrasAudioHandler::NonActiveDeviceUnplugged( 529 size_t old_devices_size, 530 size_t new_devices_size, 531 uint64 current_active_node) { 532 return (new_devices_size < old_devices_size && 533 GetDeviceFromId(current_active_node)); 534 } 535 536 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device) { 537 if (device.is_input) { 538 if (!ChangeActiveDevice(device, &active_input_node_id_)) 539 return; 540 SetupAudioInputState(); 541 SetActiveInputNode(active_input_node_id_); 542 } else { 543 if (!ChangeActiveDevice(device, &active_output_node_id_)) 544 return; 545 SetupAudioOutputState(); 546 SetActiveOutputNode(active_output_node_id_); 547 } 548 } 549 550 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, 551 bool is_input) { 552 size_t num_old_devices = 0; 553 size_t num_new_devices = 0; 554 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 555 it != audio_devices_.end(); ++it) { 556 if (is_input == it->second.is_input) 557 ++num_old_devices; 558 } 559 560 for (AudioNodeList::const_iterator it = new_nodes.begin(); 561 it != new_nodes.end(); ++it) { 562 if (is_input == it->is_input) { 563 ++num_new_devices; 564 // Look to see if the new device not in the old device list. 565 AudioDevice device(*it); 566 if (FoundNewDevice(device)) 567 return true; 568 } 569 } 570 return num_old_devices != num_new_devices; 571 } 572 573 bool CrasAudioHandler::FoundNewDevice(const AudioDevice& device) { 574 const AudioDevice* device_found = GetDeviceFromId(device.id); 575 if (!device_found) 576 return true; 577 578 if (!IsSameAudioDevice(device, *device_found)) { 579 LOG(WARNING) << "Different Audio devices with same id:" 580 << " new device: " << device.ToString() 581 << " old device: " << device_found->ToString(); 582 return true; 583 } 584 return false; 585 } 586 587 // Sanitize the audio node data. When a device is plugged in or unplugged, there 588 // should be only one NodesChanged signal from cras. However, we've observed 589 // the case that multiple NodesChanged signals being sent from cras. After the 590 // first NodesChanged being processed, chrome sets the active node properly. 591 // However, the NodesChanged received after the first one, can return stale 592 // nodes data in GetNodes call, the staled nodes data does not reflect the 593 // latest active node state. Since active audio node should only be set by 594 // chrome, the inconsistent data from cras could be the result of stale data 595 // described above and sanitized. 596 AudioDevice CrasAudioHandler::GetSanitizedAudioDevice(const AudioNode& node) { 597 AudioDevice device(node); 598 if (device.is_input) { 599 if (device.active && device.id != active_input_node_id_) { 600 LOG(WARNING) << "Stale audio device data, should not be active: " 601 << " device = " << device.ToString() 602 << " current active input node id = 0x" << std::hex 603 << active_input_node_id_; 604 device.active = false; 605 } else if (device.id == active_input_node_id_ && !device.active) { 606 LOG(WARNING) << "Stale audio device data, should be active:" 607 << " device = " << device.ToString() 608 << " current active input node id = 0x" << std::hex 609 << active_input_node_id_; 610 device.active = true; 611 } 612 } else { 613 if (device.active && device.id != active_output_node_id_) { 614 LOG(WARNING) << "Stale audio device data, should not be active: " 615 << " device = " << device.ToString() 616 << " current active output node id = 0x" << std::hex 617 << active_output_node_id_; 618 device.active = false; 619 } else if (device.id == active_output_node_id_ && !device.active) { 620 LOG(WARNING) << "Stale audio device data, should be active:" 621 << " device = " << device.ToString() 622 << " current active output node id = 0x" << std::hex 623 << active_output_node_id_; 624 device.active = true; 625 } 626 } 627 return device; 628 } 629 630 void CrasAudioHandler::UpdateDevicesAndSwitchActive( 631 const AudioNodeList& nodes) { 632 size_t old_audio_devices_size = audio_devices_.size(); 633 bool output_devices_changed = HasDeviceChange(nodes, false); 634 bool input_devices_changed = HasDeviceChange(nodes, true); 635 audio_devices_.clear(); 636 has_alternative_input_ = false; 637 has_alternative_output_ = false; 638 639 while (!input_devices_pq_.empty()) 640 input_devices_pq_.pop(); 641 while (!output_devices_pq_.empty()) 642 output_devices_pq_.pop(); 643 644 for (size_t i = 0; i < nodes.size(); ++i) { 645 AudioDevice device = GetSanitizedAudioDevice(nodes[i]); 646 audio_devices_[device.id] = device; 647 648 if (!has_alternative_input_ && 649 device.is_input && 650 device.type != AUDIO_TYPE_INTERNAL_MIC) { 651 has_alternative_input_ = true; 652 } else if (!has_alternative_output_ && 653 !device.is_input && 654 device.type != AUDIO_TYPE_INTERNAL_SPEAKER) { 655 has_alternative_output_ = true; 656 } 657 658 if (device.is_input) 659 input_devices_pq_.push(device); 660 else 661 output_devices_pq_.push(device); 662 } 663 664 // If audio nodes change is caused by unplugging some non-active audio 665 // devices, the previously set active audio device will stay active. 666 // Otherwise, switch to a new active audio device according to their priority. 667 if (input_devices_changed && 668 !NonActiveDeviceUnplugged(old_audio_devices_size, 669 audio_devices_.size(), 670 active_input_node_id_) && 671 !input_devices_pq_.empty()) 672 SwitchToDevice(input_devices_pq_.top()); 673 if (output_devices_changed && 674 !NonActiveDeviceUnplugged(old_audio_devices_size, 675 audio_devices_.size(), 676 active_output_node_id_) && 677 !output_devices_pq_.empty()) { 678 SwitchToDevice(output_devices_pq_.top()); 679 } 680 } 681 682 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, 683 bool success) { 684 if (!success) { 685 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; 686 return; 687 } 688 689 UpdateDevicesAndSwitchActive(node_list); 690 FOR_EACH_OBSERVER(AudioObserver, observers_, OnAudioNodesChanged()); 691 } 692 693 void CrasAudioHandler::HandleGetNodesError(const std::string& error_name, 694 const std::string& error_msg) { 695 LOG_IF(ERROR, log_errors_) << "Failed to call GetNodes: " 696 << error_name << ": " << error_msg; 697 } 698 } // namespace chromeos 699