| 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 |
| 11 #include <algorithm> | 11 #include <algorithm> |
| 12 #include <cmath> | 12 #include <cmath> |
| 13 | 13 |
| 14 #include "base/bind.h" | 14 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 15 #include "base/bind_helpers.h" |
| 16 #include "base/callback.h" |
| 16 #include "base/chromeos/chromeos_version.h" | 17 #include "base/chromeos/chromeos_version.h" |
| 17 #include "base/logging.h" | 18 #include "base/logging.h" |
| 18 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
| 19 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
| 20 #include "base/threading/thread_restrictions.h" | 21 #include "base/threading/thread_restrictions.h" |
| 21 #include "chrome/browser/speech/extension_api/tts_extension_api_chromeos.h" | |
| 22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
| 23 | 23 |
| 24 typedef long alsa_long_t; // 'long' is required for ALSA API calls. | 24 typedef long alsa_long_t; // 'long' is required for ALSA API calls. |
| 25 | 25 |
| 26 using content::BrowserThread; | 26 using content::BrowserThread; |
| 27 using std::string; | 27 using std::string; |
| 28 | 28 |
| 29 namespace chromeos { | 29 namespace chromeos { |
| 30 | 30 |
| 31 namespace { | 31 namespace { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 // http://crbug.com/125206 | 97 // http://crbug.com/125206 |
| 98 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 98 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 99 disconnected_event_.Wait(); | 99 disconnected_event_.Wait(); |
| 100 } | 100 } |
| 101 | 101 |
| 102 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join; | 102 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join; |
| 103 thread_->Stop(); | 103 thread_->Stop(); |
| 104 thread_.reset(); | 104 thread_.reset(); |
| 105 } | 105 } |
| 106 | 106 |
| 107 void AudioMixerAlsa::Init() { | 107 void AudioMixerAlsa::Init(const base::Closure& on_connected) { |
| 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 109 DCHECK(!thread_.get()) << "Init() called twice"; | 109 DCHECK(!thread_.get()) << "Init() called twice"; |
| 110 thread_.reset(new base::Thread("AudioMixerAlsa")); | 110 thread_.reset(new base::Thread("AudioMixerAlsa")); |
| 111 CHECK(thread_->Start()); | 111 CHECK(thread_->Start()); |
| 112 thread_->message_loop()->PostTask( | 112 thread_->message_loop()->PostTask( |
| 113 FROM_HERE, base::Bind(&AudioMixerAlsa::Connect, base::Unretained(this))); | 113 FROM_HERE, base::Bind(&AudioMixerAlsa::Connect, |
| 114 base::Unretained(this), |
| 115 on_connected)); |
| 114 } | 116 } |
| 115 | 117 |
| 116 double AudioMixerAlsa::GetVolumePercent() { | 118 double AudioMixerAlsa::GetVolumePercent() { |
| 117 base::AutoLock lock(lock_); | 119 base::AutoLock lock(lock_); |
| 118 return !alsa_mixer_ ? | 120 return !alsa_mixer_ ? |
| 119 initial_volume_percent_ : | 121 initial_volume_percent_ : |
| 120 DbToPercent(volume_db_); | 122 DbToPercent(volume_db_); |
| 121 } | 123 } |
| 122 | 124 |
| 123 void AudioMixerAlsa::SetVolumePercent(double percent) { | 125 void AudioMixerAlsa::SetVolumePercent(double percent) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 base::AutoLock lock(lock_); | 185 base::AutoLock lock(lock_); |
| 184 return is_capture_mute_locked_; | 186 return is_capture_mute_locked_; |
| 185 } | 187 } |
| 186 | 188 |
| 187 void AudioMixerAlsa::SetCaptureMuteLocked(bool locked) { | 189 void AudioMixerAlsa::SetCaptureMuteLocked(bool locked) { |
| 188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 189 base::AutoLock lock(lock_); | 191 base::AutoLock lock(lock_); |
| 190 is_capture_mute_locked_ = locked; | 192 is_capture_mute_locked_ = locked; |
| 191 } | 193 } |
| 192 | 194 |
| 193 void AudioMixerAlsa::Connect() { | 195 void AudioMixerAlsa::Connect(const base::Closure& on_connected) { |
| 194 DCHECK(MessageLoop::current() == thread_->message_loop()); | 196 DCHECK(MessageLoop::current() == thread_->message_loop()); |
| 195 DCHECK(!alsa_mixer_); | 197 DCHECK(!alsa_mixer_); |
| 196 | 198 |
| 197 if (disconnected_event_.IsSignaled()) | 199 if (disconnected_event_.IsSignaled()) |
| 198 return; | 200 return; |
| 199 | 201 |
| 200 // Do not attempt to connect if we're not on the device. | 202 // Do not attempt to connect if we're not on the device. |
| 201 if (!base::chromeos::IsRunningOnChromeOS()) | 203 if (!base::chromeos::IsRunningOnChromeOS()) |
| 202 return; | 204 return; |
| 203 | 205 |
| 204 if (!ConnectInternal()) { | 206 if (!ConnectInternal(on_connected)) { |
| 205 thread_->message_loop()->PostDelayedTask(FROM_HERE, | 207 thread_->message_loop()->PostDelayedTask( |
| 206 base::Bind(&AudioMixerAlsa::Connect, base::Unretained(this)), | 208 FROM_HERE, |
| 209 base::Bind(&AudioMixerAlsa::Connect, |
| 210 base::Unretained(this), |
| 211 on_connected), |
| 207 base::TimeDelta::FromSeconds(kConnectionRetrySleepSec)); | 212 base::TimeDelta::FromSeconds(kConnectionRetrySleepSec)); |
| 208 } | 213 } |
| 209 } | 214 } |
| 210 | 215 |
| 211 bool AudioMixerAlsa::ConnectInternal() { | 216 bool AudioMixerAlsa::ConnectInternal(const base::Closure& on_connected) { |
| 212 DCHECK(MessageLoop::current() == thread_->message_loop()); | 217 DCHECK(MessageLoop::current() == thread_->message_loop()); |
| 213 num_connection_attempts_++; | 218 num_connection_attempts_++; |
| 214 int err; | 219 int err; |
| 215 snd_mixer_t* handle = NULL; | 220 snd_mixer_t* handle = NULL; |
| 216 | 221 |
| 217 if ((err = snd_mixer_open(&handle, 0)) < 0) { | 222 if ((err = snd_mixer_open(&handle, 0)) < 0) { |
| 218 if (num_connection_attempts_ == kConnectionAttemptToLogFailure) | 223 if (num_connection_attempts_ == kConnectionAttemptToLogFailure) |
| 219 LOG(WARNING) << "Mixer open error: " << snd_strerror(err); | 224 LOG(WARNING) << "Mixer open error: " << snd_strerror(err); |
| 220 return false; | 225 return false; |
| 221 } | 226 } |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 alsa_mixer_ = handle; | 323 alsa_mixer_ = handle; |
| 319 master_element_ = master_element; | 324 master_element_ = master_element; |
| 320 pcm_element_ = pcm_element; | 325 pcm_element_ = pcm_element; |
| 321 mic_element_ = mic_element; | 326 mic_element_ = mic_element; |
| 322 front_mic_element_ = front_mic_element; | 327 front_mic_element_ = front_mic_element; |
| 323 min_volume_db_ = min_volume_db; | 328 min_volume_db_ = min_volume_db; |
| 324 max_volume_db_ = max_volume_db; | 329 max_volume_db_ = max_volume_db; |
| 325 volume_db_ = PercentToDb(initial_volume_percent_); | 330 volume_db_ = PercentToDb(initial_volume_percent_); |
| 326 } | 331 } |
| 327 | 332 |
| 328 // The speech synthesis service shouldn't be initialized until after | 333 on_connected.Run(); |
| 329 // we get to this point, so we call this function to tell it that it's | |
| 330 // safe to do TTS now. NotificationService would be cleaner, | |
| 331 // but it's not available at this point. | |
| 332 EnableChromeOsTts(); | |
| 333 | 334 |
| 334 ApplyState(); | 335 ApplyState(); |
| 335 return true; | 336 return true; |
| 336 } | 337 } |
| 337 | 338 |
| 338 void AudioMixerAlsa::Disconnect() { | 339 void AudioMixerAlsa::Disconnect() { |
| 339 DCHECK(MessageLoop::current() == thread_->message_loop()); | 340 DCHECK(MessageLoop::current() == thread_->message_loop()); |
| 340 if (alsa_mixer_) { | 341 if (alsa_mixer_) { |
| 341 snd_mixer_close(alsa_mixer_); | 342 snd_mixer_close(alsa_mixer_); |
| 342 alsa_mixer_ = NULL; | 343 alsa_mixer_ = NULL; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 void AudioMixerAlsa::ApplyStateIfNeeded() { | 499 void AudioMixerAlsa::ApplyStateIfNeeded() { |
| 499 lock_.AssertAcquired(); | 500 lock_.AssertAcquired(); |
| 500 if (!apply_is_pending_) { | 501 if (!apply_is_pending_) { |
| 501 thread_->message_loop()->PostTask( | 502 thread_->message_loop()->PostTask( |
| 502 FROM_HERE, | 503 FROM_HERE, |
| 503 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this))); | 504 base::Bind(&AudioMixerAlsa::ApplyState, base::Unretained(this))); |
| 504 } | 505 } |
| 505 } | 506 } |
| 506 | 507 |
| 507 } // namespace chromeos | 508 } // namespace chromeos |
| OLD | NEW |