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

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

Issue 5859003: Add ALSA support to volume keys (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/chrome/browser/chromeos
Patch Set: more cleanup 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_handler.h" 5 #include "chrome/browser/chromeos/audio_handler.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/singleton.h" 10 #include "base/singleton.h"
11 #include "chrome/browser/chromeos/pulse_audio_mixer.h" 11 #include "chrome/browser/chromeos/audio_mixer_alsa.h"
12 #include "chrome/browser/chromeos/audio_mixer_pulse.h"
13 #include "chrome/browser/browser_thread.h"
12 14
13 namespace chromeos { 15 namespace chromeos {
14 16
15 namespace { 17 namespace {
16 18
17 const double kSilenceDb = -200.0;
18 const double kMinVolumeDb = -90.0; 19 const double kMinVolumeDb = -90.0;
19 // Choosing 6.0dB here instead of 0dB to give user chance to amplify audio some 20 // Choosing 6.0dB here instead of 0dB to give user chance to amplify audio some
20 // in case sounds or their setup is too quiet for them. 21 // in case sounds or their setup is too quiet for them.
21 const double kMaxVolumeDb = 6.0; 22 const double kMaxVolumeDb = 6.0;
22 // A value of less than one adjusts quieter volumes in larger steps (giving 23 // A value of less than one adjusts quieter volumes in larger steps (giving
23 // finer resolution in the higher volumes). 24 // finer resolution in the higher volumes).
24 const double kVolumeBias = 0.5; 25 const double kVolumeBias = 0.5;
25 // If a connection is lost, we try again this many times 26 // If a connection is lost, we try again this many times
26 const int kMaxReconnectTries = 4; 27 const int kMaxReconnectTries = 4;
27 28
28 } // namespace 29 } // namespace
29 30
30 // This class will set volume using PulseAudio to adjust volume and mute, and 31 // This class will set volume using PulseAudio or ALSA to adjust volume and
31 // handles the volume level logic. 32 // mute, and handles the volume level logic.
32
33 // TODO(davej): Serialize volume/mute for next startup?
34 33
35 double AudioHandler::GetVolumePercent() { 34 double AudioHandler::GetVolumePercent() {
36 if (!VerifyMixerConnection()) 35 if (!VerifyMixerConnection())
37 return 0; 36 return 0;
38 37
39 return VolumeDbToPercent(mixer_->GetVolumeDb()); 38 return VolumeDbToPercent(mixer_->GetVolumeDb());
40 } 39 }
41 40
42 // Set volume using our internal 0-100% range. Notice 0% is a special case of 41 // Set volume using our internal 0-100% range. Notice 0% is a special case of
43 // silence, so we set the mixer volume to kSilenceDb instead of kMinVolumeDb. 42 // silence, so we set the mixer volume to kSilenceDb instead of min_volume_db_.
44 void AudioHandler::SetVolumePercent(double volume_percent) { 43 void AudioHandler::SetVolumePercent(double volume_percent) {
45 if (!VerifyMixerConnection()) 44 if (!VerifyMixerConnection())
46 return; 45 return;
47 DCHECK(volume_percent >= 0.0); 46 DCHECK(volume_percent >= 0.0);
48 47
49 double vol_db; 48 double vol_db;
50 if (volume_percent <= 0) 49 if (volume_percent <= 0)
51 vol_db = kSilenceDb; 50 vol_db = AudioMixer::kSilenceDb;
52 else 51 else
53 vol_db = PercentToVolumeDb(volume_percent); 52 vol_db = PercentToVolumeDb(volume_percent);
54 53
55 mixer_->SetVolumeDb(vol_db); 54 mixer_->SetVolumeDb(vol_db);
56 } 55 }
57 56
58 void AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) { 57 void AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) {
59 if (!VerifyMixerConnection()) 58 if (!VerifyMixerConnection())
60 return; 59 return;
61 60
62 DVLOG(1) << "Adjusting Volume by " << adjust_by_percent << " percent"; 61 DVLOG(1) << "Adjusting Volume by " << adjust_by_percent << " percent";
63 62
64 double volume = mixer_->GetVolumeDb(); 63 double volume = mixer_->GetVolumeDb();
65 double pct = VolumeDbToPercent(volume); 64 double pct = VolumeDbToPercent(volume);
66 65
67 if (pct < 0) 66 if (pct < 0)
68 pct = 0; 67 pct = 0;
69 pct = pct + adjust_by_percent; 68 pct = pct + adjust_by_percent;
70 if (pct > 100.0) 69 if (pct > 100.0)
71 pct = 100.0; 70 pct = 100.0;
72 71
73 double new_volume; 72 double new_volume;
74 if (pct <= 0.1) 73 if (pct <= 0.1)
75 new_volume = kSilenceDb; 74 new_volume = AudioMixer::kSilenceDb;
76 else 75 else
77 new_volume = PercentToVolumeDb(pct); 76 new_volume = PercentToVolumeDb(pct);
78 77
79 if (new_volume != volume) 78 if (new_volume != volume)
80 mixer_->SetVolumeDb(new_volume); 79 mixer_->SetVolumeDb(new_volume);
81 } 80 }
82 81
83 bool AudioHandler::IsMute() { 82 bool AudioHandler::IsMute() {
84 if (!VerifyMixerConnection()) 83 if (!VerifyMixerConnection())
85 return false; 84 return false;
86 85
87 return mixer_->IsMute(); 86 return mixer_->IsMute();
88 } 87 }
89 88
90 void AudioHandler::SetMute(bool do_mute) { 89 void AudioHandler::SetMute(bool do_mute) {
91 if (!VerifyMixerConnection()) 90 if (!VerifyMixerConnection())
92 return; 91 return;
93 92
94 DVLOG(1) << "Setting Mute to " << do_mute; 93 DVLOG(1) << "Setting Mute to " << do_mute;
95 94
96 mixer_->SetMute(do_mute); 95 mixer_->SetMute(do_mute);
97 } 96 }
98 97
98 bool AudioHandler::TryToConnect(bool async) {
99 if (using_mixer_ == MIXER_TYPE_PULSEAUDIO) {
100 VLOG(1) << "Trying to connect to PulseAudio";
101 mixer_.reset(new AudioMixerPulse());
102 } else if (using_mixer_ == MIXER_TYPE_ALSA) {
103 VLOG(1) << "Trying to connect to ALSA";
104 mixer_.reset(new AudioMixerAlsa());
105 } else {
106 VLOG(1) << "Cannot find valid volume mixer";
107 mixer_.reset();
108 return false;
109 }
110
111 if (async) {
112 if (!mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized)))
113 return false;
114 } else {
115 if (!mixer_->InitSync()) {
116 VLOG(1) << "Unable to reconnect to Mixer";
117 return false;
118 }
119 }
120 return true;
121 }
122
123 void AudioHandler::UseNextMixer() {
124 if (using_mixer_ == MIXER_TYPE_PULSEAUDIO)
125 using_mixer_ = MIXER_TYPE_ALSA;
126 else
127 using_mixer_ = MIXER_TYPE_NONE;
128 }
129
130 static void ClipVolume(double* min_volume, double* max_volume) {
131 if (*min_volume < kMinVolumeDb)
132 *min_volume = kMinVolumeDb;
133 if (*max_volume > kMaxVolumeDb)
134 *max_volume = kMaxVolumeDb;
135 }
136
99 void AudioHandler::OnMixerInitialized(bool success) { 137 void AudioHandler::OnMixerInitialized(bool success) {
100 connected_ = success; 138 connected_ = success;
101 DVLOG(1) << "OnMixerInitialized, success = " << success; 139 DVLOG(1) << "OnMixerInitialized, success = " << success;
140
141 if (connected_) {
142 if (mixer_->GetVolumeLimits(&min_volume_db_, &max_volume_db_)) {
143 ClipVolume(&min_volume_db_, &max_volume_db_);
144 }
145 } else {
146 UseNextMixer();
147 VLOG(1) << "Unable to connect to mixer, trying next";
148
149 BrowserThread::PostTask(
150 BrowserThread::UI, FROM_HERE,
151 NewRunnableMethod(this, &AudioHandler::TryToConnect, true));
152 }
102 } 153 }
103 154
104 AudioHandler::AudioHandler() 155 AudioHandler::AudioHandler()
105 : connected_(false), 156 : connected_(false),
106 reconnect_tries_(0) { 157 reconnect_tries_(0),
107 mixer_.reset(new PulseAudioMixer()); 158 max_volume_db_(0),
108 if (!mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized))) { 159 min_volume_db_(-90),
109 LOG(ERROR) << "Unable to connect to PulseAudio"; 160 using_mixer_(MIXER_TYPE_PULSEAUDIO) {
161 while (using_mixer_ != MIXER_TYPE_NONE) {
162 if (TryToConnect(true)) {
Daniel Erat 2011/01/05 01:06:53 I think that Chrome style is to omit curly braces
163 break;
164 }
165 UseNextMixer();
110 } 166 }
111 } 167 }
112 168
113 AudioHandler::~AudioHandler() { 169 AudioHandler::~AudioHandler() {
114 mixer_.reset(); 170 mixer_.reset();
115 }; 171 };
116 172
117 bool AudioHandler::VerifyMixerConnection() { 173 bool AudioHandler::VerifyMixerConnection() {
118 PulseAudioMixer::State mixer_state = mixer_->CheckState(); 174 if (mixer_ == NULL)
119 if (mixer_state == PulseAudioMixer::READY) 175 return false;
176
177 AudioMixer::State mixer_state = mixer_->CheckState();
178 if (mixer_state == AudioMixer::READY)
120 return true; 179 return true;
121 if (connected_) { 180 if (connected_) {
122 // Something happened and the mixer is no longer valid after having been 181 // Something happened and the mixer is no longer valid after having been
123 // initialized earlier. 182 // initialized earlier.
124 connected_ = false; 183 connected_ = false;
125 LOG(ERROR) << "Lost connection to PulseAudio"; 184 LOG(ERROR) << "Lost connection to mixer";
126 } else { 185 } else {
127 LOG(ERROR) << "Mixer not valid"; 186 LOG(ERROR) << "Mixer not valid";
128 } 187 }
129 188
130 if ((mixer_state == PulseAudioMixer::INITIALIZING) || 189 if ((mixer_state == AudioMixer::INITIALIZING) ||
131 (mixer_state == PulseAudioMixer::SHUTTING_DOWN)) 190 (mixer_state == AudioMixer::SHUTTING_DOWN))
132 return false; 191 return false;
133 192
134 if (reconnect_tries_ < kMaxReconnectTries) { 193 if (reconnect_tries_ < kMaxReconnectTries) {
135 reconnect_tries_++; 194 reconnect_tries_++;
136 VLOG(1) << "Re-connecting to PulseAudio attempt " << reconnect_tries_ << "/" 195 VLOG(1) << "Re-connecting to mixer attempt " << reconnect_tries_ << "/"
137 << kMaxReconnectTries; 196 << kMaxReconnectTries;
138 mixer_.reset(new PulseAudioMixer()); 197
139 connected_ = mixer_->InitSync(); 198 connected_ = TryToConnect(false);
199
140 if (connected_) { 200 if (connected_) {
141 reconnect_tries_ = 0; 201 reconnect_tries_ = 0;
142 return true; 202 return true;
143 } 203 }
144 LOG(ERROR) << "Unable to re-connect to PulseAudio"; 204 LOG(ERROR) << "Unable to re-connect to mixer";
145 } 205 }
146 return false; 206 return false;
147 } 207 }
148 208
149 // VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us 209 // VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us
150 // complete control over how the 0 to 100% range is mapped to actual loudness. 210 // complete control over how the 0 to 100% range is mapped to actual loudness.
151 // Volume range is from kMinVolumeDb at just above 0% to kMaxVolumeDb at 100% 211 // Volume range is from min_volume_db_ at just above 0% to max_volume_db_
152 // with a special case at 0% which maps to kSilenceDb. 212 // at 100% with a special case at 0% which maps to kSilenceDb.
153 // 213 //
154 // The mapping is confined to these two functions to make it easy to adjust and 214 // The mapping is confined to these two functions to make it easy to adjust and
155 // have everything else just work. The range is biased to give finer resolution 215 // have everything else just work. The range is biased to give finer resolution
156 // in the higher volumes if kVolumeBias is less than 1.0. 216 // in the higher volumes if kVolumeBias is less than 1.0.
157 217
158 // static 218 // static
159 double AudioHandler::VolumeDbToPercent(double volume_db) { 219 double AudioHandler::VolumeDbToPercent(double volume_db) const {
160 if (volume_db < kMinVolumeDb) 220 if (volume_db < min_volume_db_)
161 return 0; 221 return 0;
162 return 100.0 * pow((volume_db - kMinVolumeDb) / 222 return 100.0 * pow((volume_db - min_volume_db_) /
163 (kMaxVolumeDb - kMinVolumeDb), 1/kVolumeBias); 223 (max_volume_db_ - min_volume_db_), 1/kVolumeBias);
164 } 224 }
165 225
166 // static 226 // static
167 double AudioHandler::PercentToVolumeDb(double volume_percent) { 227 double AudioHandler::PercentToVolumeDb(double volume_percent) const {
168 return pow(volume_percent / 100.0, kVolumeBias) * 228 return pow(volume_percent / 100.0, kVolumeBias) *
169 (kMaxVolumeDb - kMinVolumeDb) + kMinVolumeDb; 229 (max_volume_db_ - min_volume_db_) + min_volume_db_;
170 } 230 }
171 231
172 // static 232 // static
173 AudioHandler* AudioHandler::GetInstance() { 233 AudioHandler* AudioHandler::GetInstance() {
174 return Singleton<AudioHandler>::get(); 234 return Singleton<AudioHandler>::get();
175 } 235 }
176 236
177 } // namespace chromeos 237 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698