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