summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authordavej@chromium.org <davej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-12 00:21:14 +0000
committerdavej@chromium.org <davej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-12 00:21:14 +0000
commit51dfe5e3b332bcea02fb4d4c7493ae841106dd9b (patch)
tree2a4ed1f83aa81ccd0e7caf62563d85f4e1195241 /chrome
parentb23d013406dea1c43a82738c6887a7b6a7959538 (diff)
downloadchromium_src-51dfe5e3b332bcea02fb4d4c7493ae841106dd9b.zip
chromium_src-51dfe5e3b332bcea02fb4d4c7493ae841106dd9b.tar.gz
chromium_src-51dfe5e3b332bcea02fb4d4c7493ae841106dd9b.tar.bz2
Add ALSA support to volume keys
If PulseAudio is running, everything should behave as before, otherwise use ALSA API for adjusting volume. The previous PulseAudioMixer was split into AudioMixerBase and audioMixerPusle, then AudioMixerAlsa was added. BUG=chromium-os:10470 TEST=Volume keys should work even if pulseaudio disabled Review URL: http://codereview.chromium.org/5859003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71115 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/chromeos/audio_handler.cc123
-rw-r--r--chrome/browser/chromeos/audio_handler.h32
-rw-r--r--chrome/browser/chromeos/audio_mixer.h67
-rw-r--r--chrome/browser/chromeos/audio_mixer_alsa.cc366
-rw-r--r--chrome/browser/chromeos/audio_mixer_alsa.h100
-rw-r--r--chrome/browser/chromeos/audio_mixer_pulse.cc (renamed from chrome/browser/chromeos/pulse_audio_mixer.cc)116
-rw-r--r--chrome/browser/chromeos/audio_mixer_pulse.h (renamed from chrome/browser/chromeos/pulse_audio_mixer.h)66
-rw-r--r--chrome/chrome_browser.gypi7
8 files changed, 734 insertions, 143 deletions
diff --git a/chrome/browser/chromeos/audio_handler.cc b/chrome/browser/chromeos/audio_handler.cc
index f8ad726..7e5d4b9 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
diff --git a/chrome/browser/chromeos/audio_handler.h b/chrome/browser/chromeos/audio_handler.h
index 59e9d70..b835f5a 100644
--- a/chrome/browser/chromeos/audio_handler.h
+++ b/chrome/browser/chromeos/audio_handler.h
@@ -8,12 +8,13 @@
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
+#include "base/threading/thread.h"
template <typename T> struct DefaultSingletonTraits;
namespace chromeos {
-class PulseAudioMixer;
+class AudioMixer;
class AudioHandler {
public:
@@ -30,7 +31,7 @@ class AudioHandler {
// as the percentage gets lower, and then switches to silence at 0%.
void SetVolumePercent(double volume_percent);
- // Adust volume up (positive percentage) or down (negative percentage),
+ // Adjust volume up (positive percentage) or down (negative percentage),
// capping at 100%. GetVolumePercent() will be accurate after this
// blocking call.
void AdjustVolumeByPercent(double adjust_by_percent);
@@ -43,10 +44,20 @@ class AudioHandler {
void SetMute(bool do_mute);
private:
+ enum MixerType {
+ MIXER_TYPE_PULSEAUDIO = 0,
+ MIXER_TYPE_ALSA,
+ MIXER_TYPE_NONE,
+ };
+
// Defines the delete on exit Singleton traits we like. Best to have this
// and constructor/destructor private as recommended for Singletons.
friend struct DefaultSingletonTraits<AudioHandler>;
+ // Connect to the current mixer_type_.
+ bool TryToConnect(bool async);
+ void UseNextMixer();
+
void OnMixerInitialized(bool success);
AudioHandler();
@@ -54,17 +65,28 @@ class AudioHandler {
bool VerifyMixerConnection();
// Conversion between our internal scaling (0-100%) and decibels.
- static double VolumeDbToPercent(double volume_db);
- static double PercentToVolumeDb(double volume_percent);
+ double VolumeDbToPercent(double volume_db) const;
+ double PercentToVolumeDb(double volume_percent) const;
+
+ scoped_ptr<AudioMixer> mixer_;
- scoped_ptr<PulseAudioMixer> mixer_;
bool connected_;
int reconnect_tries_;
+ // The min and max volume in decibels, limited to the maximum range of the
+ // audio system being used.
+ double max_volume_db_;
+ double min_volume_db_;
+
+ // Which mixer is being used, PulseAudio, ALSA or none.
+ MixerType mixer_type_;
+
DISALLOW_COPY_AND_ASSIGN(AudioHandler);
};
} // namespace chromeos
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::AudioHandler);
+
#endif // CHROME_BROWSER_CHROMEOS_AUDIO_HANDLER_H_
diff --git a/chrome/browser/chromeos/audio_mixer.h b/chrome/browser/chromeos/audio_mixer.h
new file mode 100644
index 0000000..b77e827
--- /dev/null
+++ b/chrome/browser/chromeos/audio_mixer.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_H_
+#define CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+
+namespace chromeos {
+
+class AudioMixer {
+ public:
+ // Approximation of pure silence expressed in decibels.
+ static const double kSilenceDb = -200.0;
+
+ enum State {
+ UNINITIALIZED = 0,
+ INITIALIZING,
+ READY,
+ SHUTTING_DOWN,
+ IN_ERROR,
+ };
+
+ AudioMixer() {}
+ virtual ~AudioMixer() {}
+
+ // Non-Blocking call. Connect to Mixer, find a default device, then call the
+ // callback when complete with success code.
+ typedef Callback1<bool>::Type InitDoneCallback;
+ virtual void Init(InitDoneCallback* callback) = 0;
+
+ // Call may block. Mixer will be connected before returning, unless error.
+ virtual bool InitSync() = 0;
+
+ // Call may block. Returns a default of kSilenceDb on error.
+ virtual double GetVolumeDb() const = 0;
+
+ // Non-Blocking call. Returns the actual volume limits possible according
+ // to the mixer. Limits are left unchanged on error
+ virtual bool GetVolumeLimits(double* vol_min, double* vol_max) = 0;
+
+ // Non-blocking call.
+ virtual void SetVolumeDb(double vol_db) = 0;
+
+ // Call may block. Gets the mute state of the default device (true == mute).
+ // Returns a default of false on error.
+ virtual bool IsMute() const = 0;
+
+ // Non-Blocking call.
+ virtual void SetMute(bool mute) = 0;
+
+ // Returns READY if we have a valid working connection to the Mixer.
+ // This can return IN_ERROR if we lose the connection, even after an original
+ // successful init. Non-blocking call.
+ virtual State GetState() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AudioMixer);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_H_
+
diff --git a/chrome/browser/chromeos/audio_mixer_alsa.cc b/chrome/browser/chromeos/audio_mixer_alsa.cc
new file mode 100644
index 0000000..7f96fa4
--- /dev/null
+++ b/chrome/browser/chromeos/audio_mixer_alsa.cc
@@ -0,0 +1,366 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/audio_mixer_alsa.h"
+
+#include <alsa/asoundlib.h>
+
+#include "base/logging.h"
+#include "base/task.h"
+
+namespace chromeos {
+
+// Connect to the ALSA mixer using their simple element API. Init is performed
+// asynchronously on the worker thread.
+//
+// To get a wider range and finer control over volume levels, first the Master
+// level is set, then if the PCM element exists, the total level is refined by
+// adjusting that as well. If the PCM element has more volume steps, it allows
+// for finer granularity in the total volume.
+
+// TODO(davej): Serialize volume/mute to preserve settings when restarting.
+
+typedef long alsa_long_t; // 'long' is required for ALSA API calls.
+
+namespace {
+
+const char* kMasterVolume = "Master";
+const char* kPCMVolume = "PCM";
+const double kDefaultMinVolume = -90.0;
+const double kDefaultMaxVolume = 0.0;
+
+} // namespace
+
+AudioMixerAlsa::AudioMixerAlsa()
+ : min_volume_(kDefaultMinVolume),
+ max_volume_(kDefaultMaxVolume),
+ save_volume_(0),
+ mixer_state_(UNINITIALIZED),
+ alsa_mixer_(NULL),
+ elem_master_(NULL),
+ elem_pcm_(NULL) {
+}
+
+AudioMixerAlsa::~AudioMixerAlsa() {
+ FreeAlsaMixer();
+ if (thread_ != NULL) {
+ thread_->Stop();
+ thread_.reset();
+ }
+}
+
+void AudioMixerAlsa::Init(InitDoneCallback* callback) {
+ DCHECK(callback);
+ if (!InitThread()) {
+ callback->Run(false);
+ delete callback;
+ return;
+ }
+
+ // Post the task of starting up, which can block for 200-500ms,
+ // so best not to do it on the caller's thread.
+ thread_->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &AudioMixerAlsa::DoInit, callback));
+}
+
+bool AudioMixerAlsa::InitSync() {
+ if (!InitThread())
+ return false;
+ return InitializeAlsaMixer();
+}
+
+double AudioMixerAlsa::GetVolumeDb() const {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != READY)
+ return kSilenceDb;
+
+ return DoGetVolumeDb_Locked();
+}
+
+bool AudioMixerAlsa::GetVolumeLimits(double* vol_min, double* vol_max) {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != READY)
+ return false;
+ if (vol_min)
+ *vol_min = min_volume_;
+ if (vol_max)
+ *vol_max = max_volume_;
+ return true;
+}
+
+void AudioMixerAlsa::SetVolumeDb(double vol_db) {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != READY)
+ return;
+ DoSetVolumeDb_Locked(vol_db);
+}
+
+bool AudioMixerAlsa::IsMute() const {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != READY)
+ return false;
+ return GetElementMuted_Locked(elem_master_);
+}
+
+void AudioMixerAlsa::SetMute(bool mute) {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != READY)
+ return;
+
+ // Set volume to minimum on mute, since switching the element off does not
+ // always mute as it should.
+
+ // TODO(davej): Setting volume to minimum can be removed once switching the
+ // element off can be guaranteed to work.
+
+ bool old_value = GetElementMuted_Locked(elem_master_);
+
+ if (old_value != mute) {
+ if (mute) {
+ save_volume_ = DoGetVolumeDb_Locked();
+ DoSetVolumeDb_Locked(min_volume_);
+ } else {
+ DoSetVolumeDb_Locked(save_volume_);
+ }
+ }
+
+ SetElementMuted_Locked(elem_master_, mute);
+ if (elem_pcm_)
+ SetElementMuted_Locked(elem_pcm_, mute);
+}
+
+AudioMixer::State AudioMixerAlsa::GetState() const {
+ AutoLock lock(mixer_state_lock_);
+ // If we think it's ready, verify it is actually so.
+ if ((mixer_state_ == READY) && (alsa_mixer_ == NULL))
+ mixer_state_ = IN_ERROR;
+ return mixer_state_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private functions follow
+
+void AudioMixerAlsa::DoInit(InitDoneCallback* callback) {
+ bool success = InitializeAlsaMixer();
+
+ if (callback) {
+ callback->Run(success);
+ delete callback;
+ }
+}
+
+bool AudioMixerAlsa::InitThread() {
+ AutoLock lock(mixer_state_lock_);
+
+ if (mixer_state_ != UNINITIALIZED)
+ return false;
+
+ if (thread_ == NULL) {
+ thread_.reset(new base::Thread("AudioMixerAlsa"));
+ if (!thread_->Start()) {
+ thread_.reset();
+ return false;
+ }
+ }
+
+ mixer_state_ = INITIALIZING;
+ return true;
+}
+
+bool AudioMixerAlsa::InitializeAlsaMixer() {
+ AutoLock lock(mixer_state_lock_);
+ if (mixer_state_ != INITIALIZING)
+ return false;
+
+ int err;
+ snd_mixer_t* handle = NULL;
+ const char* card = "default";
+
+ if ((err = snd_mixer_open(&handle, 0)) < 0) {
+ LOG(ERROR) << "ALSA mixer " << card << " open error: " << snd_strerror(err);
+ return false;
+ }
+
+ if ((err = snd_mixer_attach(handle, card)) < 0) {
+ LOG(ERROR) << "ALSA Attach to card " << card << " failed: "
+ << snd_strerror(err);
+ snd_mixer_close(handle);
+ return false;
+ }
+
+ if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
+ LOG(ERROR) << "ALSA mixer register error: " << snd_strerror(err);
+ snd_mixer_close(handle);
+ return false;
+ }
+
+ if ((err = snd_mixer_load(handle)) < 0) {
+ LOG(ERROR) << "ALSA mixer " << card << " load error: %s"
+ << snd_strerror(err);
+ snd_mixer_close(handle);
+ return false;
+ }
+
+ VLOG(1) << "Opened ALSA mixer " << card << " OK";
+
+ elem_master_ = FindElementWithName_Locked(handle, kMasterVolume);
+ if (elem_master_) {
+ alsa_long_t long_lo, long_hi;
+ snd_mixer_selem_get_playback_dB_range(elem_master_, &long_lo, &long_hi);
+ min_volume_ = static_cast<double>(long_lo) / 100.0;
+ max_volume_ = static_cast<double>(long_hi) / 100.0;
+ } else {
+ LOG(ERROR) << "Cannot find 'Master' ALSA mixer element on " << card;
+ snd_mixer_close(handle);
+ return false;
+ }
+
+ elem_pcm_ = FindElementWithName_Locked(handle, kPCMVolume);
+ if (elem_pcm_) {
+ alsa_long_t long_lo, long_hi;
+ snd_mixer_selem_get_playback_dB_range(elem_pcm_, &long_lo, &long_hi);
+ min_volume_ += static_cast<double>(long_lo) / 100.0;
+ max_volume_ += static_cast<double>(long_hi) / 100.0;
+ }
+
+ VLOG(1) << "ALSA volume range is " << min_volume_ << " dB to "
+ << max_volume_ << " dB";
+
+ alsa_mixer_ = handle;
+ mixer_state_ = READY;
+ return true;
+}
+
+void AudioMixerAlsa::FreeAlsaMixer() {
+ AutoLock lock(mixer_state_lock_);
+ mixer_state_ = SHUTTING_DOWN;
+ if (alsa_mixer_) {
+ snd_mixer_close(alsa_mixer_);
+ alsa_mixer_ = NULL;
+ }
+}
+
+double AudioMixerAlsa::DoGetVolumeDb_Locked() const {
+ double vol_total = 0.0;
+ GetElementVolume_Locked(elem_master_, &vol_total);
+
+ double vol_pcm = 0.0;
+ if (elem_pcm_ && (GetElementVolume_Locked(elem_pcm_, &vol_pcm)))
+ vol_total += vol_pcm;
+
+ return vol_total;
+}
+
+void AudioMixerAlsa::DoSetVolumeDb_Locked(double vol_db) {
+ double actual_vol = 0.0;
+
+ // If a PCM volume slider exists, then first set the Master volume to the
+ // nearest volume >= requested volume, then adjust PCM volume down to get
+ // closer to the requested volume.
+
+ if (elem_pcm_) {
+ SetElementVolume_Locked(elem_master_, vol_db, &actual_vol, 0.9999f);
+ SetElementVolume_Locked(elem_pcm_, vol_db - actual_vol, NULL, 0.5f);
+ } else {
+ SetElementVolume_Locked(elem_master_, vol_db, NULL, 0.5f);
+ }
+}
+
+snd_mixer_elem_t* AudioMixerAlsa::FindElementWithName_Locked(
+ snd_mixer_t* handle,
+ const char* element_name) const {
+ snd_mixer_selem_id_t* sid;
+
+ // Using id_malloc/id_free API instead of id_alloca since the latter gives the
+ // warning: the address of 'sid' will always evaluate as 'true'
+ if (snd_mixer_selem_id_malloc(&sid))
+ return NULL;
+
+ snd_mixer_selem_id_set_index(sid, 0);
+ snd_mixer_selem_id_set_name(sid, element_name);
+ snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
+ if (!elem) {
+ LOG(ERROR) << "ALSA unable to find simple control "
+ << snd_mixer_selem_id_get_name(sid);
+ }
+
+ snd_mixer_selem_id_free(sid);
+ return elem;
+}
+
+bool AudioMixerAlsa::GetElementVolume_Locked(snd_mixer_elem_t* elem,
+ double* current_vol) const {
+ alsa_long_t long_vol = 0;
+ snd_mixer_selem_get_playback_dB(elem,
+ static_cast<snd_mixer_selem_channel_id_t>(0),
+ &long_vol);
+ *current_vol = static_cast<double>(long_vol) / 100.0;
+
+ return true;
+}
+
+bool AudioMixerAlsa::SetElementVolume_Locked(snd_mixer_elem_t* elem,
+ double new_vol,
+ double* actual_vol,
+ double rounding_bias) {
+ alsa_long_t vol_lo = 0;
+ alsa_long_t vol_hi = 0;
+ snd_mixer_selem_get_playback_volume_range(elem, &vol_lo, &vol_hi);
+ alsa_long_t vol_range = vol_hi - vol_lo;
+ if (vol_range <= 0)
+ return false;
+
+ alsa_long_t db_lo_int = 0;
+ alsa_long_t db_hi_int = 0;
+ snd_mixer_selem_get_playback_dB_range(elem, &db_lo_int, &db_hi_int);
+ double db_lo = static_cast<double>(db_lo_int) / 100.0;
+ double db_hi = static_cast<double>(db_hi_int) / 100.0;
+ double db_step = static_cast<double>(db_hi - db_lo) / vol_range;
+ if (db_step <= 0.0)
+ return false;
+
+ if (new_vol < db_lo)
+ new_vol = db_lo;
+
+ alsa_long_t value = static_cast<alsa_long_t>(rounding_bias +
+ (new_vol - db_lo) / db_step) + vol_lo;
+ snd_mixer_selem_set_playback_volume_all(elem, value);
+
+ VLOG(1) << "Set volume " << snd_mixer_selem_get_name(elem)
+ << " to " << new_vol << " ==> " << (value - vol_lo) * db_step + db_lo
+ << " dB";
+
+ if (actual_vol) {
+ alsa_long_t volume;
+ snd_mixer_selem_get_playback_volume(
+ elem,
+ static_cast<snd_mixer_selem_channel_id_t>(0),
+ &volume);
+ *actual_vol = db_lo + (volume - vol_lo) * db_step;
+
+ VLOG(1) << "Actual volume " << snd_mixer_selem_get_name(elem)
+ << " now " << *actual_vol << " dB";
+ }
+ return true;
+}
+
+bool AudioMixerAlsa::GetElementMuted_Locked(snd_mixer_elem_t* elem) const {
+ int enabled;
+ snd_mixer_selem_get_playback_switch(
+ elem,
+ static_cast<snd_mixer_selem_channel_id_t>(0),
+ &enabled);
+ return (enabled) ? false : true;
+}
+
+void AudioMixerAlsa::SetElementMuted_Locked(snd_mixer_elem_t* elem, bool mute) {
+ int enabled = mute ? 0 : 1;
+ snd_mixer_selem_set_playback_switch_all(elem, enabled);
+
+ VLOG(1) << "Set playback switch " << snd_mixer_selem_get_name(elem)
+ << " to " << enabled;
+}
+
+} // namespace chromeos
+
diff --git a/chrome/browser/chromeos/audio_mixer_alsa.h b/chrome/browser/chromeos/audio_mixer_alsa.h
new file mode 100644
index 0000000..d365a22
--- /dev/null
+++ b/chrome/browser/chromeos/audio_mixer_alsa.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_ALSA_H_
+#define CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_ALSA_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/lock.h"
+#include "base/scoped_ptr.h"
+#include "base/threading/thread.h"
+#include "chrome/browser/chromeos/audio_mixer.h"
+
+struct _snd_mixer_elem;
+struct _snd_mixer;
+
+namespace chromeos {
+
+class AudioMixerAlsa : public AudioMixer {
+ public:
+ AudioMixerAlsa();
+ virtual ~AudioMixerAlsa();
+
+ // Implementation of AudioMixer
+ virtual void Init(InitDoneCallback* callback);
+ virtual bool InitSync();
+ virtual double GetVolumeDb() const;
+ virtual bool GetVolumeLimits(double* vol_min, double* vol_max);
+ virtual void SetVolumeDb(double vol_db);
+ virtual bool IsMute() const;
+ virtual void SetMute(bool mute);
+ virtual State GetState() const;
+
+ private:
+ // Called to do initialization in background from worker thread.
+ void DoInit(InitDoneCallback* callback);
+
+ // Helper function to just get our message loop thread going.
+ bool InitThread();
+
+ // Try to connect to the ALSA mixer through their simple controls interface,
+ // and cache mixer handle and mixer elements we'll be using.
+ bool InitializeAlsaMixer();
+ void FreeAlsaMixer();
+
+ // All these internal volume commands must be called with the lock held.
+ double DoGetVolumeDb_Locked() const;
+ void DoSetVolumeDb_Locked(double vol_db);
+
+ _snd_mixer_elem* FindElementWithName_Locked(_snd_mixer* handle,
+ const char* element_name) const;
+
+ bool GetElementVolume_Locked(_snd_mixer_elem* elem,
+ double* current_vol) const;
+
+ // Since volume is done in steps, we may not get the exact volume asked for,
+ // so actual_vol will contain the true volume that was set. This information
+ // can be used to further refine the volume by adjust a different mixer
+ // element. The rounding_bias is added in before rounding to the nearest
+ // volume step (use 0.5 to round to nearest).
+ bool SetElementVolume_Locked(_snd_mixer_elem* elem,
+ double new_vol,
+ double* actual_vol,
+ double rounding_bias);
+
+ // In ALSA, the mixer element's 'switch' is turned off to mute.
+ bool GetElementMuted_Locked(_snd_mixer_elem* elem) const;
+ void SetElementMuted_Locked(_snd_mixer_elem* elem, bool mute);
+
+ // Volume range limits are computed once during InitializeAlsaMixer.
+ double min_volume_;
+ double max_volume_;
+
+ // Muting is done by setting volume to minimum, so we must save the original.
+ // This is the only state information kept in this object. In some cases,
+ // ALSA can report it has a volume switch and we can turn it off, but it has
+ // no effect.
+ double save_volume_;
+
+ mutable Lock mixer_state_lock_;
+ mutable State mixer_state_;
+
+ // Cached contexts for use in ALSA calls.
+ _snd_mixer* alsa_mixer_;
+ _snd_mixer_elem* elem_master_;
+ _snd_mixer_elem* elem_pcm_;
+
+ scoped_ptr<base::Thread> thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioMixerAlsa);
+};
+
+} // namespace chromeos
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::AudioMixerAlsa);
+
+#endif // CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_ALSA_H_
+
diff --git a/chrome/browser/chromeos/pulse_audio_mixer.cc b/chrome/browser/chromeos/audio_mixer_pulse.cc
index a58548e..0001548 100644
--- a/chrome/browser/chromeos/pulse_audio_mixer.cc
+++ b/chrome/browser/chromeos/audio_mixer_pulse.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/chromeos/pulse_audio_mixer.h"
+#include "chrome/browser/chromeos/audio_mixer_pulse.h"
#include <pulse/pulseaudio.h>
@@ -26,9 +26,14 @@ namespace {
const int kInvalidDeviceId = -1;
+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.
+const double kMaxVolumeDb = 6.0;
+
// Used for passing custom data to the PulseAudio callbacks.
struct CallbackWrapper {
- PulseAudioMixer* instance;
+ AudioMixerPulse* instance;
bool done;
void* userdata;
};
@@ -37,66 +42,66 @@ struct CallbackWrapper {
// AudioInfo contains all the values we care about when getting info for a
// Sink (output device) used by GetAudioInfo().
-struct PulseAudioMixer::AudioInfo {
+struct AudioMixerPulse::AudioInfo {
pa_cvolume cvolume;
bool muted;
};
-PulseAudioMixer::PulseAudioMixer()
+AudioMixerPulse::AudioMixerPulse()
: device_id_(kInvalidDeviceId),
last_channels_(0),
mainloop_lock_count_(0),
- mixer_state_lock_(),
mixer_state_(UNINITIALIZED),
pa_context_(NULL),
- pa_mainloop_(NULL),
- thread_(NULL) {
+ pa_mainloop_(NULL) {
}
-PulseAudioMixer::~PulseAudioMixer() {
+AudioMixerPulse::~AudioMixerPulse() {
PulseAudioFree();
- thread_->Stop();
- thread_.reset();
+ if (thread_ != NULL) {
+ thread_->Stop();
+ thread_.reset();
+ }
}
-bool PulseAudioMixer::Init(InitDoneCallback* callback) {
- if (!InitThread())
- return false;
+void AudioMixerPulse::Init(InitDoneCallback* callback) {
+ DCHECK(callback);
+ if (!InitThread()) {
+ callback->Run(false);
+ delete callback;
+ return;
+ }
// Post the task of starting up, which can block for 200-500ms,
// so best not to do it on the caller's thread.
thread_->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this, &PulseAudioMixer::DoInit, callback));
- return true;
+ NewRunnableMethod(this, &AudioMixerPulse::DoInit, callback));
}
-bool PulseAudioMixer::InitSync() {
+bool AudioMixerPulse::InitSync() {
if (!InitThread())
return false;
return PulseAudioInit();
}
-double PulseAudioMixer::GetVolumeDb() const {
+double AudioMixerPulse::GetVolumeDb() const {
if (!MainloopLockIfReady())
- return pa_sw_volume_to_dB(0); // this returns -inf.
+ return AudioMixer::kSilenceDb;
AudioInfo data;
GetAudioInfo(&data);
MainloopUnlock();
return pa_sw_volume_to_dB(data.cvolume.values[0]);
}
-bool PulseAudioMixer::GetVolumeDbAsync(GetVolumeCallback* callback,
- void* user) {
- if (CheckState() != READY)
- return false;
- thread_->message_loop()->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &PulseAudioMixer::DoGetVolume,
- callback, user));
+bool AudioMixerPulse::GetVolumeLimits(double* vol_min, double* vol_max) {
+ if (vol_min)
+ *vol_min = kMinVolumeDb;
+ if (vol_max)
+ *vol_max = kMaxVolumeDb;
return true;
}
-void PulseAudioMixer::SetVolumeDb(double vol_db) {
+void AudioMixerPulse::SetVolumeDb(double vol_db) {
if (!MainloopLockIfReady())
return;
@@ -115,9 +120,10 @@ void PulseAudioMixer::SetVolumeDb(double vol_db) {
&cvolume, NULL, NULL);
pa_operation_unref(pa_op);
MainloopUnlock();
+ VLOG(1) << "Set volume to " << vol_db << " dB";
}
-bool PulseAudioMixer::IsMute() const {
+bool AudioMixerPulse::IsMute() const {
if (!MainloopLockIfReady())
return false;
AudioInfo data;
@@ -126,7 +132,7 @@ bool PulseAudioMixer::IsMute() const {
return data.muted;
}
-void PulseAudioMixer::SetMute(bool mute) {
+void AudioMixerPulse::SetMute(bool mute) {
if (!MainloopLockIfReady())
return;
pa_operation* pa_op;
@@ -134,9 +140,10 @@ void PulseAudioMixer::SetMute(bool mute) {
mute ? 1 : 0, NULL, NULL);
pa_operation_unref(pa_op);
MainloopUnlock();
+ VLOG(1) << "Set mute to " << mute;
}
-PulseAudioMixer::State PulseAudioMixer::CheckState() const {
+AudioMixer::State AudioMixerPulse::GetState() const {
AutoLock lock(mixer_state_lock_);
// If we think it's ready, verify it is actually so.
if ((mixer_state_ == READY) &&
@@ -148,25 +155,20 @@ PulseAudioMixer::State PulseAudioMixer::CheckState() const {
////////////////////////////////////////////////////////////////////////////////
// Private functions follow
-void PulseAudioMixer::DoInit(InitDoneCallback* callback) {
+void AudioMixerPulse::DoInit(InitDoneCallback* callback) {
bool success = PulseAudioInit();
callback->Run(success);
delete callback;
}
-void PulseAudioMixer::DoGetVolume(GetVolumeCallback* callback,
- void* user) {
- callback->Run(GetVolumeDb(), user);
- delete callback;
-}
-
-bool PulseAudioMixer::InitThread() {
+bool AudioMixerPulse::InitThread() {
AutoLock lock(mixer_state_lock_);
if (mixer_state_ != UNINITIALIZED)
return false;
+
if (thread_ == NULL) {
- thread_.reset(new base::Thread("PulseAudioMixer"));
+ thread_.reset(new base::Thread("AudioMixerPulse"));
if (!thread_->Start()) {
thread_.reset();
return false;
@@ -177,14 +179,14 @@ bool PulseAudioMixer::InitThread() {
}
// static
-void PulseAudioMixer::ConnectToPulseCallbackThunk(
+void AudioMixerPulse::ConnectToPulseCallbackThunk(
pa_context* context, void* userdata) {
CallbackWrapper* data =
static_cast<CallbackWrapper*>(userdata);
data->instance->OnConnectToPulseCallback(context, &data->done);
}
-void PulseAudioMixer::OnConnectToPulseCallback(
+void AudioMixerPulse::OnConnectToPulseCallback(
pa_context* context, bool* connect_done) {
pa_context_state_t state = pa_context_get_state(context);
if (state == PA_CONTEXT_READY ||
@@ -196,7 +198,7 @@ void PulseAudioMixer::OnConnectToPulseCallback(
}
}
-bool PulseAudioMixer::PulseAudioInit() {
+bool AudioMixerPulse::PulseAudioInit() {
pa_context_state_t state = PA_CONTEXT_FAILED;
{
@@ -298,13 +300,14 @@ bool PulseAudioMixer::PulseAudioInit() {
return false;
}
-void PulseAudioMixer::PulseAudioFree() {
+void AudioMixerPulse::PulseAudioFree() {
{
AutoLock lock(mixer_state_lock_);
if (!pa_mainloop_)
mixer_state_ = UNINITIALIZED;
if ((mixer_state_ == UNINITIALIZED) || (mixer_state_ == SHUTTING_DOWN))
return;
+
// If still initializing on another thread, this will cause it to exit.
mixer_state_ = SHUTTING_DOWN;
}
@@ -329,7 +332,7 @@ void PulseAudioMixer::PulseAudioFree() {
}
}
-void PulseAudioMixer::CompleteOperation(pa_operation* pa_op,
+void AudioMixerPulse::CompleteOperation(pa_operation* pa_op,
bool* done) const {
// After starting any operation, this helper checks if it started OK, then
// waits for it to complete by iterating through the mainloop until the
@@ -348,7 +351,7 @@ void PulseAudioMixer::CompleteOperation(pa_operation* pa_op,
}
// Must be called with mainloop lock held
-void PulseAudioMixer::GetDefaultPlaybackDevice() {
+void AudioMixerPulse::GetDefaultPlaybackDevice() {
DCHECK_GT(mainloop_lock_count_, 0);
DCHECK(pa_context_);
DCHECK(pa_context_get_state(pa_context_) == PA_CONTEXT_READY);
@@ -362,7 +365,7 @@ void PulseAudioMixer::GetDefaultPlaybackDevice() {
return;
}
-void PulseAudioMixer::OnEnumerateDevices(const pa_sink_info* sink_info,
+void AudioMixerPulse::OnEnumerateDevices(const pa_sink_info* sink_info,
int eol, bool* done) {
if (device_id_ != kInvalidDeviceId)
return;
@@ -378,7 +381,7 @@ void PulseAudioMixer::OnEnumerateDevices(const pa_sink_info* sink_info,
}
// static
-void PulseAudioMixer::EnumerateDevicesCallback(pa_context* unused,
+void AudioMixerPulse::EnumerateDevicesCallback(pa_context* unused,
const pa_sink_info* sink_info,
int eol,
void* userdata) {
@@ -388,9 +391,9 @@ void PulseAudioMixer::EnumerateDevicesCallback(pa_context* unused,
}
// Must be called with lock held
-void PulseAudioMixer::GetAudioInfo(AudioInfo* info) const {
+void AudioMixerPulse::GetAudioInfo(AudioInfo* info) const {
DCHECK_GT(mainloop_lock_count_, 0);
- CallbackWrapper data = {const_cast<PulseAudioMixer*>(this), false, info};
+ CallbackWrapper data = {const_cast<AudioMixerPulse*>(this), false, info};
pa_operation* pa_op = pa_context_get_sink_info_by_index(pa_context_,
device_id_,
GetAudioInfoCallback,
@@ -399,7 +402,7 @@ void PulseAudioMixer::GetAudioInfo(AudioInfo* info) const {
}
// static
-void PulseAudioMixer::GetAudioInfoCallback(pa_context* unused,
+void AudioMixerPulse::GetAudioInfoCallback(pa_context* unused,
const pa_sink_info* sink_info,
int eol,
void* userdata) {
@@ -415,38 +418,39 @@ void PulseAudioMixer::GetAudioInfoCallback(pa_context* unused,
data->instance->MainloopSignal();
}
-inline void PulseAudioMixer::MainloopLock() const {
+inline void AudioMixerPulse::MainloopLock() const {
pa_threaded_mainloop_lock(pa_mainloop_);
++mainloop_lock_count_;
}
-inline void PulseAudioMixer::MainloopUnlock() const {
+inline void AudioMixerPulse::MainloopUnlock() const {
--mainloop_lock_count_;
pa_threaded_mainloop_unlock(pa_mainloop_);
}
// Must be called with the lock held.
-inline void PulseAudioMixer::MainloopWait() const {
+inline void AudioMixerPulse::MainloopWait() const {
DCHECK_GT(mainloop_lock_count_, 0);
pa_threaded_mainloop_wait(pa_mainloop_);
}
// Must be called with the lock held.
-inline void PulseAudioMixer::MainloopSignal() const {
+inline void AudioMixerPulse::MainloopSignal() const {
DCHECK_GT(mainloop_lock_count_, 0);
pa_threaded_mainloop_signal(pa_mainloop_, 0);
}
-inline bool PulseAudioMixer::MainloopSafeLock() const {
+inline bool AudioMixerPulse::MainloopSafeLock() const {
AutoLock lock(mixer_state_lock_);
if ((mixer_state_ == SHUTTING_DOWN) || (!pa_mainloop_))
return false;
+
pa_threaded_mainloop_lock(pa_mainloop_);
++mainloop_lock_count_;
return true;
}
-inline bool PulseAudioMixer::MainloopLockIfReady() const {
+inline bool AudioMixerPulse::MainloopLockIfReady() const {
AutoLock lock(mixer_state_lock_);
if (mixer_state_ != READY)
return false;
diff --git a/chrome/browser/chromeos/pulse_audio_mixer.h b/chrome/browser/chromeos/audio_mixer_pulse.h
index f01e738..8ce8274 100644
--- a/chrome/browser/chromeos/pulse_audio_mixer.h
+++ b/chrome/browser/chromeos/audio_mixer_pulse.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_CHROMEOS_PULSE_AUDIO_MIXER_H_
-#define CHROME_BROWSER_CHROMEOS_PULSE_AUDIO_MIXER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_PULSE_H_
+#define CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_PULSE_H_
#pragma once
#include "base/basictypes.h"
@@ -11,6 +11,7 @@
#include "base/lock.h"
#include "base/scoped_ptr.h"
#include "base/threading/thread.h"
+#include "chrome/browser/chromeos/audio_mixer.h"
struct pa_context;
struct pa_cvolume;
@@ -20,56 +21,27 @@ struct pa_sink_info;
namespace chromeos {
-class PulseAudioMixer {
+class AudioMixerPulse : public AudioMixer {
public:
- enum State {
- UNINITIALIZED = 0,
- INITIALIZING,
- READY,
- SHUTTING_DOWN,
- IN_ERROR
- };
- PulseAudioMixer();
- ~PulseAudioMixer();
+ AudioMixerPulse();
+ virtual ~AudioMixerPulse();
- // Non-blocking, connect to PulseAudio and find a default device, and call
- // callback when complete with success code.
- typedef Callback1<bool>::Type InitDoneCallback;
- bool Init(InitDoneCallback* callback);
-
- // Blocking init call guarantees PulseAudio is started before returning.
- bool InitSync();
-
- // Blocking call. Returns a default of -inf on error.
- double GetVolumeDb() const;
-
- // Non-blocking, volume sent in as first param to callback. The callback is
- // only called if the function returns true.
- typedef Callback2<double, void*>::Type GetVolumeCallback;
- bool GetVolumeDbAsync(GetVolumeCallback* callback, void* user);
-
- // Non-blocking call.
- void SetVolumeDb(double vol_db);
-
- // Gets the mute state of the default device (true == mute). Blocking call.
- // Returns a default of false on error.
- bool IsMute() const;
-
- // Non-Blocking call.
- void SetMute(bool mute);
-
- // Returns READY if we have a valid working connection to PulseAudio.
- // This can return IN_ERROR if we lose the connection, even after an original
- // successful init. Non-blocking call.
- State CheckState() const;
+ // Implementation of AudioMixer
+ virtual void Init(InitDoneCallback* callback);
+ virtual bool InitSync();
+ virtual double GetVolumeDb() const;
+ virtual bool GetVolumeLimits(double* vol_min, double* vol_max);
+ virtual void SetVolumeDb(double vol_db);
+ virtual bool IsMute() const;
+ virtual void SetMute(bool mute);
+ virtual State GetState() const;
private:
struct AudioInfo;
- // These are the tasks to be run in the background on the worker thread.
+ // The initialization task is run in the background on the worker thread.
void DoInit(InitDoneCallback* callback);
- void DoGetVolume(GetVolumeCallback* callback, void* user);
static void ConnectToPulseCallbackThunk(pa_context* c, void* userdata);
void OnConnectToPulseCallback(pa_context* c, bool* connect_done);
@@ -137,12 +109,12 @@ class PulseAudioMixer {
scoped_ptr<base::Thread> thread_;
- DISALLOW_COPY_AND_ASSIGN(PulseAudioMixer);
+ DISALLOW_COPY_AND_ASSIGN(AudioMixerPulse);
};
} // namespace chromeos
-DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::PulseAudioMixer);
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::AudioMixerPulse);
-#endif // CHROME_BROWSER_CHROMEOS_PULSE_AUDIO_MIXER_H_
+#endif // CHROME_BROWSER_CHROMEOS_AUDIO_MIXER_PULSE_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d708af3..c0c00b7 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -404,6 +404,11 @@
'browser/chromeos/notifications/system_notification_factory.h',
'browser/chromeos/audio_handler.cc',
'browser/chromeos/audio_handler.h',
+ 'browser/chromeos/audio_mixer.h',
+ 'browser/chromeos/audio_mixer_alsa.cc',
+ 'browser/chromeos/audio_mixer_alsa.h',
+ 'browser/chromeos/audio_mixer_pulse.cc',
+ 'browser/chromeos/audio_mixer_pulse.h',
'browser/chromeos/boot_times_loader.cc',
'browser/chromeos/boot_times_loader.h',
'browser/chromeos/brightness_bubble.cc',
@@ -739,8 +744,6 @@
'browser/chromeos/proxy_config_service_impl.h',
'browser/chromeos/proxy_cros_settings_provider.cc',
'browser/chromeos/proxy_cros_settings_provider.h',
- 'browser/chromeos/pulse_audio_mixer.cc',
- 'browser/chromeos/pulse_audio_mixer.h',
'browser/chromeos/setting_level_bubble.cc',
'browser/chromeos/setting_level_bubble.h',
'browser/chromeos/setting_level_bubble_view.cc',