| // Copyright (c) 2012 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 "chrome/browser/chromeos/audio/audio_handler.h" |
| |
| #include <algorithm> |
| #include <cmath> |
| |
| #include "base/logging.h" |
| #include "base/memory/singleton.h" |
| #include "chrome/browser/browser_process.h" |
| #if defined(USE_CRAS) |
| #include "chrome/browser/chromeos/audio/audio_mixer_cras.h" |
| #else |
| #include "chrome/browser/chromeos/audio/audio_mixer_alsa.h" |
| #endif |
| #include "chrome/browser/prefs/pref_service.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "chrome/common/pref_names.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_service.h" |
| |
| using std::max; |
| using std::min; |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| // Default value for the volume pref, as a percent in the range [0.0, 100.0]. |
| const double kDefaultVolumePercent = 75.0; |
| |
| // Values used for muted preference. |
| const int kPrefMuteOff = 0; |
| const int kPrefMuteOn = 1; |
| |
| static AudioHandler* g_audio_handler = NULL; |
| |
| } // namespace |
| |
| // static |
| void AudioHandler::Initialize() { |
| CHECK(!g_audio_handler); |
| #if defined(USE_CRAS) |
| g_audio_handler = new AudioHandler(new AudioMixerCras()); |
| #else |
| g_audio_handler = new AudioHandler(new AudioMixerAlsa()); |
| #endif |
| } |
| |
| // static |
| void AudioHandler::Shutdown() { |
| // We may call Shutdown without calling Initialize, e.g. if we exit early. |
| if (g_audio_handler) { |
| delete g_audio_handler; |
| g_audio_handler = NULL; |
| } |
| } |
| |
| // static |
| void AudioHandler::InitializeForTesting(AudioMixer* mixer) { |
| CHECK(!g_audio_handler); |
| g_audio_handler = new AudioHandler(mixer); |
| } |
| |
| // static |
| AudioHandler* AudioHandler::GetInstance() { |
| VLOG_IF(1, !g_audio_handler) |
| << "AudioHandler::GetInstance() called with NULL global instance."; |
| return g_audio_handler; |
| } |
| |
| // static |
| void AudioHandler::RegisterPrefs(PrefService* local_state) { |
| if (!local_state->FindPreference(prefs::kAudioVolumePercent)) |
| local_state->RegisterDoublePref(prefs::kAudioVolumePercent, |
| kDefaultVolumePercent, |
| PrefService::UNSYNCABLE_PREF); |
| if (!local_state->FindPreference(prefs::kAudioMute)) |
| local_state->RegisterIntegerPref(prefs::kAudioMute, |
| kPrefMuteOff, |
| PrefService::UNSYNCABLE_PREF); |
| |
| // Register the prefs backing the audio muting policies. |
| local_state->RegisterBooleanPref(prefs::kAudioOutputAllowed, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| local_state->RegisterBooleanPref(prefs::kAudioCaptureAllowed, |
| true, |
| PrefService::UNSYNCABLE_PREF); |
| |
| // Register the old decibel-based pref so we can clear it. |
| // TODO(derat): Remove this after R20: http://crbug.com/112039 |
| if (!local_state->FindPreference(prefs::kAudioVolumeDb)) |
| local_state->RegisterDoublePref(prefs::kAudioVolumeDb, |
| 0, |
| PrefService::UNSYNCABLE_PREF); |
| local_state->ClearPref(prefs::kAudioVolumeDb); |
| local_state->UnregisterPreference(prefs::kAudioVolumeDb); |
| } |
| |
| double AudioHandler::GetVolumePercent() { |
| return mixer_->GetVolumePercent(); |
| } |
| |
| void AudioHandler::SetVolumePercent(double volume_percent) { |
| volume_percent = min(max(volume_percent, 0.0), 100.0); |
| if (IsMuted() && volume_percent > 0.0) |
| SetMuted(false); |
| mixer_->SetVolumePercent(volume_percent); |
| local_state_->SetDouble(prefs::kAudioVolumePercent, volume_percent); |
| FOR_EACH_OBSERVER(VolumeObserver, volume_observers_, OnVolumeChanged()); |
| } |
| |
| void AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) { |
| SetVolumePercent(mixer_->GetVolumePercent() + adjust_by_percent); |
| } |
| |
| bool AudioHandler::IsMuted() { |
| return mixer_->IsMuted(); |
| } |
| |
| void AudioHandler::SetMuted(bool mute) { |
| if (!mixer_->IsMuteLocked()) { |
| mixer_->SetMuted(mute); |
| local_state_->SetInteger(prefs::kAudioMute, |
| mute ? kPrefMuteOn : kPrefMuteOff); |
| FOR_EACH_OBSERVER(VolumeObserver, volume_observers_, OnMuteToggled()); |
| } |
| } |
| |
| bool AudioHandler::IsCaptureMuted() { |
| return mixer_->IsCaptureMuted(); |
| } |
| |
| void AudioHandler::SetCaptureMuted(bool mute) { |
| if (!mixer_->IsCaptureMuteLocked()) |
| mixer_->SetCaptureMuted(mute); |
| } |
| |
| void AudioHandler::AddVolumeObserver(VolumeObserver* observer) { |
| volume_observers_.AddObserver(observer); |
| } |
| |
| void AudioHandler::RemoveVolumeObserver(VolumeObserver* observer) { |
| volume_observers_.RemoveObserver(observer); |
| } |
| |
| void AudioHandler::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == chrome::NOTIFICATION_PREF_CHANGED) { |
| std::string* pref_name = content::Details<std::string>(details).ptr(); |
| if (*pref_name == prefs::kAudioOutputAllowed || |
| *pref_name == prefs::kAudioCaptureAllowed) { |
| ApplyAudioPolicy(); |
| } |
| } else { |
| NOTREACHED() << "Unexpected notification type : " << type; |
| } |
| } |
| |
| AudioHandler::AudioHandler(AudioMixer* mixer) |
| : mixer_(mixer), |
| local_state_(g_browser_process->local_state()) { |
| InitializePrefObservers(); |
| ApplyAudioPolicy(); |
| mixer_->SetVolumePercent(local_state_->GetDouble(prefs::kAudioVolumePercent)); |
| mixer_->Init(); |
| } |
| |
| AudioHandler::~AudioHandler() { |
| mixer_.reset(); |
| }; |
| |
| void AudioHandler::InitializePrefObservers() { |
| pref_change_registrar_.Init(local_state_); |
| pref_change_registrar_.Add(prefs::kAudioOutputAllowed, this); |
| pref_change_registrar_.Add(prefs::kAudioCaptureAllowed, this); |
| } |
| |
| void AudioHandler::ApplyAudioPolicy() { |
| mixer_->SetMuteLocked(false); |
| if (local_state_->GetBoolean(prefs::kAudioOutputAllowed)) { |
| mixer_->SetMuted( |
| local_state_->GetInteger(prefs::kAudioMute) == kPrefMuteOn); |
| } else { |
| mixer_->SetMuted(true); |
| mixer_->SetMuteLocked(true); |
| } |
| FOR_EACH_OBSERVER(VolumeObserver, volume_observers_, OnMuteToggled()); |
| mixer_->SetCaptureMuteLocked(false); |
| if (local_state_->GetBoolean(prefs::kAudioCaptureAllowed)) { |
| mixer_->SetCaptureMuted(false); |
| } else { |
| mixer_->SetCaptureMuted(true); |
| mixer_->SetCaptureMuteLocked(true); |
| } |
| } |
| |
| } // namespace chromeos |