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

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: Rebased to ToT. 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 mute) {
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
143 base::AutoLock lock(lock_); 146 base::AutoLock lock(lock_);
144 is_muted_ = muted; 147 if (is_mute_locked_) {
145 if (!apply_is_pending_) 148 NOTREACHED() << "Capture mute has been locked!";
146 thread_->message_loop()->PostTask(FROM_HERE, 149 return;
147 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this))); 150 }
151 is_muted_ = mute;
152 ApplyStateIfNeeded();
153 }
154
155 bool AudioMixerAlsa::IsMuteLocked() {
156 base::AutoLock lock(lock_);
157 return is_mute_locked_;
158 }
159
160 void AudioMixerAlsa::SetMuteLocked(bool locked) {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
162 base::AutoLock lock(lock_);
163 is_mute_locked_ = locked;
164 }
165
166 bool AudioMixerAlsa::IsCaptureMuted() {
167 base::AutoLock lock(lock_);
168 return is_capture_muted_;
169 }
170
171 void AudioMixerAlsa::SetCaptureMuted(bool mute) {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
173 base::AutoLock lock(lock_);
174 if (is_capture_mute_locked_) {
175 NOTREACHED() << "Capture mute has been locked!";
176 return;
177 }
178 is_capture_muted_ = mute;
179 ApplyStateIfNeeded();
180 }
181
182 bool AudioMixerAlsa::IsCaptureMuteLocked() {
183 base::AutoLock lock(lock_);
184 return is_capture_mute_locked_;
185 }
186
187 void AudioMixerAlsa::SetCaptureMuteLocked(bool locked) {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189 base::AutoLock lock(lock_);
190 is_capture_mute_locked_ = locked;
148 } 191 }
149 192
150 void AudioMixerAlsa::Connect() { 193 void AudioMixerAlsa::Connect() {
151 DCHECK(MessageLoop::current() == thread_->message_loop()); 194 DCHECK(MessageLoop::current() == thread_->message_loop());
152 DCHECK(!alsa_mixer_); 195 DCHECK(!alsa_mixer_);
153 196
154 if (disconnected_event_.IsSignaled()) 197 if (disconnected_event_.IsSignaled())
155 return; 198 return;
156 199
157 // Do not attempt to connect if we're not on the device. 200 // 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); 302 << kPCMElementName << ": " << snd_strerror(err);
260 snd_mixer_close(handle); 303 snd_mixer_close(handle);
261 return false; 304 return false;
262 } 305 }
263 min_volume_db += static_cast<double>(long_low) / 100.0; 306 min_volume_db += static_cast<double>(long_low) / 100.0;
264 max_volume_db += static_cast<double>(long_high) / 100.0; 307 max_volume_db += static_cast<double>(long_high) / 100.0;
265 } 308 }
266 309
267 VLOG(1) << "Volume range is " << min_volume_db << " dB to " 310 VLOG(1) << "Volume range is " << min_volume_db << " dB to "
268 << max_volume_db << " dB"; 311 << max_volume_db << " dB";
312
313 snd_mixer_elem_t* mic_element = FindElementWithName(handle, kMicElementName);
314 snd_mixer_elem_t* front_mic_element =
315 FindElementWithName(handle, kFrontMicElementName);
269 { 316 {
270 base::AutoLock lock(lock_); 317 base::AutoLock lock(lock_);
271 alsa_mixer_ = handle; 318 alsa_mixer_ = handle;
272 master_element_ = master_element; 319 master_element_ = master_element;
273 pcm_element_ = pcm_element; 320 pcm_element_ = pcm_element;
321 mic_element_ = mic_element;
322 front_mic_element_ = front_mic_element;
274 min_volume_db_ = min_volume_db; 323 min_volume_db_ = min_volume_db;
275 max_volume_db_ = max_volume_db; 324 max_volume_db_ = max_volume_db;
276 volume_db_ = PercentToDb(initial_volume_percent_); 325 volume_db_ = PercentToDb(initial_volume_percent_);
277 } 326 }
278 327
279 // The speech synthesis service shouldn't be initialized until after 328 // 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 329 // 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, 330 // safe to do TTS now. NotificationService would be cleaner,
282 // but it's not available at this point. 331 // but it's not available at this point.
283 EnableChromeOsTts(); 332 EnableChromeOsTts();
(...skipping 10 matching lines...) Expand all
294 } 343 }
295 disconnected_event_.Signal(); 344 disconnected_event_.Signal();
296 } 345 }
297 346
298 void AudioMixerAlsa::ApplyState() { 347 void AudioMixerAlsa::ApplyState() {
299 DCHECK(MessageLoop::current() == thread_->message_loop()); 348 DCHECK(MessageLoop::current() == thread_->message_loop());
300 if (!alsa_mixer_) 349 if (!alsa_mixer_)
301 return; 350 return;
302 351
303 bool should_mute = false; 352 bool should_mute = false;
353 bool should_mute_capture = false;
304 double new_volume_db = 0; 354 double new_volume_db = 0;
305 { 355 {
306 base::AutoLock lock(lock_); 356 base::AutoLock lock(lock_);
307 should_mute = is_muted_; 357 should_mute = is_muted_;
358 should_mute_capture = is_capture_muted_;
308 new_volume_db = should_mute ? min_volume_db_ : volume_db_; 359 new_volume_db = should_mute ? min_volume_db_ : volume_db_;
309 apply_is_pending_ = false; 360 apply_is_pending_ = false;
310 } 361 }
311 362
312 if (pcm_element_) { 363 if (pcm_element_) {
313 // If a PCM volume slider exists, then first set the Master volume to the 364 // 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 365 // nearest volume >= requested volume, then adjust PCM volume down to get
315 // closer to the requested volume. 366 // closer to the requested volume.
316 SetElementVolume(master_element_, new_volume_db, 0.9999f); 367 SetElementVolume(master_element_, new_volume_db, 0.9999f);
317 368
318 double pcm_volume_db = 0.0; 369 double pcm_volume_db = 0.0;
319 double master_volume_db = 0.0; 370 double master_volume_db = 0.0;
320 if (GetElementVolume(master_element_, &master_volume_db)) 371 if (GetElementVolume(master_element_, &master_volume_db))
321 pcm_volume_db = new_volume_db - master_volume_db; 372 pcm_volume_db = new_volume_db - master_volume_db;
322 SetElementVolume(pcm_element_, pcm_volume_db, 0.5f); 373 SetElementVolume(pcm_element_, pcm_volume_db, 0.5f);
323 } else { 374 } else {
324 SetElementVolume(master_element_, new_volume_db, 0.5f); 375 SetElementVolume(master_element_, new_volume_db, 0.5f);
325 } 376 }
326 377
327 SetElementMuted(master_element_, should_mute); 378 SetElementMuted(master_element_, should_mute);
379 if (mic_element_)
380 SetElementMuted(mic_element_, should_mute_capture);
381 if (front_mic_element_)
382 SetElementMuted(front_mic_element_, should_mute_capture);
328 } 383 }
329 384
330 snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName( 385 snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName(
331 snd_mixer_t* handle, const string& element_name) const { 386 snd_mixer_t* handle, const string& element_name) const {
332 DCHECK(MessageLoop::current() == thread_->message_loop()); 387 DCHECK(MessageLoop::current() == thread_->message_loop());
333 snd_mixer_selem_id_t* sid = NULL; 388 snd_mixer_selem_id_t* sid = NULL;
334 389
335 // Using id_malloc/id_free API instead of id_alloca since the latter gives the 390 // 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'. 391 // warning: the address of 'sid' will always evaluate as 'true'.
337 if (snd_mixer_selem_id_malloc(&sid)) 392 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_) / 488 return 100.0 * pow((db - min_volume_db_) /
434 (max_volume_db_ - min_volume_db_), 1/kVolumeBias); 489 (max_volume_db_ - min_volume_db_), 1/kVolumeBias);
435 } 490 }
436 491
437 double AudioMixerAlsa::PercentToDb(double percent) const { 492 double AudioMixerAlsa::PercentToDb(double percent) const {
438 lock_.AssertAcquired(); 493 lock_.AssertAcquired();
439 return pow(percent / 100.0, kVolumeBias) * 494 return pow(percent / 100.0, kVolumeBias) *
440 (max_volume_db_ - min_volume_db_) + min_volume_db_; 495 (max_volume_db_ - min_volume_db_) + min_volume_db_;
441 } 496 }
442 497
498 void AudioMixerAlsa::ApplyStateIfNeeded() {
499 lock_.AssertAcquired();
500 if (!apply_is_pending_) {
501 thread_->message_loop()->PostTask(
502 FROM_HERE,
503 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this)));
504 }
505 }
506
443 } // namespace chromeos 507 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/audio/audio_mixer_alsa.h ('k') | chrome/browser/chromeos/audio/audio_mixer_cras.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698