1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/audio/cras_audio_handler.h"
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"
24 // Default value for unmuting, as a percent in the range [0, 100].
25 // Used when sound is unmuted, but volume was less than kMuteThresholdPercent.
26 const int kDefaultUnmuteVolumePercent
= 4;
28 // Volume value which should be considered as muted in range [0, 100].
29 const int kMuteThresholdPercent
= 1;
31 static CrasAudioHandler
* g_cras_audio_handler
= NULL
;
33 bool IsSameAudioDevice(const AudioDevice
& a
, const AudioDevice
& b
) {
34 return a
.id
== b
.id
&& a
.is_input
== b
.is_input
&& a
.type
== b
.type
35 && a
.device_name
== b
.device_name
;
40 CrasAudioHandler::AudioObserver::AudioObserver() {
43 CrasAudioHandler::AudioObserver::~AudioObserver() {
46 void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() {
49 void CrasAudioHandler::AudioObserver::OnInputGainChanged() {
52 void CrasAudioHandler::AudioObserver::OnOutputMuteChanged() {
55 void CrasAudioHandler::AudioObserver::OnInputMuteChanged() {
58 void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() {
61 void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() {
64 void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() {
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
);
75 void CrasAudioHandler::InitializeForTesting() {
76 CHECK(!g_cras_audio_handler
);
77 CrasAudioHandler::Initialize(new AudioDevicesPrefHandlerStub());
81 void CrasAudioHandler::Shutdown() {
82 CHECK(g_cras_audio_handler
);
83 delete g_cras_audio_handler
;
84 g_cras_audio_handler
= NULL
;
88 bool CrasAudioHandler::IsInitialized() {
89 return g_cras_audio_handler
!= NULL
;
93 CrasAudioHandler
* CrasAudioHandler::Get() {
94 CHECK(g_cras_audio_handler
)
95 << "CrasAudioHandler::Get() called before Initialize().";
96 return g_cras_audio_handler
;
99 void CrasAudioHandler::AddAudioObserver(AudioObserver
* observer
) {
100 observers_
.AddObserver(observer
);
103 void CrasAudioHandler::RemoveAudioObserver(AudioObserver
* observer
) {
104 observers_
.RemoveObserver(observer
);
107 bool CrasAudioHandler::IsOutputMuted() {
108 return output_mute_on_
;
111 bool CrasAudioHandler::IsOutputMutedForDevice(uint64 device_id
) {
112 const AudioDevice
* device
= GetDeviceFromId(device_id
);
115 return audio_pref_handler_
->GetMuteValue(*device
);
118 bool CrasAudioHandler::IsOutputVolumeBelowDefaultMuteLvel() {
119 return output_volume_
<= kMuteThresholdPercent
;
122 bool CrasAudioHandler::IsInputMuted() {
123 return input_mute_on_
;
126 bool CrasAudioHandler::IsInputMutedForDevice(uint64 device_id
) {
127 const AudioDevice
* device
= GetDeviceFromId(device_id
);
130 return audio_pref_handler_
->GetMuteValue(*device
);
133 int CrasAudioHandler::GetOutputVolumePercent() {
134 return output_volume_
;
137 int CrasAudioHandler::GetOutputVolumePercentForDevice(uint64 device_id
) {
138 if (device_id
== active_output_node_id_
) {
139 return output_volume_
;
141 const AudioDevice
* device
= GetDeviceFromId(device_id
);
142 return static_cast<int>(audio_pref_handler_
->GetOutputVolumeValue(device
));
146 int CrasAudioHandler::GetInputGainPercent() {
150 int CrasAudioHandler::GetInputGainPercentForDevice(uint64 device_id
) {
151 if (device_id
== active_input_node_id_
) {
154 const AudioDevice
* device
= GetDeviceFromId(device_id
);
155 return static_cast<int>(audio_pref_handler_
->GetInputGainValue(device
));
159 uint64
CrasAudioHandler::GetActiveOutputNode() const {
160 return active_output_node_id_
;
163 uint64
CrasAudioHandler::GetActiveInputNode() const {
164 return active_input_node_id_
;
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
);
174 bool CrasAudioHandler::GetActiveOutputDevice(AudioDevice
* device
) const {
175 const AudioDevice
* active_device
= GetDeviceFromId(active_output_node_id_
);
176 if (!active_device
|| !device
)
178 *device
= *active_device
;
182 bool CrasAudioHandler::has_alternative_input() const {
183 return has_alternative_input_
;
186 bool CrasAudioHandler::has_alternative_output() const {
187 return has_alternative_output_
;
190 void CrasAudioHandler::SetOutputVolumePercent(int volume_percent
) {
191 volume_percent
= min(max(volume_percent
, 0), 100);
192 if (volume_percent
<= kMuteThresholdPercent
)
194 output_volume_
= volume_percent
;
196 if (const AudioDevice
* device
= GetDeviceFromId(active_output_node_id_
))
197 audio_pref_handler_
->SetVolumeGainValue(*device
, output_volume_
);
199 SetOutputNodeVolume(active_output_node_id_
, output_volume_
);
200 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnOutputVolumeChanged());
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
;
209 if (const AudioDevice
* device
= GetDeviceFromId(active_input_node_id_
))
210 audio_pref_handler_
->SetVolumeGainValue(*device
, input_gain_
);
212 SetInputNodeGain(active_input_node_id_
, input_gain_
);
213 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnInputGainChanged());
216 void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent
) {
217 SetOutputVolumePercent(output_volume_
+ adjust_by_percent
);
220 void CrasAudioHandler::SetOutputMute(bool mute_on
) {
221 if (!SetOutputMuteInternal(mute_on
))
224 if (const AudioDevice
* device
= GetDeviceFromId(active_output_node_id_
))
225 audio_pref_handler_
->SetMuteValue(*device
, output_mute_on_
);
227 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnOutputMuteChanged());
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
);
238 void CrasAudioHandler::SetInputMute(bool mute_on
) {
239 if (!SetInputMuteInternal(mute_on
))
243 if (const AudioDevice
* device
= GetDeviceFromId(active_input_node_id_
))
244 audio_pref_handler_
->SetMuteValue(*device
, input_mute_on_
);
247 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnInputMuteChanged());
250 void CrasAudioHandler::SetActiveOutputNode(uint64 node_id
) {
251 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
252 SetActiveOutputNode(node_id
);
253 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnActiveOutputNodeChanged());
256 void CrasAudioHandler::SetActiveInputNode(uint64 node_id
) {
257 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
258 SetActiveInputNode(node_id
);
259 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnActiveInputNodeChanged());
262 void CrasAudioHandler::SetVolumeGainPercentForDevice(uint64 device_id
,
264 if (device_id
== active_output_node_id_
) {
265 SetOutputVolumePercent(value
);
267 } else if (device_id
== active_input_node_id_
) {
268 SetInputGainPercent(value
);
272 if (const AudioDevice
* device
= GetDeviceFromId(device_id
)) {
273 if (!device
->is_input
) {
274 value
= min(max(value
, 0), 100);
275 if (value
<= kMuteThresholdPercent
)
278 audio_pref_handler_
->SetVolumeGainValue(*device
, value
);
282 void CrasAudioHandler::SetMuteForDevice(uint64 device_id
, bool mute_on
) {
283 if (device_id
== active_output_node_id_
) {
284 SetOutputMute(mute_on
);
286 } else if (device_id
== active_input_node_id_
) {
287 SetInputMute(mute_on
);
292 if (const AudioDevice
* device
= GetDeviceFromId(device_id
))
293 audio_pref_handler_
->SetMuteValue(*device
, mute_on
);
296 void CrasAudioHandler::LogErrors() {
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),
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),
315 if (!audio_pref_handler
.get())
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())
323 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this);
324 audio_pref_handler_
->AddAudioPrefObserver(this);
325 if (chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) {
326 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
329 InitializeAudioState();
332 CrasAudioHandler::~CrasAudioHandler() {
333 if (!chromeos::DBusThreadManager::IsInitialized() ||
334 !chromeos::DBusThreadManager::Get() ||
335 !chromeos::DBusThreadManager::Get()->GetCrasAudioClient())
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
;
346 void CrasAudioHandler::AudioClientRestarted() {
347 // Make sure the logging is enabled in case cras server
348 // restarts after crashing.
350 InitializeAudioState();
353 void CrasAudioHandler::NodesChanged() {
354 // Refresh audio nodes data.
358 void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id
) {
359 if (active_output_node_id_
== node_id
)
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
;
372 void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id
) {
373 if (active_input_node_id_
== node_id
)
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
;
386 void CrasAudioHandler::OnAudioPolicyPrefChanged() {
390 void CrasAudioHandler::EmitLoginPromptVisibleCalled() {
391 // Enable logging after cras server is started, which will be after
392 // EmitLoginPromptVisible.
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())
401 return &(it
->second
);
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_
);
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_
;
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.
420 void CrasAudioHandler::SetupAudioOutputState() {
421 const AudioDevice
* device
= GetDeviceFromId(active_output_node_id_
);
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_
;
428 output_mute_on_
= audio_pref_handler_
->GetMuteValue(*device
);
429 output_volume_
= audio_pref_handler_
->GetOutputVolumeValue(device
);
431 SetOutputMuteInternal(output_mute_on_
);
432 SetOutputNodeVolume(active_output_node_id_
, output_volume_
);
435 void CrasAudioHandler::InitializeAudioState() {
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;
447 // Restore the mute state.
448 const AudioDevice
* device
= GetDeviceFromId(active_output_node_id_
);
450 SetOutputMuteInternal(audio_pref_handler_
->GetMuteValue(*device
));
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_
);
458 SetInputMuteInternal(false);
461 input_mute_locked_
= true;
465 void CrasAudioHandler::SetOutputNodeVolume(uint64 node_id
, int volume
) {
466 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
467 SetOutputNodeVolume(node_id
, volume
);
470 bool CrasAudioHandler::SetOutputMuteInternal(bool mute_on
) {
471 if (output_mute_locked_
)
474 output_mute_on_
= mute_on
;
475 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
476 SetOutputUserMute(mute_on
);
480 void CrasAudioHandler::SetInputNodeGain(uint64 node_id
, int gain
) {
481 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
482 SetInputNodeGain(node_id
, gain
);
485 bool CrasAudioHandler::SetInputMuteInternal(bool mute_on
) {
486 if (input_mute_locked_
)
489 input_mute_on_
= mute_on
;
490 chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->
491 SetInputMute(mute_on
);
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()));
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,
507 if (new_active_device
.active
&&
508 new_active_device
.id
== *current_active_node_id
) {
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;
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;
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
));
536 void CrasAudioHandler::SwitchToDevice(const AudioDevice
& device
) {
537 if (device
.is_input
) {
538 if (!ChangeActiveDevice(device
, &active_input_node_id_
))
540 SetupAudioInputState();
541 SetActiveInputNode(active_input_node_id_
);
543 if (!ChangeActiveDevice(device
, &active_output_node_id_
))
545 SetupAudioOutputState();
546 SetActiveOutputNode(active_output_node_id_
);
550 bool CrasAudioHandler::HasDeviceChange(const AudioNodeList
& new_nodes
,
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
)
560 for (AudioNodeList::const_iterator it
= new_nodes
.begin();
561 it
!= new_nodes
.end(); ++it
) {
562 if (is_input
== it
->is_input
) {
564 // Look to see if the new device not in the old device list.
565 AudioDevice
device(*it
);
566 if (FoundNewDevice(device
))
570 return num_old_devices
!= num_new_devices
;
573 bool CrasAudioHandler::FoundNewDevice(const AudioDevice
& device
) {
574 const AudioDevice
* device_found
= GetDeviceFromId(device
.id
);
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();
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;
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;
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;
639 while (!input_devices_pq_
.empty())
640 input_devices_pq_
.pop();
641 while (!output_devices_pq_
.empty())
642 output_devices_pq_
.pop();
644 for (size_t i
= 0; i
< nodes
.size(); ++i
) {
645 AudioDevice device
= GetSanitizedAudioDevice(nodes
[i
]);
646 audio_devices_
[device
.id
] = device
;
648 if (!has_alternative_input_
&&
650 device
.type
!= AUDIO_TYPE_INTERNAL_MIC
) {
651 has_alternative_input_
= true;
652 } else if (!has_alternative_output_
&&
654 device
.type
!= AUDIO_TYPE_INTERNAL_SPEAKER
) {
655 has_alternative_output_
= true;
659 input_devices_pq_
.push(device
);
661 output_devices_pq_
.push(device
);
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());
682 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList
& node_list
,
685 LOG_IF(ERROR
, log_errors_
) << "Failed to retrieve audio nodes data";
689 UpdateDevicesAndSwitchActive(node_list
);
690 FOR_EACH_OBSERVER(AudioObserver
, observers_
, OnAudioNodesChanged());
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
;
698 } // namespace chromeos