| 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..bea9173a4affd0eae636990b2b17cb880e03d8a1 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,73 @@ void AudioHandler::SetMute(bool do_mute) {
|
| mixer_->SetMute(do_mute);
|
| }
|
|
|
| +bool AudioHandler::TryToConnect(bool async) {
|
| + if (mixer_type_ == MIXER_TYPE_PULSEAUDIO) {
|
| + VLOG(1) << "Trying to connect to PulseAudio";
|
| + mixer_.reset(new AudioMixerPulse());
|
| + } else if (mixer_type_ == 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 (mixer_type_ == MIXER_TYPE_PULSEAUDIO)
|
| + mixer_type_ = MIXER_TYPE_ALSA;
|
| + else
|
| + mixer_type_ = 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),
|
| + mixer_type_(MIXER_TYPE_PULSEAUDIO) {
|
| + while (mixer_type_ != MIXER_TYPE_NONE) {
|
| + if (TryToConnect(true))
|
| + break;
|
| + UseNextMixer();
|
| }
|
| }
|
|
|
| @@ -115,58 +170,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
|
|
|