OLD | NEW |
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 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 pcm_element_(NULL), | 80 pcm_element_(NULL), |
81 mic_element_(NULL), | 81 mic_element_(NULL), |
82 front_mic_element_(NULL), | 82 front_mic_element_(NULL), |
83 disconnected_event_(true, false), | 83 disconnected_event_(true, false), |
84 num_connection_attempts_(0) { | 84 num_connection_attempts_(0) { |
85 } | 85 } |
86 | 86 |
87 AudioMixerAlsa::~AudioMixerAlsa() { | 87 AudioMixerAlsa::~AudioMixerAlsa() { |
88 if (!thread_.get()) | 88 if (!thread_.get()) |
89 return; | 89 return; |
90 DCHECK(MessageLoop::current() != thread_->message_loop()); | 90 DCHECK(base::MessageLoop::current() != thread_->message_loop()); |
91 | 91 |
92 thread_->message_loop()->PostTask( | 92 thread_->message_loop()->PostTask( |
93 FROM_HERE, base::Bind(&AudioMixerAlsa::Disconnect, | 93 FROM_HERE, base::Bind(&AudioMixerAlsa::Disconnect, |
94 base::Unretained(this))); | 94 base::Unretained(this))); |
95 { | 95 { |
96 // http://crbug.com/125206 | 96 // http://crbug.com/125206 |
97 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 97 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
98 disconnected_event_.Wait(); | 98 disconnected_event_.Wait(); |
99 } | 99 } |
100 | 100 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 return is_capture_mute_locked_; | 183 return is_capture_mute_locked_; |
184 } | 184 } |
185 | 185 |
186 void AudioMixerAlsa::SetCaptureMuteLocked(bool locked) { | 186 void AudioMixerAlsa::SetCaptureMuteLocked(bool locked) { |
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
188 base::AutoLock lock(lock_); | 188 base::AutoLock lock(lock_); |
189 is_capture_mute_locked_ = locked; | 189 is_capture_mute_locked_ = locked; |
190 } | 190 } |
191 | 191 |
192 void AudioMixerAlsa::Connect() { | 192 void AudioMixerAlsa::Connect() { |
193 DCHECK(MessageLoop::current() == thread_->message_loop()); | 193 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
194 DCHECK(!alsa_mixer_); | 194 DCHECK(!alsa_mixer_); |
195 | 195 |
196 if (disconnected_event_.IsSignaled()) | 196 if (disconnected_event_.IsSignaled()) |
197 return; | 197 return; |
198 | 198 |
199 // Do not attempt to connect if we're not on the device. | 199 // Do not attempt to connect if we're not on the device. |
200 if (!base::chromeos::IsRunningOnChromeOS()) | 200 if (!base::chromeos::IsRunningOnChromeOS()) |
201 return; | 201 return; |
202 | 202 |
203 if (!ConnectInternal()) { | 203 if (!ConnectInternal()) { |
204 thread_->message_loop()->PostDelayedTask(FROM_HERE, | 204 thread_->message_loop()->PostDelayedTask(FROM_HERE, |
205 base::Bind(&AudioMixerAlsa::Connect, base::Unretained(this)), | 205 base::Bind(&AudioMixerAlsa::Connect, base::Unretained(this)), |
206 base::TimeDelta::FromSeconds(kConnectionRetrySleepSec)); | 206 base::TimeDelta::FromSeconds(kConnectionRetrySleepSec)); |
207 } | 207 } |
208 } | 208 } |
209 | 209 |
210 bool AudioMixerAlsa::ConnectInternal() { | 210 bool AudioMixerAlsa::ConnectInternal() { |
211 DCHECK(MessageLoop::current() == thread_->message_loop()); | 211 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
212 num_connection_attempts_++; | 212 num_connection_attempts_++; |
213 int err; | 213 int err; |
214 snd_mixer_t* handle = NULL; | 214 snd_mixer_t* handle = NULL; |
215 | 215 |
216 if ((err = snd_mixer_open(&handle, 0)) < 0) { | 216 if ((err = snd_mixer_open(&handle, 0)) < 0) { |
217 if (num_connection_attempts_ == kConnectionAttemptToLogFailure) | 217 if (num_connection_attempts_ == kConnectionAttemptToLogFailure) |
218 LOG(WARNING) << "Mixer open error: " << snd_strerror(err); | 218 LOG(WARNING) << "Mixer open error: " << snd_strerror(err); |
219 return false; | 219 return false; |
220 } | 220 } |
221 | 221 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 min_volume_db_ = min_volume_db; | 322 min_volume_db_ = min_volume_db; |
323 max_volume_db_ = max_volume_db; | 323 max_volume_db_ = max_volume_db; |
324 volume_db_ = PercentToDb(initial_volume_percent_); | 324 volume_db_ = PercentToDb(initial_volume_percent_); |
325 } | 325 } |
326 | 326 |
327 ApplyState(); | 327 ApplyState(); |
328 return true; | 328 return true; |
329 } | 329 } |
330 | 330 |
331 void AudioMixerAlsa::Disconnect() { | 331 void AudioMixerAlsa::Disconnect() { |
332 DCHECK(MessageLoop::current() == thread_->message_loop()); | 332 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
333 if (alsa_mixer_) { | 333 if (alsa_mixer_) { |
334 snd_mixer_close(alsa_mixer_); | 334 snd_mixer_close(alsa_mixer_); |
335 alsa_mixer_ = NULL; | 335 alsa_mixer_ = NULL; |
336 } | 336 } |
337 disconnected_event_.Signal(); | 337 disconnected_event_.Signal(); |
338 } | 338 } |
339 | 339 |
340 void AudioMixerAlsa::ApplyState() { | 340 void AudioMixerAlsa::ApplyState() { |
341 DCHECK(MessageLoop::current() == thread_->message_loop()); | 341 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
342 if (!alsa_mixer_) | 342 if (!alsa_mixer_) |
343 return; | 343 return; |
344 | 344 |
345 bool should_mute = false; | 345 bool should_mute = false; |
346 bool should_mute_capture = false; | 346 bool should_mute_capture = false; |
347 double new_volume_db = 0; | 347 double new_volume_db = 0; |
348 { | 348 { |
349 base::AutoLock lock(lock_); | 349 base::AutoLock lock(lock_); |
350 should_mute = is_muted_; | 350 should_mute = is_muted_; |
351 should_mute_capture = is_capture_muted_; | 351 should_mute_capture = is_capture_muted_; |
(...skipping 18 matching lines...) Expand all Loading... |
370 | 370 |
371 SetElementMuted(master_element_, should_mute); | 371 SetElementMuted(master_element_, should_mute); |
372 if (mic_element_) | 372 if (mic_element_) |
373 SetElementMuted(mic_element_, should_mute_capture); | 373 SetElementMuted(mic_element_, should_mute_capture); |
374 if (front_mic_element_) | 374 if (front_mic_element_) |
375 SetElementMuted(front_mic_element_, should_mute_capture); | 375 SetElementMuted(front_mic_element_, should_mute_capture); |
376 } | 376 } |
377 | 377 |
378 snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName( | 378 snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName( |
379 snd_mixer_t* handle, const string& element_name) const { | 379 snd_mixer_t* handle, const string& element_name) const { |
380 DCHECK(MessageLoop::current() == thread_->message_loop()); | 380 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
381 snd_mixer_selem_id_t* sid = NULL; | 381 snd_mixer_selem_id_t* sid = NULL; |
382 | 382 |
383 // Using id_malloc/id_free API instead of id_alloca since the latter gives the | 383 // Using id_malloc/id_free API instead of id_alloca since the latter gives the |
384 // warning: the address of 'sid' will always evaluate as 'true'. | 384 // warning: the address of 'sid' will always evaluate as 'true'. |
385 if (snd_mixer_selem_id_malloc(&sid)) | 385 if (snd_mixer_selem_id_malloc(&sid)) |
386 return NULL; | 386 return NULL; |
387 | 387 |
388 snd_mixer_selem_id_set_index(sid, 0); | 388 snd_mixer_selem_id_set_index(sid, 0); |
389 snd_mixer_selem_id_set_name(sid, element_name.c_str()); | 389 snd_mixer_selem_id_set_name(sid, element_name.c_str()); |
390 snd_mixer_elem_t* element = snd_mixer_find_selem(handle, sid); | 390 snd_mixer_elem_t* element = snd_mixer_find_selem(handle, sid); |
391 if (!element) | 391 if (!element) |
392 VLOG(1) << "Unable to find control " << snd_mixer_selem_id_get_name(sid); | 392 VLOG(1) << "Unable to find control " << snd_mixer_selem_id_get_name(sid); |
393 | 393 |
394 snd_mixer_selem_id_free(sid); | 394 snd_mixer_selem_id_free(sid); |
395 return element; | 395 return element; |
396 } | 396 } |
397 | 397 |
398 bool AudioMixerAlsa::GetElementVolume(snd_mixer_elem_t* element, | 398 bool AudioMixerAlsa::GetElementVolume(snd_mixer_elem_t* element, |
399 double* current_volume_db) { | 399 double* current_volume_db) { |
400 DCHECK(MessageLoop::current() == thread_->message_loop()); | 400 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
401 alsa_long_t long_volume = 0; | 401 alsa_long_t long_volume = 0; |
402 int alsa_result = snd_mixer_selem_get_playback_dB( | 402 int alsa_result = snd_mixer_selem_get_playback_dB( |
403 element, static_cast<snd_mixer_selem_channel_id_t>(0), &long_volume); | 403 element, static_cast<snd_mixer_selem_channel_id_t>(0), &long_volume); |
404 if (alsa_result != 0) { | 404 if (alsa_result != 0) { |
405 LOG(WARNING) << "snd_mixer_selem_get_playback_dB() failed: " | 405 LOG(WARNING) << "snd_mixer_selem_get_playback_dB() failed: " |
406 << snd_strerror(alsa_result); | 406 << snd_strerror(alsa_result); |
407 return false; | 407 return false; |
408 } | 408 } |
409 *current_volume_db = static_cast<double>(long_volume) / 100.0; | 409 *current_volume_db = static_cast<double>(long_volume) / 100.0; |
410 return true; | 410 return true; |
411 } | 411 } |
412 | 412 |
413 bool AudioMixerAlsa::SetElementVolume(snd_mixer_elem_t* element, | 413 bool AudioMixerAlsa::SetElementVolume(snd_mixer_elem_t* element, |
414 double new_volume_db, | 414 double new_volume_db, |
415 double rounding_bias) { | 415 double rounding_bias) { |
416 DCHECK(MessageLoop::current() == thread_->message_loop()); | 416 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
417 alsa_long_t volume_low = 0; | 417 alsa_long_t volume_low = 0; |
418 alsa_long_t volume_high = 0; | 418 alsa_long_t volume_high = 0; |
419 int alsa_result = snd_mixer_selem_get_playback_volume_range( | 419 int alsa_result = snd_mixer_selem_get_playback_volume_range( |
420 element, &volume_low, &volume_high); | 420 element, &volume_low, &volume_high); |
421 if (alsa_result != 0) { | 421 if (alsa_result != 0) { |
422 LOG(WARNING) << "snd_mixer_selem_get_playback_volume_range() failed: " | 422 LOG(WARNING) << "snd_mixer_selem_get_playback_volume_range() failed: " |
423 << snd_strerror(alsa_result); | 423 << snd_strerror(alsa_result); |
424 return false; | 424 return false; |
425 } | 425 } |
426 alsa_long_t volume_range = volume_high - volume_low; | 426 alsa_long_t volume_range = volume_high - volume_low; |
(...skipping 29 matching lines...) Expand all Loading... |
456 } | 456 } |
457 | 457 |
458 VLOG(1) << "Set volume " << snd_mixer_selem_get_name(element) | 458 VLOG(1) << "Set volume " << snd_mixer_selem_get_name(element) |
459 << " to " << new_volume_db << " ==> " | 459 << " to " << new_volume_db << " ==> " |
460 << (value - volume_low) * db_step + db_low << " dB"; | 460 << (value - volume_low) * db_step + db_low << " dB"; |
461 | 461 |
462 return true; | 462 return true; |
463 } | 463 } |
464 | 464 |
465 void AudioMixerAlsa::SetElementMuted(snd_mixer_elem_t* element, bool mute) { | 465 void AudioMixerAlsa::SetElementMuted(snd_mixer_elem_t* element, bool mute) { |
466 DCHECK(MessageLoop::current() == thread_->message_loop()); | 466 DCHECK(base::MessageLoop::current() == thread_->message_loop()); |
467 int alsa_result = snd_mixer_selem_set_playback_switch_all(element, !mute); | 467 int alsa_result = snd_mixer_selem_set_playback_switch_all(element, !mute); |
468 if (alsa_result != 0) { | 468 if (alsa_result != 0) { |
469 LOG(WARNING) << "snd_mixer_selem_set_playback_switch_all() failed: " | 469 LOG(WARNING) << "snd_mixer_selem_set_playback_switch_all() failed: " |
470 << snd_strerror(alsa_result); | 470 << snd_strerror(alsa_result); |
471 } else { | 471 } else { |
472 VLOG(1) << "Set playback switch " << snd_mixer_selem_get_name(element) | 472 VLOG(1) << "Set playback switch " << snd_mixer_selem_get_name(element) |
473 << " to " << mute; | 473 << " to " << mute; |
474 } | 474 } |
475 } | 475 } |
476 | 476 |
(...skipping 14 matching lines...) Expand all Loading... |
491 void AudioMixerAlsa::ApplyStateIfNeeded() { | 491 void AudioMixerAlsa::ApplyStateIfNeeded() { |
492 lock_.AssertAcquired(); | 492 lock_.AssertAcquired(); |
493 if (!apply_is_pending_) { | 493 if (!apply_is_pending_) { |
494 thread_->message_loop()->PostTask( | 494 thread_->message_loop()->PostTask( |
495 FROM_HERE, | 495 FROM_HERE, |
496 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this))); | 496 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this))); |
497 } | 497 } |
498 } | 498 } |
499 | 499 |
500 } // namespace chromeos | 500 } // namespace chromeos |
OLD | NEW |