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 bool IsInNodeList(uint64 node_id, const CrasAudioHandler::NodeIdList& id_list) { 39 return std::find(id_list.begin(), id_list.end(), node_id) != id_list.end(); 40 } 41 42 } // namespace 43 44 CrasAudioHandler::AudioObserver::AudioObserver() { 45 } 46 47 CrasAudioHandler::AudioObserver::~AudioObserver() { 48 } 49 50 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() { 51 } 52 53 void CrasAudioHandler::AudioObserver::OnInputGainChanged() { 54 } 55 56 void CrasAudioHandler::AudioObserver::OnOutputMuteChanged() { 57 } 58 59 void CrasAudioHandler::AudioObserver::OnInputMuteChanged() { 60 } 61 62 void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() { 63 } 64 65 void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() { 66 } 67 68 void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() { 69 } 70 71 // static 72 void CrasAudioHandler::Initialize( 73 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler) { 74 CHECK(!g_cras_audio_handler); 75 g_cras_audio_handler = new CrasAudioHandler(audio_pref_handler); 76 } 77 78 // static 79 void CrasAudioHandler::InitializeForTesting() { 80 CHECK(!g_cras_audio_handler); 81 CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub()); 82 } 83 84 // static 85 void CrasAudioHandler::Shutdown() { 86 CHECK(g_cras_audio_handler); 87 delete g_cras_audio_handler; 88 g_cras_audio_handler = NULL; 89 } 90 91 // static 92 bool CrasAudioHandler::IsInitialized() { 93 return g_cras_audio_handler != NULL; 94 } 95 96 // static 97 CrasAudioHandler* CrasAudioHandler::Get() { 98 CHECK(g_cras_audio_handler) 99 << "CrasAudioHandler::Get() called before Initialize()."; 100 return g_cras_audio_handler; 101 } 102 103 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) { 104 observers_.AddObserver(observer); 105 } 106 107 void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) { 108 observers_.RemoveObserver(observer); 109 } 110 111 bool CrasAudioHandler::HasKeyboardMic() { 112 return GetKeyboardMic() != NULL; 113 } 114 115 bool CrasAudioHandler::IsOutputMuted() { 116 return output_mute_on_; 117 } 118 119 bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id) { 120 const AudioDevice* device = GetDeviceFromId(device_id); 121 if (!device) 122 return false; 123 DCHECK(!device->is_input); 124 return audio_pref_handler_->GetMuteValue(*device); 125 } 126 127 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLevel() { 128 return output_volume_ <= kMuteThresholdPercent; 129 } 130 131 bool CrasAudioHandler::IsInputMuted() { 132 return input_mute_on_; 133 } 134 135 bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id) { 136 const AudioDevice* device = GetDeviceFromId(device_id); 137 if (!device) 138 return false; 139 DCHECK(device->is_input); 140 // We don't record input mute state for each device in the prefs, 141 // for any non-active input device, we assume mute is off. 142 if (device->id == active_input_node_id_) 143 return input_mute_on_; 144 return false; 145 } 146 147 int CrasAudioHandler::GetOutputDefaultVolumeMuteThreshold() { 148 return kMuteThresholdPercent; 149 } 150 151 int CrasAudioHandler::GetOutputVolumePercent() { 152 return output_volume_; 153 } 154 155 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64 device_id) { 156 if (device_id == active_output_node_id_) { 157 return output_volume_; 158 } else { 159 const AudioDevice* device = GetDeviceFromId(device_id); 160 return static_cast<int>(audio_pref_handler_->GetOutputVolumeValue(device)); 161 } 162 } 163 164 int CrasAudioHandler::GetInputGainPercent() { 165 return input_gain_; 166 } 167 168 int CrasAudioHandler::GetInputGainPercentForDevice(uint64 device_id) { 169 if (device_id == active_input_node_id_) { 170 return input_gain_; 171 } else { 172 const AudioDevice* device = GetDeviceFromId(device_id); 173 return static_cast<int>(audio_pref_handler_->GetInputGainValue(device)); 174 } 175 } 176 177 uint64 CrasAudioHandler::GetPrimaryActiveOutputNode() const { 178 return active_output_node_id_; 179 } 180 181 uint64 CrasAudioHandler::GetPrimaryActiveInputNode() const { 182 return active_input_node_id_; 183 } 184 185 void CrasAudioHandler::GetAudioDevices(AudioDeviceList* device_list) const { 186 device_list->clear(); 187 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 188 it != audio_devices_.end(); ++it) 189 device_list->push_back(it->second); 190 } 191 192 bool CrasAudioHandler::GetPrimaryActiveOutputDevice(AudioDevice* device) const { 193 const AudioDevice* active_device = GetDeviceFromId(active_output_node_id_); 194 if (!active_device || !device) 195 return false; 196 *device = *active_device; 197 return true; 198 } 199 200 void CrasAudioHandler::SetKeyboardMicActive(bool active) { 201 const AudioDevice* keyboard_mic = GetKeyboardMic(); 202 if (!keyboard_mic) 203 return; 204 // Keyboard mic is invisible to chromeos users. It is always added or removed 205 // as additional active node. 206 DCHECK(active_input_node_id_ && active_input_node_id_ != keyboard_mic->id); 207 if (active) 208 AddActiveNode(keyboard_mic->id, true); 209 else 210 RemoveActiveNodeInternal(keyboard_mic->id, true); 211 } 212 213 void CrasAudioHandler::AddActiveNode(uint64 node_id, bool notify) { 214 const AudioDevice* device = GetDeviceFromId(node_id); 215 if (!device) { 216 VLOG(1) << "AddActiveInputNode: Cannot find device id=" 217 << "0x" << std::hex << node_id; 218 return; 219 } 220 221 // If there is no primary active device, set |node_id| to primary active node. 222 if ((device->is_input && !active_input_node_id_) || 223 (!device->is_input && !active_output_node_id_)) { 224 SwitchToDevice(*device, notify); 225 return; 226 } 227 228 AddAdditionalActiveNode(node_id, notify); 229 } 230 231 void CrasAudioHandler::ChangeActiveNodes(const NodeIdList& new_active_ids) { 232 // Flags for whether there are input or output nodes passed in from 233 // |new_active_ids|. If there are no input nodes passed in, we will not 234 // make any change for input nodes; same for the output nodes. 235 bool request_input_change = false; 236 bool request_output_change = false; 237 238 // Flags for whether we will actually change active status of input 239 // or output nodes. 240 bool make_input_change = false; 241 bool make_output_change = false; 242 243 NodeIdList nodes_to_activate; 244 for (size_t i = 0; i < new_active_ids.size(); ++i) { 245 const AudioDevice* device = GetDeviceFromId(new_active_ids[i]); 246 if (device) { 247 if (device->is_input) 248 request_input_change = true; 249 else 250 request_output_change = true; 251 252 // If the new active device is already active, keep it as active. 253 if (device->active) 254 continue; 255 256 nodes_to_activate.push_back(new_active_ids[i]); 257 if (device->is_input) 258 make_input_change = true; 259 else 260 make_output_change = true; 261 } 262 } 263 264 // Remove all existing active devices that are not in the |new_active_ids| 265 // list. 266 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 267 it != audio_devices_.end(); ++it) { 268 AudioDevice device = it->second; 269 // Remove the existing active input or output nodes that are not in the new 270 // active node list if there are new input or output nodes specified. 271 if (device.active) { 272 if ((device.is_input && request_input_change && 273 !IsInNodeList(device.id, new_active_ids))) { 274 make_input_change = true; 275 RemoveActiveNodeInternal(device.id, false); // no notification. 276 } else if (!device.is_input && request_output_change && 277 !IsInNodeList(device.id, new_active_ids)) { 278 make_output_change = true; 279 RemoveActiveNodeInternal(device.id, false); // no notification. 280 } 281 } 282 } 283 284 // Adds the new active devices. 285 for (size_t i = 0; i < nodes_to_activate.size(); ++i) 286 AddActiveNode(nodes_to_activate[i], false); // no notification. 287 288 // Notify the active nodes change now. 289 if (make_input_change) 290 NotifyActiveNodeChanged(true); 291 if (make_output_change) 292 NotifyActiveNodeChanged(false); 293 } 294 295 bool CrasAudioHandler::has_alternative_input() const { 296 return has_alternative_input_; 297 } 298 299 bool CrasAudioHandler::has_alternative_output() const { 300 return has_alternative_output_; 301 } 302 303 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) { 304 // Set all active devices to the same volume. 305 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 306 it != audio_devices_.end(); 307 it++) { 308 const AudioDevice& device = it->second; 309 if (!device.is_input && device.active) 310 SetOutputNodeVolumePercent(device.id, volume_percent); 311 } 312 } 313 314 // TODO: Rename the 'Percent' to something more meaningful. 315 void CrasAudioHandler::SetInputGainPercent(int gain_percent) { 316 // TODO(jennyz): Should we set all input devices' gain to the same level? 317 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 318 it != audio_devices_.end(); 319 it++) { 320 const AudioDevice& device = it->second; 321 if (device.is_input && device.active) 322 SetInputNodeGainPercent(active_input_node_id_, gain_percent); 323 } 324 } 325 326 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) { 327 SetOutputVolumePercent(output_volume_ + adjust_by_percent); 328 } 329 330 void CrasAudioHandler::SetOutputMute(bool mute_on) { 331 if (!SetOutputMuteInternal(mute_on)) 332 return; 333 334 // Save the mute state for all active output audio devices. 335 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 336 it != audio_devices_.end(); 337 it++) { 338 const AudioDevice& device = it->second; 339 if (!device.is_input && device.active) { 340 audio_pref_handler_->SetMuteValue(device, output_mute_on_); 341 } 342 } 343 344 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged()); 345 } 346 347 void CrasAudioHandler::AdjustOutputVolumeToAudibleLevel() { 348 if (output_volume_ <= kMuteThresholdPercent) { 349 // Avoid the situation when sound has been unmuted, but the volume 350 // is set to a very low value, so user still can't hear any sound. 351 SetOutputVolumePercent(kDefaultUnmuteVolumePercent); 352 } 353 } 354 355 void CrasAudioHandler::SetInputMute(bool mute_on) { 356 if (!SetInputMuteInternal(mute_on)) 357 return; 358 359 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputMuteChanged()); 360 } 361 362 void CrasAudioHandler::SetActiveOutputNode(uint64 node_id, bool notify) { 363 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 364 SetActiveOutputNode(node_id); 365 if (notify) 366 NotifyActiveNodeChanged(false); 367 } 368 369 void CrasAudioHandler::SetActiveInputNode(uint64 node_id, bool notify) { 370 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 371 SetActiveInputNode(node_id); 372 if (notify) 373 NotifyActiveNodeChanged(true); 374 } 375 376 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64 device_id, 377 int value) { 378 const AudioDevice* device = GetDeviceFromId(device_id); 379 if (!device) 380 return; 381 382 if (device->is_input) 383 SetInputNodeGainPercent(device_id, value); 384 else 385 SetOutputNodeVolumePercent(device_id, value); 386 } 387 388 void CrasAudioHandler::SetMuteForDevice(uint64 device_id, bool mute_on) { 389 if (device_id == active_output_node_id_) { 390 SetOutputMute(mute_on); 391 return; 392 } else if (device_id == active_input_node_id_) { 393 VLOG(1) << "SetMuteForDevice sets active input device id=" 394 << "0x" << std::hex << device_id << " mute=" << mute_on; 395 SetInputMute(mute_on); 396 return; 397 } 398 399 const AudioDevice* device = GetDeviceFromId(device_id); 400 // Input device's mute state is not recorded in the pref. crbug.com/365050. 401 if (device && !device->is_input) 402 audio_pref_handler_->SetMuteValue(*device, mute_on); 403 } 404 405 void CrasAudioHandler::LogErrors() { 406 log_errors_ = true; 407 } 408 409 CrasAudioHandler::CrasAudioHandler( 410 scoped_refptr<AudioDevicesPrefHandler> audio_pref_handler) 411 : audio_pref_handler_(audio_pref_handler), 412 output_mute_on_(false), 413 input_mute_on_(false), 414 output_volume_(0), 415 input_gain_(0), 416 active_output_node_id_(0), 417 active_input_node_id_(0), 418 has_alternative_input_(false), 419 has_alternative_output_(false), 420 output_mute_locked_(false), 421 input_mute_locked_(false), 422 log_errors_(false), 423 weak_ptr_factory_(this) { 424 if (!audio_pref_handler.get()) 425 return; 426 // If the DBusThreadManager or the CrasAudioClient aren't available, there 427 // isn't much we can do. This should only happen when running tests. 428 if (!chromeos::DBusThreadManager::IsInitialized() || 429 !chromeos::DBusThreadManager::Get() || 430 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient()) 431 return; 432 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this); 433 audio_pref_handler_->AddAudioPrefObserver(this); 434 if (chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) { 435 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> 436 AddObserver(this); 437 } 438 InitializeAudioState(); 439 } 440 441 CrasAudioHandler::~CrasAudioHandler() { 442 if (!chromeos::DBusThreadManager::IsInitialized() || 443 !chromeos::DBusThreadManager::Get() || 444 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient()) 445 return; 446 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 447 RemoveObserver(this); 448 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> 449 RemoveObserver(this); 450 if (audio_pref_handler_.get()) 451 audio_pref_handler_->RemoveAudioPrefObserver(this); 452 audio_pref_handler_ = NULL; 453 } 454 455 void CrasAudioHandler::AudioClientRestarted() { 456 // Make sure the logging is enabled in case cras server 457 // restarts after crashing. 458 LogErrors(); 459 InitializeAudioState(); 460 } 461 462 void CrasAudioHandler::NodesChanged() { 463 // Refresh audio nodes data. 464 GetNodes(); 465 } 466 467 void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id) { 468 if (active_output_node_id_ == node_id) 469 return; 470 471 // Active audio output device should always be changed by chrome. 472 // During system boot, cras may change active input to unknown device 0x1, 473 // we don't need to log it, since it is not an valid device. 474 if (GetDeviceFromId(node_id)) { 475 LOG_IF(WARNING, log_errors_) 476 << "Active output node changed unexpectedly by system node_id=" 477 << "0x" << std::hex << node_id; 478 } 479 } 480 481 void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id) { 482 if (active_input_node_id_ == node_id) 483 return; 484 485 // Active audio input device should always be changed by chrome. 486 // During system boot, cras may change active input to unknown device 0x2, 487 // we don't need to log it, since it is not an valid device. 488 if (GetDeviceFromId(node_id)) { 489 LOG_IF(WARNING, log_errors_) 490 << "Active input node changed unexpectedly by system node_id=" 491 << "0x" << std::hex << node_id; 492 } 493 } 494 495 void CrasAudioHandler::OnAudioPolicyPrefChanged() { 496 ApplyAudioPolicy(); 497 } 498 499 void CrasAudioHandler::EmitLoginPromptVisibleCalled() { 500 // Enable logging after cras server is started, which will be after 501 // EmitLoginPromptVisible. 502 LogErrors(); 503 } 504 505 const AudioDevice* CrasAudioHandler::GetDeviceFromId(uint64 device_id) const { 506 AudioDeviceMap::const_iterator it = audio_devices_.find(device_id); 507 if (it == audio_devices_.end()) 508 return NULL; 509 510 return &(it->second); 511 } 512 513 const AudioDevice* CrasAudioHandler::GetKeyboardMic() const { 514 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 515 it != audio_devices_.end(); it++) { 516 if (it->second.is_input && it->second.type == AUDIO_TYPE_KEYBOARD_MIC) 517 return &(it->second); 518 } 519 return NULL; 520 } 521 522 void CrasAudioHandler::SetupAudioInputState() { 523 // Set the initial audio state to the ones read from audio prefs. 524 const AudioDevice* device = GetDeviceFromId(active_input_node_id_); 525 if (!device) { 526 LOG_IF(ERROR, log_errors_) 527 << "Can't set up audio state for unknown input device id =" 528 << "0x" << std::hex << active_input_node_id_; 529 return; 530 } 531 input_gain_ = audio_pref_handler_->GetInputGainValue(device); 532 VLOG(1) << "SetupAudioInputState for active device id=" 533 << "0x" << std::hex << device->id << " mute=" << input_mute_on_; 534 SetInputMuteInternal(input_mute_on_); 535 // TODO(rkc,jennyz): Set input gain once we decide on how to store 536 // the gain values since the range and step are both device specific. 537 } 538 539 void CrasAudioHandler::SetupAudioOutputState() { 540 const AudioDevice* device = GetDeviceFromId(active_output_node_id_); 541 if (!device) { 542 LOG_IF(ERROR, log_errors_) 543 << "Can't set up audio state for unknown output device id =" 544 << "0x" << std::hex << active_output_node_id_; 545 return; 546 } 547 DCHECK(!device->is_input); 548 output_mute_on_ = audio_pref_handler_->GetMuteValue(*device); 549 output_volume_ = audio_pref_handler_->GetOutputVolumeValue(device); 550 551 SetOutputMuteInternal(output_mute_on_); 552 SetOutputNodeVolume(active_output_node_id_, output_volume_); 553 } 554 555 // This sets up the state of an additional active node. 556 void CrasAudioHandler::SetupAdditionalActiveAudioNodeState(uint64 node_id) { 557 const AudioDevice* device = GetDeviceFromId(node_id); 558 if (!device) { 559 VLOG(1) << "Can't set up audio state for unknown device id =" 560 << "0x" << std::hex << node_id; 561 return; 562 } 563 564 DCHECK(node_id != active_output_node_id_ && node_id != active_input_node_id_); 565 566 // Note: The mute state is a system wide state, we don't set mute per device, 567 // but just keep the mute state consistent for the active node in prefs. 568 // The output volume should be set to the same value for all active output 569 // devices. For input devices, we don't restore their gain value so far. 570 // TODO(jennyz): crbug.com/417418, track the status for the decison if 571 // we should persist input gain value in prefs. 572 if (!device->is_input) { 573 audio_pref_handler_->SetMuteValue(*device, IsOutputMuted()); 574 SetOutputNodeVolumePercent(node_id, GetOutputVolumePercent()); 575 } 576 } 577 578 void CrasAudioHandler::InitializeAudioState() { 579 ApplyAudioPolicy(); 580 GetNodes(); 581 } 582 583 void CrasAudioHandler::ApplyAudioPolicy() { 584 output_mute_locked_ = false; 585 if (!audio_pref_handler_->GetAudioOutputAllowedValue()) { 586 // Mute the device, but do not update the preference. 587 SetOutputMuteInternal(true); 588 output_mute_locked_ = true; 589 } else { 590 // Restore the mute state. 591 const AudioDevice* device = GetDeviceFromId(active_output_node_id_); 592 if (device) 593 SetOutputMuteInternal(audio_pref_handler_->GetMuteValue(*device)); 594 } 595 596 input_mute_locked_ = false; 597 if (audio_pref_handler_->GetAudioCaptureAllowedValue()) { 598 VLOG(1) << "Audio input allowed by policy, sets input id=" 599 << "0x" << std::hex << active_input_node_id_ << " mute=false"; 600 SetInputMuteInternal(false); 601 } else { 602 VLOG(0) << "Audio input NOT allowed by policy, sets input id=" 603 << "0x" << std::hex << active_input_node_id_ << " mute=true"; 604 SetInputMuteInternal(true); 605 input_mute_locked_ = true; 606 } 607 } 608 609 void CrasAudioHandler::SetOutputNodeVolume(uint64 node_id, int volume) { 610 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 611 SetOutputNodeVolume(node_id, volume); 612 } 613 614 void CrasAudioHandler::SetOutputNodeVolumePercent(uint64 node_id, 615 int volume_percent) { 616 const AudioDevice* device = this->GetDeviceFromId(node_id); 617 if (!device || device->is_input) 618 return; 619 620 volume_percent = min(max(volume_percent, 0), 100); 621 if (volume_percent <= kMuteThresholdPercent) 622 volume_percent = 0; 623 if (node_id == active_output_node_id_) 624 output_volume_ = volume_percent; 625 626 audio_pref_handler_->SetVolumeGainValue(*device, volume_percent); 627 628 if (device->active) { 629 SetOutputNodeVolume(node_id, volume_percent); 630 FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged()); 631 } 632 } 633 634 bool CrasAudioHandler::SetOutputMuteInternal(bool mute_on) { 635 if (output_mute_locked_) 636 return false; 637 638 output_mute_on_ = mute_on; 639 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 640 SetOutputUserMute(mute_on); 641 return true; 642 } 643 644 void CrasAudioHandler::SetInputNodeGain(uint64 node_id, int gain) { 645 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 646 SetInputNodeGain(node_id, gain); 647 } 648 649 void CrasAudioHandler::SetInputNodeGainPercent(uint64 node_id, 650 int gain_percent) { 651 const AudioDevice* device = GetDeviceFromId(node_id); 652 if (!device || !device->is_input) 653 return; 654 655 // NOTE: We do not sanitize input gain values since the range is completely 656 // dependent on the device. 657 if (active_input_node_id_ == node_id) 658 input_gain_ = gain_percent; 659 660 audio_pref_handler_->SetVolumeGainValue(*device, gain_percent); 661 662 if (device->active) { 663 SetInputNodeGain(node_id, gain_percent); 664 FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputGainChanged()); 665 } 666 } 667 668 bool CrasAudioHandler::SetInputMuteInternal(bool mute_on) { 669 if (input_mute_locked_) 670 return false; 671 672 input_mute_on_ = mute_on; 673 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> 674 SetInputMute(mute_on); 675 return true; 676 } 677 678 void CrasAudioHandler::GetNodes() { 679 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes( 680 base::Bind(&CrasAudioHandler::HandleGetNodes, 681 weak_ptr_factory_.GetWeakPtr()), 682 base::Bind(&CrasAudioHandler::HandleGetNodesError, 683 weak_ptr_factory_.GetWeakPtr())); 684 } 685 686 bool CrasAudioHandler::ChangeActiveDevice(const AudioDevice& new_active_device, 687 uint64* current_active_node_id) { 688 // If the device we want to switch to is already the current active device, 689 // do nothing. 690 if (new_active_device.active && 691 new_active_device.id == *current_active_node_id) { 692 return false; 693 } 694 695 // Reset all other input or output devices' active status. The active audio 696 // device from the previous user session can be remembered by cras, but not 697 // in chrome. see crbug.com/273271. 698 for (AudioDeviceMap::iterator it = audio_devices_.begin(); 699 it != audio_devices_.end(); ++it) { 700 if (it->second.is_input == new_active_device.is_input && 701 it->second.id != new_active_device.id) 702 it->second.active = false; 703 } 704 705 // Set the current active input/output device to the new_active_device. 706 *current_active_node_id = new_active_device.id; 707 audio_devices_[*current_active_node_id].active = true; 708 return true; 709 } 710 711 bool CrasAudioHandler::NonActiveDeviceUnplugged( 712 size_t old_devices_size, 713 size_t new_devices_size, 714 uint64 current_active_node) { 715 return (new_devices_size < old_devices_size && 716 GetDeviceFromId(current_active_node)); 717 } 718 719 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device, bool notify) { 720 if (device.is_input) { 721 if (!ChangeActiveDevice(device, &active_input_node_id_)) 722 return; 723 SetupAudioInputState(); 724 SetActiveInputNode(active_input_node_id_, notify); 725 } else { 726 if (!ChangeActiveDevice(device, &active_output_node_id_)) 727 return; 728 SetupAudioOutputState(); 729 SetActiveOutputNode(active_output_node_id_, notify); 730 } 731 } 732 733 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList& new_nodes, 734 bool is_input) { 735 size_t num_old_devices = 0; 736 size_t num_new_devices = 0; 737 for (AudioDeviceMap::const_iterator it = audio_devices_.begin(); 738 it != audio_devices_.end(); ++it) { 739 if (is_input == it->second.is_input) 740 ++num_old_devices; 741 } 742 743 for (AudioNodeList::const_iterator it = new_nodes.begin(); 744 it != new_nodes.end(); ++it) { 745 if (is_input == it->is_input) { 746 ++num_new_devices; 747 // Look to see if the new device not in the old device list. 748 AudioDevice device(*it); 749 if (FoundNewOrChangedDevice(device)) 750 return true; 751 } 752 } 753 return num_old_devices != num_new_devices; 754 } 755 756 bool CrasAudioHandler::FoundNewOrChangedDevice(const AudioDevice& device) { 757 const AudioDevice* device_found = GetDeviceFromId(device.id); 758 if (!device_found) 759 return true; 760 761 if (!IsSameAudioDevice(device, *device_found)) { 762 LOG(WARNING) << "Different Audio devices with same id:" 763 << " new device: " << device.ToString() 764 << " old device: " << device_found->ToString(); 765 return true; 766 } else if (device.active != device_found->active) { 767 return true; 768 } 769 770 return false; 771 } 772 773 void CrasAudioHandler::NotifyActiveNodeChanged(bool is_input) { 774 if (is_input) 775 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); 776 else 777 FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); 778 } 779 780 void CrasAudioHandler::UpdateDevicesAndSwitchActive( 781 const AudioNodeList& nodes) { 782 size_t old_audio_devices_size = audio_devices_.size(); 783 bool output_devices_changed = HasDeviceChange(nodes, false); 784 bool input_devices_changed = HasDeviceChange(nodes, true); 785 audio_devices_.clear(); 786 has_alternative_input_ = false; 787 has_alternative_output_ = false; 788 789 while (!input_devices_pq_.empty()) 790 input_devices_pq_.pop(); 791 while (!output_devices_pq_.empty()) 792 output_devices_pq_.pop(); 793 794 for (size_t i = 0; i < nodes.size(); ++i) { 795 AudioDevice device(nodes[i]); 796 audio_devices_[device.id] = device; 797 798 if (!has_alternative_input_ && 799 device.is_input && 800 device.type != AUDIO_TYPE_INTERNAL_MIC && 801 device.type != AUDIO_TYPE_KEYBOARD_MIC) { 802 has_alternative_input_ = true; 803 } else if (!has_alternative_output_ && 804 !device.is_input && 805 device.type != AUDIO_TYPE_INTERNAL_SPEAKER) { 806 has_alternative_output_ = true; 807 } 808 809 if (device.is_input) 810 input_devices_pq_.push(device); 811 else 812 output_devices_pq_.push(device); 813 } 814 815 // If audio nodes change is caused by unplugging some non-active audio 816 // devices, the previously set active audio device will stay active. 817 // Otherwise, switch to a new active audio device according to their priority. 818 if (input_devices_changed && 819 !NonActiveDeviceUnplugged(old_audio_devices_size, 820 audio_devices_.size(), 821 active_input_node_id_) && 822 !input_devices_pq_.empty()) 823 SwitchToDevice(input_devices_pq_.top(), true); 824 if (output_devices_changed && 825 !NonActiveDeviceUnplugged(old_audio_devices_size, 826 audio_devices_.size(), 827 active_output_node_id_) && 828 !output_devices_pq_.empty()) { 829 SwitchToDevice(output_devices_pq_.top(), true); 830 } 831 } 832 833 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, 834 bool success) { 835 if (!success) { 836 LOG_IF(ERROR, log_errors_) << "Failed to retrieve audio nodes data"; 837 return; 838 } 839 840 UpdateDevicesAndSwitchActive(node_list); 841 FOR_EACH_OBSERVER(AudioObserver, observers_, OnAudioNodesChanged()); 842 } 843 844 void CrasAudioHandler::HandleGetNodesError(const std::string& error_name, 845 const std::string& error_msg) { 846 LOG_IF(ERROR, log_errors_) << "Failed to call GetNodes: " 847 << error_name << ": " << error_msg; 848 } 849 850 void CrasAudioHandler::AddAdditionalActiveNode(uint64 node_id, bool notify) { 851 const AudioDevice* device = GetDeviceFromId(node_id); 852 if (!device) { 853 VLOG(1) << "AddActiveInputNode: Cannot find device id=" 854 << "0x" << std::hex << node_id; 855 return; 856 } 857 858 audio_devices_[node_id].active = true; 859 SetupAdditionalActiveAudioNodeState(node_id); 860 861 if (device->is_input) { 862 DCHECK(node_id != active_input_node_id_); 863 chromeos::DBusThreadManager::Get() 864 ->GetCrasAudioClient() 865 ->AddActiveInputNode(node_id); 866 if (notify) 867 NotifyActiveNodeChanged(true); 868 } else { 869 DCHECK(node_id != active_output_node_id_); 870 chromeos::DBusThreadManager::Get() 871 ->GetCrasAudioClient() 872 ->AddActiveOutputNode(node_id); 873 if (notify) 874 NotifyActiveNodeChanged(false); 875 } 876 } 877 878 void CrasAudioHandler::RemoveActiveNodeInternal(uint64 node_id, bool notify) { 879 const AudioDevice* device = GetDeviceFromId(node_id); 880 if (!device) { 881 VLOG(1) << "RemoveActiveInputNode: Cannot find device id=" 882 << "0x" << std::hex << node_id; 883 return; 884 } 885 886 audio_devices_[node_id].active = false; 887 if (device->is_input) { 888 if (node_id == active_input_node_id_) 889 active_input_node_id_ = 0; 890 chromeos::DBusThreadManager::Get() 891 ->GetCrasAudioClient() 892 ->RemoveActiveInputNode(node_id); 893 if (notify) 894 NotifyActiveNodeChanged(true); 895 } else { 896 if (node_id == active_output_node_id_) 897 active_output_node_id_ = 0; 898 chromeos::DBusThreadManager::Get() 899 ->GetCrasAudioClient() 900 ->RemoveActiveOutputNode(node_id); 901 if (notify) 902 NotifyActiveNodeChanged(false); 903 } 904 } 905 906 } // namespace chromeos 907