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

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: Responded to comments 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
« no previous file with comments | « chrome/browser/chromeos/audio_handler.h ('k') | chrome/browser/chromeos/audio_mixer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/browser_thread.h"
12 #include "chrome/browser/chromeos/audio_mixer_alsa.h"
13 #include "chrome/browser/chromeos/audio_mixer_pulse.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;
92 DVLOG(1) << "Setting Mute to " << do_mute;
93 mixer_->SetMute(do_mute);
94 }
93 95
94 DVLOG(1) << "Setting Mute to " << do_mute; 96 bool AudioHandler::TryToConnect(bool async) {
97 if (mixer_type_ == MIXER_TYPE_PULSEAUDIO) {
98 VLOG(1) << "Trying to connect to PulseAudio";
99 mixer_.reset(new AudioMixerPulse());
100 } else if (mixer_type_ == MIXER_TYPE_ALSA) {
101 VLOG(1) << "Trying to connect to ALSA";
102 mixer_.reset(new AudioMixerAlsa());
103 } else {
104 VLOG(1) << "Cannot find valid volume mixer";
105 mixer_.reset();
106 return false;
107 }
95 108
96 mixer_->SetMute(do_mute); 109 if (async) {
110 mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized));
111 } else {
112 if (!mixer_->InitSync()) {
113 VLOG(1) << "Unable to reconnect to Mixer";
114 return false;
115 }
116 }
117 return true;
118 }
119
120 void AudioHandler::UseNextMixer() {
121 if (mixer_type_ == MIXER_TYPE_PULSEAUDIO)
122 mixer_type_ = MIXER_TYPE_ALSA;
123 else
124 mixer_type_ = MIXER_TYPE_NONE;
125 }
126
127 static void ClipVolume(double* min_volume, double* max_volume) {
128 if (*min_volume < kMinVolumeDb)
129 *min_volume = kMinVolumeDb;
130 if (*max_volume > kMaxVolumeDb)
131 *max_volume = kMaxVolumeDb;
97 } 132 }
98 133
99 void AudioHandler::OnMixerInitialized(bool success) { 134 void AudioHandler::OnMixerInitialized(bool success) {
100 connected_ = success; 135 connected_ = success;
101 DVLOG(1) << "OnMixerInitialized, success = " << success; 136 DVLOG(1) << "OnMixerInitialized, success = " << success;
137
138 if (connected_) {
139 if (mixer_->GetVolumeLimits(&min_volume_db_, &max_volume_db_)) {
140 ClipVolume(&min_volume_db_, &max_volume_db_);
141 }
142 return;
143 }
144
145 VLOG(1) << "Unable to connect to mixer, trying next";
146 UseNextMixer();
147
148 BrowserThread::PostTask(
149 BrowserThread::UI, FROM_HERE,
150 NewRunnableMethod(this, &AudioHandler::TryToConnect, true));
102 } 151 }
103 152
104 AudioHandler::AudioHandler() 153 AudioHandler::AudioHandler()
105 : connected_(false), 154 : connected_(false),
106 reconnect_tries_(0) { 155 reconnect_tries_(0),
107 mixer_.reset(new PulseAudioMixer()); 156 max_volume_db_(kMaxVolumeDb),
108 if (!mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized))) { 157 min_volume_db_(kMinVolumeDb),
109 LOG(ERROR) << "Unable to connect to PulseAudio"; 158 mixer_type_(MIXER_TYPE_PULSEAUDIO) {
110 } 159
160 // Start trying to connect to mixers asychronously, starting with the current
161 // mixer_type_. If the connection fails, another TryToConnect for the next
scherkus (not reviewing) 2011/01/11 20:10:39 nit: add () to function names and get rid of blank
162 // mixer will be posted at that time.
163
164 TryToConnect(true);
111 } 165 }
112 166
113 AudioHandler::~AudioHandler() { 167 AudioHandler::~AudioHandler() {
114 mixer_.reset(); 168 mixer_.reset();
115 }; 169 };
116 170
117 bool AudioHandler::VerifyMixerConnection() { 171 bool AudioHandler::VerifyMixerConnection() {
118 PulseAudioMixer::State mixer_state = mixer_->CheckState(); 172 if (mixer_ == NULL)
119 if (mixer_state == PulseAudioMixer::READY) 173 return false;
174
175 AudioMixer::State mixer_state = mixer_->GetState();
176 if (mixer_state == AudioMixer::READY)
120 return true; 177 return true;
121 if (connected_) { 178 if (connected_) {
122 // Something happened and the mixer is no longer valid after having been 179 // Something happened and the mixer is no longer valid after having been
123 // initialized earlier. 180 // initialized earlier.
124 connected_ = false; 181 connected_ = false;
125 LOG(ERROR) << "Lost connection to PulseAudio"; 182 LOG(ERROR) << "Lost connection to mixer";
126 } else { 183 } else {
127 LOG(ERROR) << "Mixer not valid"; 184 LOG(ERROR) << "Mixer not valid";
128 } 185 }
129 186
130 if ((mixer_state == PulseAudioMixer::INITIALIZING) || 187 if ((mixer_state == AudioMixer::INITIALIZING) ||
131 (mixer_state == PulseAudioMixer::SHUTTING_DOWN)) 188 (mixer_state == AudioMixer::SHUTTING_DOWN))
132 return false; 189 return false;
133 190
134 if (reconnect_tries_ < kMaxReconnectTries) { 191 if (reconnect_tries_ < kMaxReconnectTries) {
135 reconnect_tries_++; 192 reconnect_tries_++;
136 VLOG(1) << "Re-connecting to PulseAudio attempt " << reconnect_tries_ << "/" 193 VLOG(1) << "Re-connecting to mixer attempt " << reconnect_tries_ << "/"
137 << kMaxReconnectTries; 194 << kMaxReconnectTries;
138 mixer_.reset(new PulseAudioMixer()); 195
139 connected_ = mixer_->InitSync(); 196 connected_ = TryToConnect(false);
197
140 if (connected_) { 198 if (connected_) {
141 reconnect_tries_ = 0; 199 reconnect_tries_ = 0;
142 return true; 200 return true;
143 } 201 }
144 LOG(ERROR) << "Unable to re-connect to PulseAudio"; 202 LOG(ERROR) << "Unable to re-connect to mixer";
145 } 203 }
146 return false; 204 return false;
147 } 205 }
148 206
149 // VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us 207 // VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us
150 // complete control over how the 0 to 100% range is mapped to actual loudness. 208 // 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% 209 // 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. 210 // at 100% with a special case at 0% which maps to kSilenceDb.
153 // 211 //
154 // The mapping is confined to these two functions to make it easy to adjust and 212 // 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 213 // 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. 214 // in the higher volumes if kVolumeBias is less than 1.0.
157 215
158 // static 216 // static
159 double AudioHandler::VolumeDbToPercent(double volume_db) { 217 double AudioHandler::VolumeDbToPercent(double volume_db) const {
160 if (volume_db < kMinVolumeDb) 218 if (volume_db < min_volume_db_)
161 return 0; 219 return 0;
162 return 100.0 * pow((volume_db - kMinVolumeDb) / 220 return 100.0 * pow((volume_db - min_volume_db_) /
163 (kMaxVolumeDb - kMinVolumeDb), 1/kVolumeBias); 221 (max_volume_db_ - min_volume_db_), 1/kVolumeBias);
164 } 222 }
165 223
166 // static 224 // static
167 double AudioHandler::PercentToVolumeDb(double volume_percent) { 225 double AudioHandler::PercentToVolumeDb(double volume_percent) const {
168 return pow(volume_percent / 100.0, kVolumeBias) * 226 return pow(volume_percent / 100.0, kVolumeBias) *
169 (kMaxVolumeDb - kMinVolumeDb) + kMinVolumeDb; 227 (max_volume_db_ - min_volume_db_) + min_volume_db_;
170 } 228 }
171 229
172 // static 230 // static
173 AudioHandler* AudioHandler::GetInstance() { 231 AudioHandler* AudioHandler::GetInstance() {
174 return Singleton<AudioHandler>::get(); 232 return Singleton<AudioHandler>::get();
175 } 233 }
176 234
177 } // namespace chromeos 235 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/audio_handler.h ('k') | chrome/browser/chromeos/audio_mixer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698