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

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

Issue 10873085: Implement two new policies to control muting the audio I/O. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. Created 8 years, 3 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/audio_mixer_alsa.h" 5 #include "chrome/browser/chromeos/audio/audio_mixer_alsa.h"
6 6
7 #include <unistd.h> 7 #include <unistd.h>
8 8
9 #include <alsa/asoundlib.h> 9 #include <alsa/asoundlib.h>
10 10
(...skipping 23 matching lines...) Expand all
34 const char kCardName[] = "default"; 34 const char kCardName[] = "default";
35 35
36 // Mixer element names. We'll use the first master element from the list that 36 // Mixer element names. We'll use the first master element from the list that
37 // exists. 37 // exists.
38 const char* const kMasterElementNames[] = { 38 const char* const kMasterElementNames[] = {
39 "Master", // x86 39 "Master", // x86
40 "Digital", // ARM 40 "Digital", // ARM
41 }; 41 };
42 const char kPCMElementName[] = "PCM"; 42 const char kPCMElementName[] = "PCM";
43 43
44 const char kMicElementName[] = "Mic";
45 const char kFrontMicElementName[] = "Front Mic";
46
44 // Default minimum and maximum volume (before we've loaded the actual range from 47 // Default minimum and maximum volume (before we've loaded the actual range from
45 // ALSA), in decibels. 48 // ALSA), in decibels.
46 const double kDefaultMinVolumeDb = -90.0; 49 const double kDefaultMinVolumeDb = -90.0;
47 const double kDefaultMaxVolumeDb = 0.0; 50 const double kDefaultMaxVolumeDb = 0.0;
48 51
49 // Default volume as a percentage in the range [0.0, 100.0]. 52 // Default volume as a percentage in the range [0.0, 100.0].
50 const double kDefaultVolumePercent = 75.0; 53 const double kDefaultVolumePercent = 75.0;
51 54
52 // A value of less than 1.0 adjusts quieter volumes in larger steps (giving 55 // A value of less than 1.0 adjusts quieter volumes in larger steps (giving
53 // finer resolution in the higher volumes). 56 // finer resolution in the higher volumes).
(...skipping 15 matching lines...) Expand all
69 72
70 AudioMixerAlsa::AudioMixerAlsa() 73 AudioMixerAlsa::AudioMixerAlsa()
71 : min_volume_db_(kDefaultMinVolumeDb), 74 : min_volume_db_(kDefaultMinVolumeDb),
72 max_volume_db_(kDefaultMaxVolumeDb), 75 max_volume_db_(kDefaultMaxVolumeDb),
73 volume_db_(kDefaultMinVolumeDb), 76 volume_db_(kDefaultMinVolumeDb),
74 is_muted_(false), 77 is_muted_(false),
75 apply_is_pending_(true), 78 apply_is_pending_(true),
76 initial_volume_percent_(kDefaultVolumePercent), 79 initial_volume_percent_(kDefaultVolumePercent),
77 alsa_mixer_(NULL), 80 alsa_mixer_(NULL),
78 pcm_element_(NULL), 81 pcm_element_(NULL),
82 mic_element_(NULL),
83 front_mic_element_(NULL),
79 disconnected_event_(true, false), 84 disconnected_event_(true, false),
80 num_connection_attempts_(0) { 85 num_connection_attempts_(0) {
81 } 86 }
82 87
83 AudioMixerAlsa::~AudioMixerAlsa() { 88 AudioMixerAlsa::~AudioMixerAlsa() {
84 if (!thread_.get()) 89 if (!thread_.get())
85 return; 90 return;
86 DCHECK(MessageLoop::current() != thread_->message_loop()); 91 DCHECK(MessageLoop::current() != thread_->message_loop());
87 92
88 thread_->message_loop()->PostTask( 93 thread_->message_loop()->PostTask(
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 125
121 if (isnan(percent)) 126 if (isnan(percent))
122 percent = 0.0; 127 percent = 0.0;
123 percent = std::max(std::min(percent, 100.0), 0.0); 128 percent = std::max(std::min(percent, 100.0), 0.0);
124 129
125 base::AutoLock lock(lock_); 130 base::AutoLock lock(lock_);
126 if (!alsa_mixer_) { 131 if (!alsa_mixer_) {
127 initial_volume_percent_ = percent; 132 initial_volume_percent_ = percent;
128 } else { 133 } else {
129 volume_db_ = PercentToDb(percent); 134 volume_db_ = PercentToDb(percent);
130 if (!apply_is_pending_) 135 ApplyStateIfNeeded();
131 thread_->message_loop()->PostTask(FROM_HERE,
132 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this)));
133 } 136 }
134 } 137 }
135 138
136 bool AudioMixerAlsa::IsMuted() { 139 bool AudioMixerAlsa::IsMuted() {
137 base::AutoLock lock(lock_); 140 base::AutoLock lock(lock_);
138 return is_muted_; 141 return is_muted_;
139 } 142 }
140 143
141 void AudioMixerAlsa::SetMuted(bool muted) { 144 void AudioMixerAlsa::SetMuted(bool muted) {
Daniel Erat 2012/08/29 15:37:00 nit: s/muted/mute/
pastarmovj 2012/08/29 16:15:52 Done.
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143 base::AutoLock lock(lock_); 146 base::AutoLock lock(lock_);
147 if (is_mute_locked_)
Daniel Erat 2012/08/29 15:37:00 add a NOTREACHED() here to match AudioMixerCras an
pastarmovj 2012/08/29 16:15:52 Done.
148 return;
144 is_muted_ = muted; 149 is_muted_ = muted;
145 if (!apply_is_pending_) 150 ApplyStateIfNeeded();
146 thread_->message_loop()->PostTask(FROM_HERE, 151 }
147 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this))); 152
153 bool AudioMixerAlsa::IsMuteLocked() {
154 base::AutoLock lock(lock_);
155 return is_mute_locked_;
156 }
157
158 void AudioMixerAlsa::SetMuteLocked(bool locked) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 base::AutoLock lock(lock_);
161 is_mute_locked_ = locked;
162 ApplyStateIfNeeded();
Daniel Erat 2012/08/29 15:37:00 this call doesn't appear to be necessary since the
pastarmovj 2012/08/29 16:15:52 True. Cleaned.
163 }
164
165 bool AudioMixerAlsa::IsCaptureMuted() {
166 base::AutoLock lock(lock_);
167 return is_capture_muted_;
168 }
169
170 void AudioMixerAlsa::SetCaptureMuted(bool muted) {
Daniel Erat 2012/08/29 15:37:00 nit: s/muted/mute/ here too?
pastarmovj 2012/08/29 16:15:52 Done.
171 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172 base::AutoLock lock(lock_);
173 if (is_capture_mute_locked_)
Daniel Erat 2012/08/29 15:37:00 NOTREACHED()?
pastarmovj 2012/08/29 16:15:52 Done.
174 return;
175 is_capture_muted_ = muted;
176 ApplyStateIfNeeded();
177 }
178
179 bool AudioMixerAlsa::IsCaptureMuteLocked() {
180 base::AutoLock lock(lock_);
181 return is_capture_mute_locked_;
182 }
183
184 void AudioMixerAlsa::SetCaptureMuteLocked(bool locked) {
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186 base::AutoLock lock(lock_);
187 is_capture_mute_locked_ = locked;
188 ApplyStateIfNeeded();
Daniel Erat 2012/08/29 15:37:00 this call doesn't appear to be necessary since the
pastarmovj 2012/08/29 16:15:52 Done.
148 } 189 }
149 190
150 void AudioMixerAlsa::Connect() { 191 void AudioMixerAlsa::Connect() {
151 DCHECK(MessageLoop::current() == thread_->message_loop()); 192 DCHECK(MessageLoop::current() == thread_->message_loop());
152 DCHECK(!alsa_mixer_); 193 DCHECK(!alsa_mixer_);
153 194
154 if (disconnected_event_.IsSignaled()) 195 if (disconnected_event_.IsSignaled())
155 return; 196 return;
156 197
157 // Do not attempt to connect if we're not on the device. 198 // Do not attempt to connect if we're not on the device.
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 << kPCMElementName << ": " << snd_strerror(err); 300 << kPCMElementName << ": " << snd_strerror(err);
260 snd_mixer_close(handle); 301 snd_mixer_close(handle);
261 return false; 302 return false;
262 } 303 }
263 min_volume_db += static_cast<double>(long_low) / 100.0; 304 min_volume_db += static_cast<double>(long_low) / 100.0;
264 max_volume_db += static_cast<double>(long_high) / 100.0; 305 max_volume_db += static_cast<double>(long_high) / 100.0;
265 } 306 }
266 307
267 VLOG(1) << "Volume range is " << min_volume_db << " dB to " 308 VLOG(1) << "Volume range is " << min_volume_db << " dB to "
268 << max_volume_db << " dB"; 309 << max_volume_db << " dB";
310
311 snd_mixer_elem_t* mic_element = FindElementWithName(handle, kMicElementName);
312 snd_mixer_elem_t* front_mic_element =
313 FindElementWithName(handle, kFrontMicElementName);
269 { 314 {
270 base::AutoLock lock(lock_); 315 base::AutoLock lock(lock_);
271 alsa_mixer_ = handle; 316 alsa_mixer_ = handle;
272 master_element_ = master_element; 317 master_element_ = master_element;
273 pcm_element_ = pcm_element; 318 pcm_element_ = pcm_element;
319 mic_element_ = mic_element;
320 front_mic_element_ = front_mic_element;
274 min_volume_db_ = min_volume_db; 321 min_volume_db_ = min_volume_db;
275 max_volume_db_ = max_volume_db; 322 max_volume_db_ = max_volume_db;
276 volume_db_ = PercentToDb(initial_volume_percent_); 323 volume_db_ = PercentToDb(initial_volume_percent_);
277 } 324 }
278 325
279 // The speech synthesis service shouldn't be initialized until after 326 // The speech synthesis service shouldn't be initialized until after
280 // we get to this point, so we call this function to tell it that it's 327 // we get to this point, so we call this function to tell it that it's
281 // safe to do TTS now. NotificationService would be cleaner, 328 // safe to do TTS now. NotificationService would be cleaner,
282 // but it's not available at this point. 329 // but it's not available at this point.
283 EnableChromeOsTts(); 330 EnableChromeOsTts();
(...skipping 10 matching lines...) Expand all
294 } 341 }
295 disconnected_event_.Signal(); 342 disconnected_event_.Signal();
296 } 343 }
297 344
298 void AudioMixerAlsa::ApplyState() { 345 void AudioMixerAlsa::ApplyState() {
299 DCHECK(MessageLoop::current() == thread_->message_loop()); 346 DCHECK(MessageLoop::current() == thread_->message_loop());
300 if (!alsa_mixer_) 347 if (!alsa_mixer_)
301 return; 348 return;
302 349
303 bool should_mute = false; 350 bool should_mute = false;
351 bool should_mute_capture = false;
304 double new_volume_db = 0; 352 double new_volume_db = 0;
305 { 353 {
306 base::AutoLock lock(lock_); 354 base::AutoLock lock(lock_);
307 should_mute = is_muted_; 355 should_mute = is_muted_;
356 should_mute_capture = is_capture_muted_;
308 new_volume_db = should_mute ? min_volume_db_ : volume_db_; 357 new_volume_db = should_mute ? min_volume_db_ : volume_db_;
309 apply_is_pending_ = false; 358 apply_is_pending_ = false;
310 } 359 }
311 360
312 if (pcm_element_) { 361 if (pcm_element_) {
313 // If a PCM volume slider exists, then first set the Master volume to the 362 // If a PCM volume slider exists, then first set the Master volume to the
314 // nearest volume >= requested volume, then adjust PCM volume down to get 363 // nearest volume >= requested volume, then adjust PCM volume down to get
315 // closer to the requested volume. 364 // closer to the requested volume.
316 SetElementVolume(master_element_, new_volume_db, 0.9999f); 365 SetElementVolume(master_element_, new_volume_db, 0.9999f);
317 366
318 double pcm_volume_db = 0.0; 367 double pcm_volume_db = 0.0;
319 double master_volume_db = 0.0; 368 double master_volume_db = 0.0;
320 if (GetElementVolume(master_element_, &master_volume_db)) 369 if (GetElementVolume(master_element_, &master_volume_db))
321 pcm_volume_db = new_volume_db - master_volume_db; 370 pcm_volume_db = new_volume_db - master_volume_db;
322 SetElementVolume(pcm_element_, pcm_volume_db, 0.5f); 371 SetElementVolume(pcm_element_, pcm_volume_db, 0.5f);
323 } else { 372 } else {
324 SetElementVolume(master_element_, new_volume_db, 0.5f); 373 SetElementVolume(master_element_, new_volume_db, 0.5f);
325 } 374 }
326 375
327 SetElementMuted(master_element_, should_mute); 376 SetElementMuted(master_element_, should_mute);
377 if (mic_element_)
378 SetElementMuted(mic_element_, should_mute_capture);
379 if (front_mic_element_)
380 SetElementMuted(front_mic_element_, should_mute_capture);
328 } 381 }
329 382
330 snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName( 383 snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName(
331 snd_mixer_t* handle, const string& element_name) const { 384 snd_mixer_t* handle, const string& element_name) const {
332 DCHECK(MessageLoop::current() == thread_->message_loop()); 385 DCHECK(MessageLoop::current() == thread_->message_loop());
333 snd_mixer_selem_id_t* sid = NULL; 386 snd_mixer_selem_id_t* sid = NULL;
334 387
335 // Using id_malloc/id_free API instead of id_alloca since the latter gives the 388 // Using id_malloc/id_free API instead of id_alloca since the latter gives the
336 // warning: the address of 'sid' will always evaluate as 'true'. 389 // warning: the address of 'sid' will always evaluate as 'true'.
337 if (snd_mixer_selem_id_malloc(&sid)) 390 if (snd_mixer_selem_id_malloc(&sid))
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 return 100.0 * pow((db - min_volume_db_) / 486 return 100.0 * pow((db - min_volume_db_) /
434 (max_volume_db_ - min_volume_db_), 1/kVolumeBias); 487 (max_volume_db_ - min_volume_db_), 1/kVolumeBias);
435 } 488 }
436 489
437 double AudioMixerAlsa::PercentToDb(double percent) const { 490 double AudioMixerAlsa::PercentToDb(double percent) const {
438 lock_.AssertAcquired(); 491 lock_.AssertAcquired();
439 return pow(percent / 100.0, kVolumeBias) * 492 return pow(percent / 100.0, kVolumeBias) *
440 (max_volume_db_ - min_volume_db_) + min_volume_db_; 493 (max_volume_db_ - min_volume_db_) + min_volume_db_;
441 } 494 }
442 495
496 void AudioMixerAlsa::ApplyStateIfNeeded() {
497 lock_.AssertAcquired();
498 if (!apply_is_pending_) {
499 thread_->message_loop()->PostTask(FROM_HERE,
500 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this)));
501 }
502 }
503
443 } // namespace chromeos 504 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698