Chromium Code Reviews| Index: chrome/browser/chromeos/audio_handler.cc |
| diff --git a/chrome/browser/chromeos/audio_handler.cc b/chrome/browser/chromeos/audio_handler.cc |
| index f8ad726747daa6feef40eb861116bd8fc43442ff..bfcb4954bcfeab3abf48eadb236bcfe18a6b3703 100644 |
| --- a/chrome/browser/chromeos/audio_handler.cc |
| +++ b/chrome/browser/chromeos/audio_handler.cc |
| @@ -8,13 +8,14 @@ |
| #include "base/logging.h" |
| #include "base/singleton.h" |
| -#include "chrome/browser/chromeos/pulse_audio_mixer.h" |
| +#include "chrome/browser/chromeos/audio_mixer_alsa.h" |
| +#include "chrome/browser/chromeos/audio_mixer_pulse.h" |
| +#include "chrome/browser/browser_thread.h" |
| namespace chromeos { |
| namespace { |
| -const double kSilenceDb = -200.0; |
| const double kMinVolumeDb = -90.0; |
| // Choosing 6.0dB here instead of 0dB to give user chance to amplify audio some |
| // in case sounds or their setup is too quiet for them. |
| @@ -27,10 +28,8 @@ const int kMaxReconnectTries = 4; |
| } // namespace |
| -// This class will set volume using PulseAudio to adjust volume and mute, and |
| -// handles the volume level logic. |
| - |
| -// TODO(davej): Serialize volume/mute for next startup? |
| +// This class will set volume using PulseAudio or ALSA to adjust volume and |
| +// mute, and handles the volume level logic. |
| double AudioHandler::GetVolumePercent() { |
| if (!VerifyMixerConnection()) |
| @@ -40,7 +39,7 @@ double AudioHandler::GetVolumePercent() { |
| } |
| // Set volume using our internal 0-100% range. Notice 0% is a special case of |
| -// silence, so we set the mixer volume to kSilenceDb instead of kMinVolumeDb. |
| +// silence, so we set the mixer volume to kSilenceDb instead of min_volume_db_. |
| void AudioHandler::SetVolumePercent(double volume_percent) { |
| if (!VerifyMixerConnection()) |
| return; |
| @@ -48,7 +47,7 @@ void AudioHandler::SetVolumePercent(double volume_percent) { |
| double vol_db; |
| if (volume_percent <= 0) |
| - vol_db = kSilenceDb; |
| + vol_db = AudioMixer::kSilenceDb; |
| else |
| vol_db = PercentToVolumeDb(volume_percent); |
| @@ -72,7 +71,7 @@ void AudioHandler::AdjustVolumeByPercent(double adjust_by_percent) { |
| double new_volume; |
| if (pct <= 0.1) |
| - new_volume = kSilenceDb; |
| + new_volume = AudioMixer::kSilenceDb; |
| else |
| new_volume = PercentToVolumeDb(pct); |
| @@ -96,17 +95,74 @@ void AudioHandler::SetMute(bool do_mute) { |
| mixer_->SetMute(do_mute); |
| } |
| +bool AudioHandler::TryToConnect(bool async) { |
| + if (using_mixer_ == MIXER_TYPE_PULSEAUDIO) { |
| + VLOG(1) << "Trying to connect to PulseAudio"; |
| + mixer_.reset(new AudioMixerPulse()); |
| + } else if (using_mixer_ == MIXER_TYPE_ALSA) { |
| + VLOG(1) << "Trying to connect to ALSA"; |
| + mixer_.reset(new AudioMixerAlsa()); |
| + } else { |
| + VLOG(1) << "Cannot find valid volume mixer"; |
| + mixer_.reset(); |
| + return false; |
| + } |
| + |
| + if (async) { |
| + if (!mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized))) |
| + return false; |
| + } else { |
| + if (!mixer_->InitSync()) { |
| + VLOG(1) << "Unable to reconnect to Mixer"; |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +void AudioHandler::UseNextMixer() { |
| + if (using_mixer_ == MIXER_TYPE_PULSEAUDIO) |
| + using_mixer_ = MIXER_TYPE_ALSA; |
| + else |
| + using_mixer_ = MIXER_TYPE_NONE; |
| +} |
| + |
| +static void ClipVolume(double* min_volume, double* max_volume) { |
| + if (*min_volume < kMinVolumeDb) |
| + *min_volume = kMinVolumeDb; |
| + if (*max_volume > kMaxVolumeDb) |
| + *max_volume = kMaxVolumeDb; |
| +} |
| + |
| void AudioHandler::OnMixerInitialized(bool success) { |
| connected_ = success; |
| DVLOG(1) << "OnMixerInitialized, success = " << success; |
| + |
| + if (connected_) { |
| + if (mixer_->GetVolumeLimits(&min_volume_db_, &max_volume_db_)) { |
| + ClipVolume(&min_volume_db_, &max_volume_db_); |
| + } |
| + } else { |
| + UseNextMixer(); |
| + VLOG(1) << "Unable to connect to mixer, trying next"; |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + NewRunnableMethod(this, &AudioHandler::TryToConnect, true)); |
| + } |
| } |
| AudioHandler::AudioHandler() |
| : connected_(false), |
| - reconnect_tries_(0) { |
| - mixer_.reset(new PulseAudioMixer()); |
| - if (!mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized))) { |
| - LOG(ERROR) << "Unable to connect to PulseAudio"; |
| + reconnect_tries_(0), |
| + max_volume_db_(0), |
| + min_volume_db_(-90), |
| + using_mixer_(MIXER_TYPE_PULSEAUDIO) { |
| + while (using_mixer_ != MIXER_TYPE_NONE) { |
| + if (TryToConnect(true)) { |
|
Daniel Erat
2011/01/05 01:06:53
I think that Chrome style is to omit curly braces
|
| + break; |
| + } |
| + UseNextMixer(); |
| } |
| } |
| @@ -115,58 +171,62 @@ AudioHandler::~AudioHandler() { |
| }; |
| bool AudioHandler::VerifyMixerConnection() { |
| - PulseAudioMixer::State mixer_state = mixer_->CheckState(); |
| - if (mixer_state == PulseAudioMixer::READY) |
| + if (mixer_ == NULL) |
| + return false; |
| + |
| + AudioMixer::State mixer_state = mixer_->CheckState(); |
| + if (mixer_state == AudioMixer::READY) |
| return true; |
| if (connected_) { |
| // Something happened and the mixer is no longer valid after having been |
| // initialized earlier. |
| connected_ = false; |
| - LOG(ERROR) << "Lost connection to PulseAudio"; |
| + LOG(ERROR) << "Lost connection to mixer"; |
| } else { |
| LOG(ERROR) << "Mixer not valid"; |
| } |
| - if ((mixer_state == PulseAudioMixer::INITIALIZING) || |
| - (mixer_state == PulseAudioMixer::SHUTTING_DOWN)) |
| + if ((mixer_state == AudioMixer::INITIALIZING) || |
| + (mixer_state == AudioMixer::SHUTTING_DOWN)) |
| return false; |
| if (reconnect_tries_ < kMaxReconnectTries) { |
| reconnect_tries_++; |
| - VLOG(1) << "Re-connecting to PulseAudio attempt " << reconnect_tries_ << "/" |
| + VLOG(1) << "Re-connecting to mixer attempt " << reconnect_tries_ << "/" |
| << kMaxReconnectTries; |
| - mixer_.reset(new PulseAudioMixer()); |
| - connected_ = mixer_->InitSync(); |
| + |
| + connected_ = TryToConnect(false); |
| + |
| if (connected_) { |
| reconnect_tries_ = 0; |
| return true; |
| } |
| - LOG(ERROR) << "Unable to re-connect to PulseAudio"; |
| + LOG(ERROR) << "Unable to re-connect to mixer"; |
| } |
| return false; |
| } |
| // VolumeDbToPercent() and PercentToVolumeDb() conversion functions allow us |
| // complete control over how the 0 to 100% range is mapped to actual loudness. |
| -// Volume range is from kMinVolumeDb at just above 0% to kMaxVolumeDb at 100% |
| -// with a special case at 0% which maps to kSilenceDb. |
| +// Volume range is from min_volume_db_ at just above 0% to max_volume_db_ |
| +// at 100% with a special case at 0% which maps to kSilenceDb. |
| // |
| // The mapping is confined to these two functions to make it easy to adjust and |
| // have everything else just work. The range is biased to give finer resolution |
| // in the higher volumes if kVolumeBias is less than 1.0. |
| // static |
| -double AudioHandler::VolumeDbToPercent(double volume_db) { |
| - if (volume_db < kMinVolumeDb) |
| +double AudioHandler::VolumeDbToPercent(double volume_db) const { |
| + if (volume_db < min_volume_db_) |
| return 0; |
| - return 100.0 * pow((volume_db - kMinVolumeDb) / |
| - (kMaxVolumeDb - kMinVolumeDb), 1/kVolumeBias); |
| + return 100.0 * pow((volume_db - min_volume_db_) / |
| + (max_volume_db_ - min_volume_db_), 1/kVolumeBias); |
| } |
| // static |
| -double AudioHandler::PercentToVolumeDb(double volume_percent) { |
| +double AudioHandler::PercentToVolumeDb(double volume_percent) const { |
| return pow(volume_percent / 100.0, kVolumeBias) * |
| - (kMaxVolumeDb - kMinVolumeDb) + kMinVolumeDb; |
| + (max_volume_db_ - min_volume_db_) + min_volume_db_; |
| } |
| // static |