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