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..7e5d4b92a1f6aa83029dbaa44f9be018e67ae850 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/browser_thread.h" |
+#include "chrome/browser/chromeos/audio_mixer_alsa.h" |
+#include "chrome/browser/chromeos/audio_mixer_pulse.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); |
@@ -90,24 +89,78 @@ bool AudioHandler::IsMute() { |
void AudioHandler::SetMute(bool do_mute) { |
if (!VerifyMixerConnection()) |
return; |
- |
DVLOG(1) << "Setting Mute to " << 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) { |
+ mixer_->Init(NewCallback(this, &AudioHandler::OnMixerInitialized)); |
+ } 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_); |
+ } |
+ return; |
+ } |
+ |
+ VLOG(1) << "Unable to connect to mixer, trying next"; |
+ UseNextMixer(); |
+ |
+ 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_(kMaxVolumeDb), |
+ min_volume_db_(kMinVolumeDb), |
+ mixer_type_(MIXER_TYPE_PULSEAUDIO) { |
+ |
+ // Start trying to connect to mixers asychronously, starting with the current |
+ // mixer_type_. If the connection fails, another TryToConnect() for the next |
+ // mixer will be posted at that time. |
+ TryToConnect(true); |
} |
AudioHandler::~AudioHandler() { |
@@ -115,58 +168,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_->GetState(); |
+ 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 |