Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(965)

Side by Side Diff: chrome/browser/chromeos/audio_mixer_alsa.cc

Issue 6118006: Save/Restore ALSA volume/mute (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/chrome/browser/chromeos
Patch Set: cleaned Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/audio_mixer_alsa.h" 5 #include "chrome/browser/chromeos/audio_mixer_alsa.h"
6 6
7 #include <alsa/asoundlib.h> 7 #include <alsa/asoundlib.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/task.h" 10 #include "base/task.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/browser_thread.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/common/pref_names.h"
11 15
12 namespace chromeos { 16 namespace chromeos {
13 17
14 // Connect to the ALSA mixer using their simple element API. Init is performed 18 // Connect to the ALSA mixer using their simple element API. Init is performed
15 // asynchronously on the worker thread. 19 // asynchronously on the worker thread.
16 // 20 //
17 // To get a wider range and finer control over volume levels, first the Master 21 // To get a wider range and finer control over volume levels, first the Master
18 // level is set, then if the PCM element exists, the total level is refined by 22 // level is set, then if the PCM element exists, the total level is refined by
19 // adjusting that as well. If the PCM element has more volume steps, it allows 23 // adjusting that as well. If the PCM element has more volume steps, it allows
20 // for finer granularity in the total volume. 24 // for finer granularity in the total volume.
21 25
22 // TODO(davej): Serialize volume/mute to preserve settings when restarting.
23
24 typedef long alsa_long_t; // 'long' is required for ALSA API calls. 26 typedef long alsa_long_t; // 'long' is required for ALSA API calls.
25 27
26 namespace { 28 namespace {
27 29
28 const char* kMasterVolume = "Master"; 30 const char* kMasterVolume = "Master";
29 const char* kPCMVolume = "PCM"; 31 const char* kPCMVolume = "PCM";
30 const double kDefaultMinVolume = -90.0; 32 const double kDefaultMinVolume = -90.0;
31 const double kDefaultMaxVolume = 0.0; 33 const double kDefaultMaxVolume = 0.0;
34 const double kPrefVolumeNotSet = -999.0;
32 35
33 } // namespace 36 } // namespace
34 37
35 AudioMixerAlsa::AudioMixerAlsa() 38 AudioMixerAlsa::AudioMixerAlsa()
36 : min_volume_(kDefaultMinVolume), 39 : min_volume_(kDefaultMinVolume),
37 max_volume_(kDefaultMaxVolume), 40 max_volume_(kDefaultMaxVolume),
38 save_volume_(0), 41 save_volume_(0),
39 mixer_state_(UNINITIALIZED), 42 mixer_state_(UNINITIALIZED),
40 alsa_mixer_(NULL), 43 alsa_mixer_(NULL),
41 elem_master_(NULL), 44 elem_master_(NULL),
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 if (mixer_state_ != READY) 86 if (mixer_state_ != READY)
84 return false; 87 return false;
85 if (vol_min) 88 if (vol_min)
86 *vol_min = min_volume_; 89 *vol_min = min_volume_;
87 if (vol_max) 90 if (vol_max)
88 *vol_max = max_volume_; 91 *vol_max = max_volume_;
89 return true; 92 return true;
90 } 93 }
91 94
92 void AudioMixerAlsa::SetVolumeDb(double vol_db) { 95 void AudioMixerAlsa::SetVolumeDb(double vol_db) {
93 AutoLock lock(mixer_state_lock_); 96 {
94 if (mixer_state_ != READY) 97 AutoLock lock(mixer_state_lock_);
95 return; 98 if (mixer_state_ != READY)
96 DoSetVolumeDb_Locked(vol_db); 99 return;
100 DoSetVolumeDb_Locked(vol_db);
101 }
102 SaveVolume(vol_db);
97 } 103 }
98 104
99 bool AudioMixerAlsa::IsMute() const { 105 bool AudioMixerAlsa::IsMute() const {
100 AutoLock lock(mixer_state_lock_); 106 AutoLock lock(mixer_state_lock_);
101 if (mixer_state_ != READY) 107 if (mixer_state_ != READY)
102 return false; 108 return false;
103 return GetElementMuted_Locked(elem_master_); 109 return GetElementMuted_Locked(elem_master_);
104 } 110 }
105 111
106 void AudioMixerAlsa::SetMute(bool mute) { 112 void AudioMixerAlsa::SetMute(bool mute) {
107 AutoLock lock(mixer_state_lock_); 113 {
108 if (mixer_state_ != READY) 114 AutoLock lock(mixer_state_lock_);
109 return;
110 115
111 // Set volume to minimum on mute, since switching the element off does not 116 if (mixer_state_ != READY)
112 // always mute as it should. 117 return;
113 118
114 // TODO(davej): Setting volume to minimum can be removed once switching the 119 // Set volume to minimum on mute, since switching the element off does not
115 // element off can be guaranteed to work. 120 // always mute as it should.
116 121
117 bool old_value = GetElementMuted_Locked(elem_master_); 122 // TODO(davej): Remove save_volume_ and setting volume to minimum if
123 // switching the element off can be guaranteed to mute it.
118 124
119 if (old_value != mute) { 125 bool old_value = GetElementMuted_Locked(elem_master_);
120 if (mute) { 126
121 save_volume_ = DoGetVolumeDb_Locked(); 127 if (old_value != mute) {
122 DoSetVolumeDb_Locked(min_volume_); 128 if (mute) {
123 } else { 129 save_volume_ = DoGetVolumeDb_Locked();
124 DoSetVolumeDb_Locked(save_volume_); 130 DoSetVolumeDb_Locked(min_volume_);
131 } else {
132 DoSetVolumeDb_Locked(save_volume_);
133 }
125 } 134 }
135
136 SetElementMuted_Locked(elem_master_, mute);
137 if (elem_pcm_)
138 SetElementMuted_Locked(elem_pcm_, mute);
126 } 139 }
127 140 SaveMute(mute);
128 SetElementMuted_Locked(elem_master_, mute);
129 if (elem_pcm_)
130 SetElementMuted_Locked(elem_pcm_, mute);
131 } 141 }
132 142
133 AudioMixer::State AudioMixerAlsa::GetState() const { 143 AudioMixer::State AudioMixerAlsa::GetState() const {
134 AutoLock lock(mixer_state_lock_); 144 AutoLock lock(mixer_state_lock_);
135 // If we think it's ready, verify it is actually so. 145 // If we think it's ready, verify it is actually so.
136 if ((mixer_state_ == READY) && (alsa_mixer_ == NULL)) 146 if ((mixer_state_ == READY) && (alsa_mixer_ == NULL))
137 mixer_state_ = IN_ERROR; 147 mixer_state_ = IN_ERROR;
138 return mixer_state_; 148 return mixer_state_;
139 } 149 }
140 150
141 //////////////////////////////////////////////////////////////////////////////// 151 ////////////////////////////////////////////////////////////////////////////////
142 // Private functions follow 152 // Private functions follow
143 153
144 void AudioMixerAlsa::DoInit(InitDoneCallback* callback) { 154 void AudioMixerAlsa::DoInit(InitDoneCallback* callback) {
145 bool success = InitializeAlsaMixer(); 155 bool success = InitializeAlsaMixer();
146 156
157 if (success) {
158 BrowserThread::PostTask(
159 BrowserThread::UI, FROM_HERE,
160 NewRunnableMethod(this, &AudioMixerAlsa::RestoreVolumeMute));
161 }
162
147 if (callback) { 163 if (callback) {
148 callback->Run(success); 164 callback->Run(success);
149 delete callback; 165 delete callback;
150 } 166 }
151 } 167 }
152 168
153 bool AudioMixerAlsa::InitThread() { 169 bool AudioMixerAlsa::InitThread() {
154 AutoLock lock(mixer_state_lock_); 170 AutoLock lock(mixer_state_lock_);
155 171
156 if (mixer_state_ != UNINITIALIZED) 172 if (mixer_state_ != UNINITIALIZED)
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 250
235 void AudioMixerAlsa::FreeAlsaMixer() { 251 void AudioMixerAlsa::FreeAlsaMixer() {
236 AutoLock lock(mixer_state_lock_); 252 AutoLock lock(mixer_state_lock_);
237 mixer_state_ = SHUTTING_DOWN; 253 mixer_state_ = SHUTTING_DOWN;
238 if (alsa_mixer_) { 254 if (alsa_mixer_) {
239 snd_mixer_close(alsa_mixer_); 255 snd_mixer_close(alsa_mixer_);
240 alsa_mixer_ = NULL; 256 alsa_mixer_ = NULL;
241 } 257 }
242 } 258 }
243 259
260 void AudioMixerAlsa::DoSetVolumeMute(double volume, bool mute) {
261 AutoLock lock(mixer_state_lock_);
262 if (mixer_state_ != READY)
263 return;
264
265 VLOG(1) << "Setting volume to " << volume << "and mute to " << mute;
266 if (mute) {
267 save_volume_ = volume;
268 DoSetVolumeDb_Locked(min_volume_);
269 } else {
270 DoSetVolumeDb_Locked(volume);
271 }
272
273 SetElementMuted_Locked(elem_master_, mute);
274 if (elem_pcm_)
275 SetElementMuted_Locked(elem_pcm_, mute);
276 }
277
244 double AudioMixerAlsa::DoGetVolumeDb_Locked() const { 278 double AudioMixerAlsa::DoGetVolumeDb_Locked() const {
245 double vol_total = 0.0; 279 double vol_total = 0.0;
246 GetElementVolume_Locked(elem_master_, &vol_total); 280 GetElementVolume_Locked(elem_master_, &vol_total);
247 281
248 double vol_pcm = 0.0; 282 double vol_pcm = 0.0;
249 if (elem_pcm_ && (GetElementVolume_Locked(elem_pcm_, &vol_pcm))) 283 if (elem_pcm_ && (GetElementVolume_Locked(elem_pcm_, &vol_pcm)))
250 vol_total += vol_pcm; 284 vol_total += vol_pcm;
251 285
252 return vol_total; 286 return vol_total;
253 } 287 }
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 } 389 }
356 390
357 void AudioMixerAlsa::SetElementMuted_Locked(snd_mixer_elem_t* elem, bool mute) { 391 void AudioMixerAlsa::SetElementMuted_Locked(snd_mixer_elem_t* elem, bool mute) {
358 int enabled = mute ? 0 : 1; 392 int enabled = mute ? 0 : 1;
359 snd_mixer_selem_set_playback_switch_all(elem, enabled); 393 snd_mixer_selem_set_playback_switch_all(elem, enabled);
360 394
361 VLOG(1) << "Set playback switch " << snd_mixer_selem_get_name(elem) 395 VLOG(1) << "Set playback switch " << snd_mixer_selem_get_name(elem)
362 << " to " << enabled; 396 << " to " << enabled;
363 } 397 }
364 398
399 void AudioMixerAlsa::RestoreVolumeMute() {
400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
401 if (!g_browser_process)
402 return;
403
404 PrefService* local_state = g_browser_process->local_state();
scherkus (not reviewing) 2011/01/13 00:54:52 take a look at PrefMember which wraps up all these
davejcool 2011/01/13 21:31:14 Thanks for the PrefMember pointer! This greatly s
405 if (!local_state) {
406 LOG(ERROR) << "Cannot get local_state for prefs, not initializing volume";
407 return;
408 }
409
410 if (!local_state->FindPreference(prefs::kAudioVolume)) {
411 local_state->RegisterRealPref(prefs::kAudioVolume, kPrefVolumeNotSet);
412 local_state->RegisterBooleanPref(prefs::kAudioMute, false);
413 }
414
415 DCHECK(local_state->FindPreference(prefs::kAudioVolume));
416 double pref_volume = local_state->GetReal(prefs::kAudioVolume);
417
418 if (pref_volume != kPrefVolumeNotSet) {
419 DCHECK(local_state->FindPreference(prefs::kAudioMute));
420 bool pref_mute = local_state->GetBoolean(prefs::kAudioMute);
421
422 thread_->message_loop()->PostTask(FROM_HERE,
423 NewRunnableMethod(this, &AudioMixerAlsa::DoSetVolumeMute,
424 pref_volume, pref_mute));
425 }
426 }
427
428 void AudioMixerAlsa::SaveVolume(double volume) {
429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
430 if (!g_browser_process)
431 return;
432
433 PrefService* local_state = g_browser_process->local_state();
434 if (!local_state) {
435 LOG(ERROR) << "Cannot get local_state to store volume in prefs";
436 return;
437 }
438 DCHECK(local_state->FindPreference(prefs::kAudioVolume));
439 local_state->SetReal(prefs::kAudioVolume, volume);
440 }
441
442 void AudioMixerAlsa::SaveMute(bool mute) {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
444 if (!g_browser_process)
445 return;
446
447 PrefService* local_state = g_browser_process->local_state();
448 if (!local_state) {
zhurunz 2011/01/13 00:19:25 Could we add a util function to get local_state so
davejcool 2011/01/13 21:31:14 By using the PrefMember class, I was able to encap
449 LOG(ERROR) << "Cannot get local_state to store mute in prefs";
450 return;
451 }
452 DCHECK(local_state->FindPreference(prefs::kAudioMute));
453 local_state->SetBoolean(prefs::kAudioMute, mute);
454 }
455
365 } // namespace chromeos 456 } // namespace chromeos
366 457
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698