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..e5bcec7e9dc043547bd1fd0a4a8683f8c8094a0a |
| --- /dev/null |
| +++ b/chromeos/audio/cras_audio_handler.cc |
| @@ -0,0 +1,297 @@ |
| +// 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 "chromeos/audio/audio_pref_handler.h" |
| +#include "chromeos/dbus/dbus_thread_manager.h" |
| + |
| +using std::max; |
| +using std::min; |
| + |
| +namespace chromeos { |
| + |
| +namespace { |
| + |
| +// 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; |
| + |
| +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( |
| + scoped_refptr<AudioPrefHandler> audio_pref_handler) { |
| + CHECK(!g_cras_audio_handler); |
| + g_cras_audio_handler = new CrasAudioHandler(audio_pref_handler); |
| +} |
| + |
| +// 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; |
| +} |
| + |
| +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); |
|
dgreid
2013/04/19 04:20:18
Should these be reversed? Is it possible that som
jennyz
2013/04/19 16:48:18
This clones the exact logic we used in AudioHandle
dgreid
2013/04/22 16:23:26
I think that is safer. It will most likely not ha
jennyz
2013/04/23 17:22:55
Will changed in the next cl.
|
| +} |
| + |
| +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); |
| + |
| + if (!mute_on) { |
| + if (output_volume_ <= kMuteThresholdPercent) { |
|
dgreid
2013/04/19 04:20:18
If SetOutputVolumePercent(50) is called when curre
jennyz
2013/04/19 16:48:18
It could if the audio is muted when user sets it t
dgreid
2013/04/22 16:23:26
I was less worried about the user noticing and mor
jennyz
2013/04/23 17:22:55
Shouldn't happen after the change made in SetOutpu
|
| + // Avoid the situation when sound has been unmuted, but the volume |
| + // is set to a very low value, so user still can't hear any sound. |
| + SetOutputVolumeInternal(kDefaultUnmuteVolumePercent); |
| + } |
| + } |
| +} |
| + |
| +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( |
| + scoped_refptr<AudioPrefHandler> audio_pref_handler) |
| + : audio_pref_handler_(audio_pref_handler), |
| + weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| + 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); |
| + DCHECK(audio_pref_handler_.get()); |
| + audio_pref_handler_->AddAudioPrefObserver(this); |
| + SetupInitialAudioState(); |
| +} |
| + |
| +CrasAudioHandler::~CrasAudioHandler() { |
| + chromeos::DBusThreadManager::Get()->GetCrasAudioClient()-> |
| + RemoveObserver(this); |
| + audio_pref_handler_->RemoveAudioPrefObserver(this); |
| + audio_pref_handler_ = NULL; |
| +} |
| + |
| +void CrasAudioHandler::AudioClientRestarted() { |
| + SetupInitialAudioState(); |
| +} |
| + |
| +void CrasAudioHandler::OutputVolumeChanged(int volume) { |
| + if (output_volume_ == volume) |
| + return; |
| + |
| + output_volume_ = volume; |
| + audio_pref_handler_->SetOutputVolumeValue(output_volume_); |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged()); |
| +} |
| + |
| +void CrasAudioHandler::OutputMuteChanged(bool mute_on) { |
| + if (output_mute_on_ == mute_on) |
| + return; |
| + |
| + output_mute_on_ = mute_on; |
| + audio_pref_handler_->SetOutputMuteValue(mute_on); |
| + FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputMuteChanged()); |
| +} |
| + |
| +void CrasAudioHandler::InputMuteChanged(bool mute_on) { |
| + if (input_mute_on_ == mute_on) |
| + return; |
| + |
| + 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::OnAudioPolicyPrefChanged() { |
| + ApplyAudioPolicy(); |
| +} |
| + |
| +void CrasAudioHandler::SetupInitialAudioState() { |
| + ApplyAudioPolicy(); |
| + |
| + // Set the initial audio state to the ones read from audio prefs. |
| + output_mute_on_ = audio_pref_handler_->GetOutputMuteValue(); |
| + output_volume_ = audio_pref_handler_->GetOutputVolumeValue(); |
| + SetOutputMute(output_mute_on_); |
| + SetOutputVolumeInternal(output_volume_); |
|
dgreid
2013/04/19 04:20:18
similar comment to above about the order of this.
jennyz
2013/04/19 16:48:18
Same as we discussed in previous comment.
jennyz
2013/04/23 17:22:55
Changed in the next cl.
|
| + |
| + // Get the initial audio data. |
| + GetNodes(); |
| +} |
| + |
| +void CrasAudioHandler::ApplyAudioPolicy() { |
| + output_mute_locked_ = false; |
| + if (!audio_pref_handler_->GetAudioOutputAllowedValue()) { |
| + SetOutputMute(true); |
| + output_mute_locked_ = true; |
| + } |
| + |
| + input_mute_locked_ = false; |
| + if (audio_pref_handler_->GetAudioCaptureAllowedValue()) { |
| + 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 |