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.
4
5#include "chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/logging.h"
12#include "base/prefs/pref_registry_simple.h"
13#include "base/prefs/pref_service.h"
14#include "base/prefs/scoped_user_pref_update.h"
15#include "base/strings/string_number_conversions.h"
16#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/common/pref_names.h"
18#include "chromeos/audio/audio_device.h"
19
20namespace {
21
22const double kDefaultOutputVolume = 75.0;
23const double kDefaultHDMIOutputVolume = 100.0;
24
25// Values used for muted preference.
26const int kPrefMuteOff = 0;
27const int kPrefMuteOn = 1;
28
29// Gets the device id string for storing audio preference. The format of
30// device string is a string consisting of 3 parts.
31// |device_name| : |integer from lower 32 bit of device id| :
32// |0(output device) or 1(input device)|
33// If an audio device has both integrated input and output devices, the first 2
34// parts of the string could be identical, only the last part will differentiate
35// them.
36std::string GetDeviceIdString(const chromeos::AudioDevice& device) {
37  return device.device_name + " : " +
38         base::Uint64ToString(device.id & static_cast<uint64>(0xffffffff)) +
39         " : " + (device.is_input ? "1" : "0");
40}
41
42}  // namespace
43
44namespace chromeos {
45
46double AudioDevicesPrefHandlerImpl::GetOutputVolumeValue(
47    const AudioDevice* device) {
48  if (!device)
49    return kDefaultOutputVolume;
50  else
51    return GetVolumeGainPrefValue(*device);
52}
53
54double AudioDevicesPrefHandlerImpl::GetInputGainValue(
55    const AudioDevice* device) {
56  DCHECK(device);
57  return GetVolumeGainPrefValue(*device);
58}
59
60void AudioDevicesPrefHandlerImpl::SetVolumeGainValue(
61    const AudioDevice& device, double value) {
62  device_volume_settings_->SetDouble(GetDeviceIdString(device), value);
63
64  SaveDevicesVolumePref();
65}
66
67bool AudioDevicesPrefHandlerImpl::GetMuteValue(const AudioDevice& device) {
68  UpdateDevicesMutePref();
69
70  std::string device_id_str = GetDeviceIdString(device);
71  if (!device_mute_settings_->HasKey(device_id_str))
72    MigrateDeviceMuteSettings(device_id_str);
73
74  int mute = kPrefMuteOff;
75  device_mute_settings_->GetInteger(device_id_str, &mute);
76
77  return (mute == kPrefMuteOn);
78}
79
80void AudioDevicesPrefHandlerImpl::SetMuteValue(const AudioDevice& device,
81                                               bool mute) {
82  device_mute_settings_->SetInteger(GetDeviceIdString(device),
83                                    mute ? kPrefMuteOn : kPrefMuteOff);
84  SaveDevicesMutePref();
85}
86
87
88bool AudioDevicesPrefHandlerImpl::GetAudioCaptureAllowedValue() {
89  return local_state_->GetBoolean(prefs::kAudioCaptureAllowed);
90}
91
92bool AudioDevicesPrefHandlerImpl::GetAudioOutputAllowedValue() {
93  return local_state_->GetBoolean(prefs::kAudioOutputAllowed);
94}
95
96void AudioDevicesPrefHandlerImpl::AddAudioPrefObserver(
97    AudioPrefObserver* observer) {
98  observers_.AddObserver(observer);
99}
100
101void AudioDevicesPrefHandlerImpl::RemoveAudioPrefObserver(
102    AudioPrefObserver* observer) {
103  observers_.RemoveObserver(observer);
104}
105
106double AudioDevicesPrefHandlerImpl::GetVolumeGainPrefValue(
107    const AudioDevice& device) {
108  UpdateDevicesVolumePref();
109
110  std::string device_id_str = GetDeviceIdString(device);
111  if (!device_volume_settings_->HasKey(device_id_str))
112    MigrateDeviceVolumeSettings(device_id_str);
113
114  // TODO(jennyz, rkc): Return a meaningful input gain default value, when
115  // cras has added support for normalizing input gain range.
116  double value = device.is_input ?
117      0.0 : GetDeviceDefaultOutputVolume(device);
118  device_volume_settings_->GetDouble(device_id_str, &value);
119
120  return value;
121}
122
123double AudioDevicesPrefHandlerImpl::GetDeviceDefaultOutputVolume(
124    const AudioDevice& device) {
125  if (device.type == AUDIO_TYPE_HDMI)
126    return kDefaultHDMIOutputVolume;
127  else
128    return kDefaultOutputVolume;
129}
130
131AudioDevicesPrefHandlerImpl::AudioDevicesPrefHandlerImpl(
132    PrefService* local_state)
133    : device_mute_settings_(new base::DictionaryValue()),
134      device_volume_settings_(new base::DictionaryValue()),
135      local_state_(local_state) {
136  InitializePrefObservers();
137
138  UpdateDevicesMutePref();
139  UpdateDevicesVolumePref();
140}
141
142AudioDevicesPrefHandlerImpl::~AudioDevicesPrefHandlerImpl() {
143};
144
145void AudioDevicesPrefHandlerImpl::InitializePrefObservers() {
146  pref_change_registrar_.Init(local_state_);
147  base::Closure callback =
148      base::Bind(&AudioDevicesPrefHandlerImpl::NotifyAudioPolicyChange,
149                 base::Unretained(this));
150  pref_change_registrar_.Add(prefs::kAudioOutputAllowed, callback);
151  pref_change_registrar_.Add(prefs::kAudioCaptureAllowed, callback);
152}
153
154void AudioDevicesPrefHandlerImpl::UpdateDevicesMutePref() {
155  const base::DictionaryValue* mute_prefs =
156      local_state_->GetDictionary(prefs::kAudioDevicesMute);
157  if (mute_prefs)
158    device_mute_settings_.reset(mute_prefs->DeepCopy());
159}
160
161void AudioDevicesPrefHandlerImpl::SaveDevicesMutePref() {
162  DictionaryPrefUpdate dict_update(local_state_, prefs::kAudioDevicesMute);
163  base::DictionaryValue::Iterator it(*device_mute_settings_);
164  while (!it.IsAtEnd()) {
165    int mute = kPrefMuteOff;
166    it.value().GetAsInteger(&mute);
167    dict_update->SetInteger(it.key(), mute);
168    it.Advance();
169  }
170}
171
172void AudioDevicesPrefHandlerImpl::UpdateDevicesVolumePref() {
173  const base::DictionaryValue* volume_prefs =
174      local_state_->GetDictionary(prefs::kAudioDevicesVolumePercent);
175  if (volume_prefs)
176    device_volume_settings_.reset(volume_prefs->DeepCopy());
177}
178
179void AudioDevicesPrefHandlerImpl::SaveDevicesVolumePref() {
180  DictionaryPrefUpdate dict_update(local_state_,
181                                   prefs::kAudioDevicesVolumePercent);
182  base::DictionaryValue::Iterator it(*device_volume_settings_);
183  while (!it.IsAtEnd()) {
184    double volume = kDefaultOutputVolume;
185    bool success = it.value().GetAsDouble(&volume);
186    DCHECK(success);
187    dict_update->SetDouble(it.key(), volume);
188    it.Advance();
189  }
190}
191
192void AudioDevicesPrefHandlerImpl::MigrateDeviceMuteSettings(
193    std::string active_device) {
194  int old_mute = local_state_->GetInteger(prefs::kAudioMute);
195  device_mute_settings_->SetInteger(active_device, old_mute);
196  SaveDevicesMutePref();
197}
198
199void AudioDevicesPrefHandlerImpl::MigrateDeviceVolumeSettings(
200    std::string active_device) {
201  double old_volume = local_state_->GetDouble(prefs::kAudioVolumePercent);
202  device_volume_settings_->SetDouble(active_device, old_volume);
203  SaveDevicesVolumePref();
204}
205
206void AudioDevicesPrefHandlerImpl::NotifyAudioPolicyChange() {
207  FOR_EACH_OBSERVER(AudioPrefObserver,
208                    observers_,
209                    OnAudioPolicyPrefChanged());
210}
211
212// static
213void AudioDevicesPrefHandlerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
214  registry->RegisterDictionaryPref(prefs::kAudioDevicesVolumePercent);
215  registry->RegisterDictionaryPref(prefs::kAudioDevicesMute);
216
217  // Register the prefs backing the audio muting policies.
218  registry->RegisterBooleanPref(prefs::kAudioOutputAllowed, true);
219  // This pref has moved to the media subsystem but we should verify it is there
220  // before we use it.
221  registry->RegisterBooleanPref(::prefs::kAudioCaptureAllowed, true);
222
223  // Register the legacy audio prefs for migration.
224  registry->RegisterDoublePref(prefs::kAudioVolumePercent,
225                               kDefaultOutputVolume);
226  registry->RegisterIntegerPref(prefs::kAudioMute, kPrefMuteOff);
227}
228
229// static
230AudioDevicesPrefHandler* AudioDevicesPrefHandler::Create(
231    PrefService* local_state) {
232  return new AudioDevicesPrefHandlerImpl(local_state);
233}
234
235}  // namespace chromeos
236