Chromium Code Reviews| Index: chromeos/audio/cras_audio_handler.cc |
| diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..30979d07800a51f693cc2b12c5dac3490b9eb144 |
| --- /dev/null |
| +++ b/chromeos/audio/cras_audio_handler.cc |
| @@ -0,0 +1,308 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chromeos/audio/cras_audio_handler.h" |
| + |
| +#include <algorithm> |
| +#include <cmath> |
| + |
| +#include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| +#include "base/logging.h" |
| +#include "base/prefs/pref_registry_simple.h" |
| +#include "base/prefs/pref_service.h" |
| +#include "chromeos/audio/audio_pref_names.h" |
| +#include "chromeos/dbus/dbus_thread_manager.h" |
| + |
| +using std::max; |
| +using std::min; |
| + |
| +namespace chromeos { |
| + |
| +namespace { |
| + |
| +// Default value for the volume pref, as a percent in the range [0, 100]. |
| +const int kDefaultVolumePercent = 75; |
| + |
| +// Default value for unmuting, as a percent in the range [0, 100]. |
| +// Used when sound is unmuted, but volume was less than kMuteThresholdPercent. |
| +const int kDefaultUnmuteVolumePercent = 4; |
| + |
| +// Volume value which should be considered as muted in range [0, 100]. |
| +const int kMuteThresholdPercent = 1; |
| + |
| +// Values used for output muted preference. |
| +const int kPrefOutputMuteOff = 0; |
| +const int kPrefOutputMuteOn = 1; |
| + |
| +static CrasAudioHandler* g_cras_audio_handler = NULL; |
| + |
| +} // namespace |
| + |
| +CrasAudioHandler::AudioObserver::AudioObserver() { |
| +} |
| + |
| +CrasAudioHandler::AudioObserver::~AudioObserver() { |
| +} |
| + |
| +void CrasAudioHandler::AudioObserver::OnOutputVolumeChanged() { |
| +} |
| + |
| +void CrasAudioHandler::AudioObserver::OnOutputMuteChanged() { |
| +} |
| + |
| +void CrasAudioHandler::AudioObserver::OnInputMuteChanged() { |
| +} |
| + |
| +void CrasAudioHandler::AudioObserver::OnAudioNodesChanged() { |
| +} |
| + |
| +void CrasAudioHandler::AudioObserver::OnActiveOutputNodeChanged() { |
| +} |
| + |
| +void CrasAudioHandler::AudioObserver::OnActiveInputNodeChanged() { |
| +} |
| + |
| +// static |
| +void CrasAudioHandler::Initialize(PrefService* local_state) { |
| + CHECK(!g_cras_audio_handler); |
| + g_cras_audio_handler = new CrasAudioHandler(local_state); |
| +} |
| + |
| +// static |
| +void CrasAudioHandler::Shutdown() { |
| + CHECK(g_cras_audio_handler); |
| + delete g_cras_audio_handler; |
| + g_cras_audio_handler = NULL; |
| +} |
| + |
| +// static |
| +bool CrasAudioHandler::IsInitialized() { |
| + return g_cras_audio_handler != NULL; |
| +} |
| + |
| +// static |
| +CrasAudioHandler* CrasAudioHandler::Get() { |
| + CHECK(g_cras_audio_handler) |
| + << "CrasAudioHandler::Get() called before Initialize()."; |
| + return g_cras_audio_handler; |
| +} |
| + |
| +// static |
| +void CrasAudioHandler::RegisterPrefs(PrefRegistrySimple* registry) { |
| + registry->RegisterDoublePref(prefs::kAudioVolumePercent, |
| + kDefaultVolumePercent); |
| + registry->RegisterIntegerPref(prefs::kAudioMute, kPrefOutputMuteOff); |
| + // Register the prefs backing the audio muting policies. |
| + registry->RegisterBooleanPref(prefs::kAudioOutputAllowed, true); |
| + // This pref has moved to the media subsystem but we should verify it is there |
| + // before we use it. |
| + registry->RegisterBooleanPref(prefs::kAudioCaptureAllowed, true); |
| +} |
| + |
| +void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) { |
| + observers_.AddObserver(observer); |
| +} |
| + |
| +void CrasAudioHandler::RemoveAudioObserver(AudioObserver* observer) { |
| + observers_.RemoveObserver(observer); |
| +} |
| + |
| +bool CrasAudioHandler::IsOutputMuted() { |
| + return output_mute_on_; |
| +} |
| + |
| +bool CrasAudioHandler::IsInputMuted() { |
| + return input_mute_on_; |
| +} |
| + |
| +int CrasAudioHandler::GetOutputVolumePercent() { |
| + return output_volume_; |
| +} |
| + |
| +uint64 CrasAudioHandler::GetActiveOutputNode() const { |
| + return active_output_node_id_; |
| +} |
| + |
| +uint64 CrasAudioHandler::GetActiveInputNode() const { |
| + return active_input_node_id_; |
| +} |
| + |
| +void CrasAudioHandler::SetOutputVolumePercent(int volume_percent) { |
| + volume_percent = min(max(volume_percent, 0), 100); |
| + if (volume_percent <= kMuteThresholdPercent) |
| + volume_percent = 0; |
| + if (IsOutputMuted() && volume_percent > 0) |
| + SetOutputMute(false); |
| + if (!IsOutputMuted() && volume_percent == 0) |
| + SetOutputMute(true); |
| + SetOutputVolumeInternal(volume_percent); |
| +} |
| + |
| +void CrasAudioHandler::AdjustOutputVolumeByPercent(int adjust_by_percent) { |
| + SetOutputVolumePercent(output_volume_ + adjust_by_percent); |
| +} |
| + |
| +void CrasAudioHandler::SetOutputMute(bool mute_on) { |
| + if (output_mute_locked_) { |
| + NOTREACHED() << "Output mute has been locked"; |
| + return; |
| + } |
| + |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + SetOutputMute(mute_on); |
| +} |
| + |
| +void CrasAudioHandler::SetInputMute(bool mute_on) { |
| + if (input_mute_locked_) { |
| + NOTREACHED() << "Input mute has been locked"; |
| + return; |
| + } |
| + |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + SetInputMute(mute_on); |
| +} |
| + |
| +void CrasAudioHandler::SetActiveOutputNode(uint64 node_id) { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + SetActiveOutputNode(node_id); |
| +} |
| + |
| +void CrasAudioHandler::SetActiveInputNode(uint64 node_id) { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + SetActiveInputNode(node_id); |
| +} |
| + |
| +CrasAudioHandler::CrasAudioHandler(PrefService* local_state) |
| + : weak_ptr_factory_(this), |
|
stevenjb
2013/04/17 01:25:12
ALLOW_THIS...
jennyz
2013/04/18 01:21:19
Done.
|
| + local_state_(local_state), |
| + output_mute_on_(false), |
| + input_mute_on_(false), |
| + output_volume_(0), |
| + active_output_node_id_(0), |
| + active_input_node_id_(0), |
| + output_mute_locked_(false), |
| + input_mute_locked_(false) { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->AddObserver(this); |
| + SetupInitialAudioState(); |
| +} |
| + |
| +CrasAudioHandler::~CrasAudioHandler() { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + RemoveObserver(this); |
| +} |
| + |
| +void CrasAudioHandler::AudioClientRestarted() { |
| + SetupInitialAudioState(); |
| +} |
| + |
| +void CrasAudioHandler::OutputVolumeChanged(int volume) { |
| + if (output_volume_ != volume) { |
|
stevenjb
2013/04/17 01:25:12
nit: early exit instead
jennyz
2013/04/18 01:21:19
Done.
|
| + output_volume_ = volume; |
| + local_state_->SetDouble(prefs::kAudioVolumePercent, output_volume_); |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged()); |
| + } |
| +} |
| + |
| +void CrasAudioHandler::OutputMuteChanged(bool mute_on) { |
| + if (output_mute_on_ != mute_on) { |
|
stevenjb
2013/04/17 01:25:12
nit: early exit
jennyz
2013/04/18 01:21:19
Done.
|
| + output_mute_on_ = mute_on; |
| + local_state_->SetInteger( |
| + prefs::kAudioMute, |
| + output_mute_on_ ? kPrefOutputMuteOn : kPrefOutputMuteOff); |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged()); |
| + } |
| +} |
| + |
| +void CrasAudioHandler::InputMuteChanged(bool mute_on) { |
|
stevenjb
2013/04/17 01:25:12
nit: early exit
jennyz
2013/04/18 01:21:19
Done.
|
| + if (input_mute_on_ != mute_on) { |
| + input_mute_on_ = mute_on; |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnInputMuteChanged()); |
| + } |
| +} |
| + |
| +void CrasAudioHandler::NodesChanged() { |
| + // Refresh audio nodes data. |
| + GetNodes(); |
| +} |
| + |
| +void CrasAudioHandler::ActiveOutputNodeChanged(uint64 node_id) { |
| + active_output_node_id_ = node_id; |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveOutputNodeChanged()); |
| +} |
| + |
| +void CrasAudioHandler::ActiveInputNodeChanged(uint64 node_id) { |
| + active_input_node_id_ = node_id; |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnActiveInputNodeChanged()); |
| +} |
| + |
| +void CrasAudioHandler::InitializePrefObservers() { |
| + pref_change_registrar_.Init(local_state_); |
| + base::Closure callback = base::Bind(&CrasAudioHandler::ApplyAudioPolicy, |
| + weak_ptr_factory_.GetWeakPtr()); |
| + pref_change_registrar_.Add(prefs::kAudioOutputAllowed, callback); |
| + pref_change_registrar_.Add(prefs::kAudioCaptureAllowed, callback); |
| +} |
| + |
| +void CrasAudioHandler::SetupInitialAudioState() { |
| + ApplyAudioPolicy(); |
| + |
| + // Set the initial audio state to the ones read from audio prefs. |
| + output_mute_on_ = |
| + (local_state_->GetInteger(prefs::kAudioMute) == kPrefOutputMuteOn); |
| + output_volume_ = local_state_->GetDouble(prefs::kAudioVolumePercent); |
| + SetOutputMute(output_mute_on_); |
| + SetOutputVolumeInternal(output_volume_); |
| + |
| + // Get the initial audio data. |
| + GetNodes(); |
| +} |
| + |
| +void CrasAudioHandler::ApplyAudioPolicy() { |
| + output_mute_locked_ = false; |
| + if (!local_state_->GetBoolean(prefs::kAudioOutputAllowed)) { |
| + SetOutputMute(true); |
| + output_mute_locked_ = true; |
| + } |
| + |
| + input_mute_locked_ = false; |
| + if (local_state_->GetBoolean(prefs::kAudioCaptureAllowed)) { |
| + SetInputMute(false); |
| + } else { |
| + SetInputMute(true); |
| + input_mute_locked_ = true; |
| + } |
| +} |
| + |
| +void CrasAudioHandler::SetOutputVolumeInternal(int volume) { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + SetOutputVolume(volume); |
| +} |
| + |
| +void CrasAudioHandler::GetNodes() { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()->GetNodes( |
| + base::Bind(&CrasAudioHandler::HandleGetNodes, |
| + weak_ptr_factory_.GetWeakPtr())); |
| +} |
| + |
| +void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list, |
| + bool success) { |
| + if (!success) { |
| + LOG(ERROR) << "Failed to retrieve audio nodes data"; |
| + return; |
| + } |
| + |
| + audio_nodes_.clear(); |
| + for (size_t i = 0; i < node_list.size(); ++i) { |
| + if (node_list[i].is_input && node_list[i].active) |
| + active_input_node_id_ = node_list[i].id; |
| + else if (!node_list[i].is_input && node_list[i].active) |
| + active_output_node_id_ = node_list[i].id; |
| + audio_nodes_.push_back(node_list[i]); |
| + } |
| + |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnAudioNodesChanged()); |
| +} |
| + |
| +} // namespace chromeos |