Skip to content

Commit

Permalink
Switch Audio Preferences to per device.
Browse files Browse the repository at this point in the history
Currently Chrome stores one global audio volume pref; if a user switches devices, this value remains the same. Change this so that we remember what volume (and mute setting) a user switched to when on a particular device, so when we switch to that device, we can set the volume/mute setting back to it again.

R=brettw@chromium.org, hshi@chromium.org, stevenjb@chromium.org
BUG=175798
TEST=Switched between speakers and USB headphones to verify that audio settings were rememebered and switched to correctly.

Review URL: https://codereview.chromium.org/14801002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198011 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rkc@chromium.org committed May 2, 2013
1 parent 983efa8 commit 36221c6
Show file tree
Hide file tree
Showing 14 changed files with 369 additions and 29 deletions.
192 changes: 192 additions & 0 deletions chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// 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 "chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h"

#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 "base/strings/string_number_conversions.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "chromeos/audio/cras_audio_handler.h"

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;

} // namespace

double AudioDevicesPrefHandlerImpl::GetOutputVolumeValue() {
if (!CrasAudioHandler::IsInitialized())
return kDefaultVolumePercent;

UpdateDevicesVolumePref();
std::string active_device_id = base::Uint64ToString(
CrasAudioHandler::Get()->GetActiveOutputNode());
if (!device_volume_settings_->HasKey(active_device_id))
MigrateDeviceVolumeSettings(active_device_id);
double volume = kDefaultVolumePercent;
device_volume_settings_->GetDouble(active_device_id, &volume);
return volume;
}

void AudioDevicesPrefHandlerImpl::SetOutputVolumeValue(double volume_percent) {
std::string active_device_id = base::Uint64ToString(
CrasAudioHandler::Get()->GetActiveOutputNode());
if (volume_percent > 100.0)
volume_percent = 100.0;
if (volume_percent < 0.0)
volume_percent = 0.0;
device_volume_settings_->SetDouble(active_device_id, volume_percent);
SaveDevicesVolumePref();
}

bool AudioDevicesPrefHandlerImpl::GetOutputMuteValue() {
if (!CrasAudioHandler::IsInitialized())
return false;

UpdateDevicesVolumePref();
std::string active_device_id = base::Uint64ToString(
CrasAudioHandler::Get()->GetActiveOutputNode());
if (!device_mute_settings_->HasKey(active_device_id))
MigrateDeviceMuteSettings(active_device_id);
int mute = kPrefMuteOff;
device_mute_settings_->GetInteger(active_device_id, &mute);
return (mute == kPrefMuteOn);
}

void AudioDevicesPrefHandlerImpl::SetOutputMuteValue(bool mute) {
std::string active_device_id = base::Uint64ToString(
CrasAudioHandler::Get()->GetActiveOutputNode());
device_mute_settings_->SetBoolean(active_device_id,
mute ? kPrefMuteOn : kPrefMuteOff);
SaveDevicesVolumePref();
}

bool AudioDevicesPrefHandlerImpl::GetAudioCaptureAllowedValue() {
return local_state_->GetBoolean(prefs::kAudioCaptureAllowed);
}

bool AudioDevicesPrefHandlerImpl::GetAudioOutputAllowedValue() {
return local_state_->GetBoolean(prefs::kAudioOutputAllowed);
}

void AudioDevicesPrefHandlerImpl::AddAudioPrefObserver(
AudioPrefObserver* observer) {
observers_.AddObserver(observer);
}

void AudioDevicesPrefHandlerImpl::RemoveAudioPrefObserver(
AudioPrefObserver* observer) {
observers_.RemoveObserver(observer);
}

AudioDevicesPrefHandlerImpl::AudioDevicesPrefHandlerImpl(
PrefService* local_state)
: device_mute_settings_(new base::DictionaryValue()),
device_volume_settings_(new base::DictionaryValue()),
local_state_(local_state) {
InitializePrefObservers();

UpdateDevicesMutePref();
UpdateDevicesVolumePref();
}

AudioDevicesPrefHandlerImpl::~AudioDevicesPrefHandlerImpl() {
};

void AudioDevicesPrefHandlerImpl::InitializePrefObservers() {
pref_change_registrar_.Init(local_state_);
base::Closure callback =
base::Bind(&AudioDevicesPrefHandlerImpl::NotifyAudioPolicyChange,
base::Unretained(this));
pref_change_registrar_.Add(prefs::kAudioOutputAllowed, callback);
pref_change_registrar_.Add(prefs::kAudioCaptureAllowed, callback);
}

void AudioDevicesPrefHandlerImpl::UpdateDevicesMutePref() {
const base::DictionaryValue* mute_prefs =
local_state_->GetDictionary(prefs::kAudioDevicesMute);
if (mute_prefs)
device_mute_settings_.reset(mute_prefs->DeepCopy());
}

