| 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 |