void AudioDevicesPrefHandlerImpl::SaveDevicesMutePref() {
DictionaryPrefUpdate dict_update(local_state_, prefs::kAudioDevicesMute);
base::DictionaryValue::Iterator it(*device_mute_settings_);
while (!it.IsAtEnd()) {
int mute = kPrefMuteOff;
it.value().GetAsInteger(&mute);
dict_update->Set(it.key(), new base::FundamentalValue(mute));
it.Advance();
}
}

void AudioDevicesPrefHandlerImpl::UpdateDevicesVolumePref() {
const base::DictionaryValue* volume_prefs =
local_state_->GetDictionary(prefs::kAudioDevicesVolumePercent);
if (volume_prefs)
device_volume_settings_.reset(volume_prefs->DeepCopy());
}

void AudioDevicesPrefHandlerImpl::SaveDevicesVolumePref() {
DictionaryPrefUpdate dict_update(local_state_,
prefs::kAudioDevicesVolumePercent);
base::DictionaryValue::Iterator it(*device_volume_settings_);
while (!it.IsAtEnd()) {
double volume = kDefaultVolumePercent;
it.value().GetAsDouble(&volume);
dict_update->Set(it.key(), new base::FundamentalValue(volume));
it.Advance();
}
}

void AudioDevicesPrefHandlerImpl::MigrateDeviceMuteSettings(
std::string active_device) {
int old_mute = local_state_->GetInteger(prefs::kAudioMute);
device_mute_settings_->SetInteger(active_device, old_mute);
SaveDevicesMutePref();
}

void AudioDevicesPrefHandlerImpl::MigrateDeviceVolumeSettings(
std::string active_device) {
double old_volume = local_state_->GetDouble(prefs::kAudioVolumePercent);
device_volume_settings_->SetDouble(active_device, old_volume);
SaveDevicesVolumePref();
}

void AudioDevicesPrefHandlerImpl::NotifyAudioPolicyChange() {
FOR_EACH_OBSERVER(AudioPrefObserver,
observers_,
OnAudioPolicyPrefChanged());
}

// static
void AudioDevicesPrefHandlerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(prefs::kAudioDevicesVolumePercent);
registry->RegisterDictionaryPref(prefs::kAudioDevicesMute);

// TODO(jennyz,rkc): Move the rest of the preferences registered by
// AudioPrefHandlerImpl::RegisterPrefs here once we remove the old audio
// handler code.
}

// static
AudioDevicesPrefHandler* AudioDevicesPrefHandler::Create(
PrefService* local_state) {
return new AudioDevicesPrefHandlerImpl(local_state);
}

} // namespace chromeos
74 changes: 74 additions & 0 deletions chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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.

#ifndef CHROME_BROWSER_CHROMEOS_AUDIO_AUDIO_DEVICES_PREF_HANDLER_IMPL_H_
#define CHROME_BROWSER_CHROMEOS_AUDIO_AUDIO_DEVICES_PREF_HANDLER_IMPL_H_

#include "base/observer_list.h"
#include "base/prefs/pref_change_registrar.h"
#include "base/values.h"
#include "chromeos/audio/audio_devices_pref_handler.h"

class PrefRegistrySimple;
class PrefService;

namespace chromeos {

// Class which implements AudioDevicesPrefHandler interface and register audio
// preferences as well.
class AudioDevicesPrefHandlerImpl : public AudioDevicesPrefHandler {
public:
explicit AudioDevicesPrefHandlerImpl(PrefService* local_state);

// Overridden from AudioDevicesPrefHandler.
virtual double GetOutputVolumeValue() OVERRIDE;
virtual bool GetOutputMuteValue() OVERRIDE;
virtual void SetOutputVolumeValue(double volume_percent) OVERRIDE;
virtual void SetOutputMuteValue(bool mute_on) OVERRIDE;
virtual bool GetAudioCaptureAllowedValue() OVERRIDE;
virtual bool GetAudioOutputAllowedValue() OVERRIDE;
virtual void AddAudioPrefObserver(AudioPrefObserver* observer) OVERRIDE;
virtual void RemoveAudioPrefObserver(AudioPrefObserver* observer) OVERRIDE;

// Registers volume and mute preferences.
static void RegisterPrefs(PrefRegistrySimple* registry);

protected:
virtual ~AudioDevicesPrefHandlerImpl();

private:
// Initializes the observers for the policy prefs.
void InitializePrefObservers();

// Update and save methods for the mute preferences for all devices.
void UpdateDevicesMutePref();
void SaveDevicesMutePref();

// Update and save methods for the volume preferences for all devices.
void UpdateDevicesVolumePref();
void SaveDevicesVolumePref();

// Methods to migrate the mute and volume settings for a device from the
// previous global pref value to the new per device pref value for the
// current active device. If a previous global setting doesn't exist, we'll
// use default values of mute = off and volume = 75%.
void MigrateDeviceMuteSettings(std::string active_device);
void MigrateDeviceVolumeSettings(std::string active_device);

// Notifies the AudioPrefObserver for audio policy pref changes.
void NotifyAudioPolicyChange();

scoped_ptr<base::DictionaryValue> device_mute_settings_;
scoped_ptr<base::DictionaryValue> device_volume_settings_;

PrefService* local_state_; // not owned
PrefChangeRegistrar pref_change_registrar_;
ObserverList<AudioPrefObserver> observers_;

DISALLOW_COPY_AND_ASSIGN(AudioDevicesPrefHandlerImpl);
};

} // namespace chromeos

#endif // CHROME_BROWSER_CHROMEOS_AUDIO_AUDIO_DEVICES_PREF_HANDLER_IMPL_H_
2 changes: 2 additions & 0 deletions chrome/browser/chromeos/audio/audio_pref_handler_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class PrefService;

namespace chromeos {

// TODO(jennyz,rkc): This class will be removed once we remove the old Audio
// Handler code.
// Class which implements AudioPrefHandler interface and register audio
// preferences as well.
class AudioPrefHandlerImpl : public AudioPrefHandler {
Expand Down
3 changes: 2 additions & 1 deletion chrome/browser/chromeos/chrome_browser_main_chromeos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
#include "chromeos/audio/audio_devices_pref_handler.h"
#include "chromeos/audio/audio_pref_handler.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "chromeos/audio/cras_audio_switch_handler.h"
Expand Down Expand Up @@ -485,7 +486,7 @@ void ChromeBrowserMainPartsChromeos::PreMainMessageLoopRun() {
CrasAudioSwitchHandler::Initialize();
if (UseNewAudioHandler()) {
CrasAudioHandler::Initialize(
AudioPrefHandler::Create(g_browser_process->local_state()));
AudioDevicesPrefHandler::Create(g_browser_process->local_state()));
} else {
AudioHandler::Initialize(
AudioPrefHandler::Create(g_browser_process->local_state()));
Expand Down
2 changes: 2 additions & 0 deletions chrome/browser/prefs/browser_prefs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h"
#include "chrome/browser/chromeos/audio/audio_handler.h"
#include "chrome/browser/chromeos/audio/audio_pref_handler_impl.h"
#include "chrome/browser/chromeos/customization_document.h"
Expand Down Expand Up @@ -241,6 +242,7 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
#endif

#if defined(OS_CHROMEOS)
chromeos::AudioDevicesPrefHandlerImpl::RegisterPrefs(registry);
chromeos::AudioPrefHandlerImpl::RegisterPrefs(registry);
chromeos::DataPromoNotification::RegisterPrefs(registry);
chromeos::DeviceOAuth2TokenService::RegisterPrefs(registry);
Expand Down
2 changes: 2 additions & 0 deletions chrome/chrome_browser_chromeos.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@
'browser/chromeos/attestation/attestation_ca_client.h',
'browser/chromeos/attestation/attestation_policy_observer.cc',
'browser/chromeos/attestation/attestation_policy_observer.h',
'browser/chromeos/audio/audio_devices_pref_handler_impl.cc',
'browser/chromeos/audio/audio_devices_pref_handler_impl.h',
'browser/chromeos/audio/audio_handler.cc',
'browser/chromeos/audio/audio_handler.h',
'browser/chromeos/audio/audio_pref_handler_impl.cc',
Expand Down
17 changes: 15 additions & 2 deletions chrome/common/pref_names.cc
Original file line number Diff line number Diff line change
Expand Up @@ -541,12 +541,25 @@ const char kDefaultAppsInstallState[] = "default_apps_install_state";
const char kHideWebStoreIcon[] = "hide_web_store_icon";

#if defined(OS_CHROMEOS)
// A dictionary pref to hold the mute setting for all the currently known
// audio devices.
const char kAudioDevicesMute[] = "settings.audio.devices.mute";

// A dictionary pref storing the volume settings for all the currently known
// audio devices.
const char kAudioDevicesVolumePercent[] =
"settings.audio.devices.volume_percent";

// An integer pref to initially mute volume if 1. This pref is ignored if
// |kAudioOutputAllowed| is set to false, but its value is preserved, therefore
// when the policy is lifted the original mute state is restored.
// when the policy is lifted the original mute state is restored. This setting
// is here only for migration purposes now. It is being replaced by the
// |kAudioDevicesMute| setting.
const char kAudioMute[] = "settings.audio.mute";

// A double pref storing the user-requested volume.
// A double pref storing the user-requested volume. This setting is here only
// for migration purposes now. It is being replaced by the
// |kAudioDevicesVolumePercent| setting.
const char kAudioVolumePercent[] = "settings.audio.volume_percent";

// A boolean pref set to true if touchpad tap-to-click is enabled.
Expand Down
2 changes: 2 additions & 0 deletions chrome/common/pref_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ extern const char kNetworkPredictionEnabled[];
extern const char kDefaultAppsInstallState[];
extern const char kHideWebStoreIcon[];
#if defined(OS_CHROMEOS)
extern const char kAudioDevicesMute[];
extern const char kAudioDevicesVolumePercent[];
extern const char kAudioMute[];
extern const char kAudioVolumePercent[];
extern const char kTapToClickEnabled[];
Expand Down
Loading

0 comments on commit 36221c6

Please sign in to comment.