summaryrefslogtreecommitdiffstats
path: root/media/audio/linux/audio_manager_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'media/audio/linux/audio_manager_linux.cc')
-rw-r--r--media/audio/linux/audio_manager_linux.cc355
1 files changed, 10 insertions, 345 deletions
diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc
index 0d0f104..350cd64 100644
--- a/media/audio/linux/audio_manager_linux.cc
+++ b/media/audio/linux/audio_manager_linux.cc
@@ -2,51 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/audio/linux/audio_manager_linux.h"
-
#include "base/command_line.h"
-#include "base/environment.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
#include "base/metrics/histogram.h"
-#include "base/nix/xdg_util.h"
-#include "base/process/launch.h"
-#include "base/stl_util.h"
-#include "media/audio/audio_output_dispatcher.h"
-#include "media/audio/audio_parameters.h"
+#if defined(USE_ALSA)
+#include "media/audio/alsa/audio_manager_alsa.h"
+#else
+#include "media/audio/fake_audio_manager.h"
+#endif
#if defined(USE_CRAS)
#include "media/audio/cras/audio_manager_cras.h"
#endif
-#include "media/audio/linux/alsa_input.h"
-#include "media/audio/linux/alsa_output.h"
-#include "media/audio/linux/alsa_wrapper.h"
#if defined(USE_PULSEAUDIO)
#include "media/audio/pulse/audio_manager_pulse.h"
#endif
-#include "media/base/channel_layout.h"
-#include "media/base/limits.h"
#include "media/base/media_switches.h"
namespace media {
-// Maximum number of output streams that can be open simultaneously.
-static const int kMaxOutputStreams = 50;
-
-// Default sample rate for input and output streams.
-static const int kDefaultSampleRate = 48000;
-
-// Since "default", "pulse" and "dmix" devices are virtual devices mapped to
-// real devices, we remove them from the list to avoiding duplicate counting.
-// In addition, note that we support no more than 2 channels for recording,
-// hence surround devices are not stored in the list.
-static const char* kInvalidAudioInputDevices[] = {
- "default",
- "dmix",
- "null",
- "pulse",
- "surround",
-};
-
enum LinuxAudioIO {
kPulse,
kAlsa,
@@ -54,317 +26,6 @@ enum LinuxAudioIO {
kAudioIOMax // Must always be last!
};
-// static
-void AudioManagerLinux::ShowLinuxAudioInputSettings() {
- scoped_ptr<base::Environment> env(base::Environment::Create());
- CommandLine command_line(CommandLine::NO_PROGRAM);
- switch (base::nix::GetDesktopEnvironment(env.get())) {
- case base::nix::DESKTOP_ENVIRONMENT_GNOME:
- command_line.SetProgram(base::FilePath("gnome-volume-control"));
- break;
- case base::nix::DESKTOP_ENVIRONMENT_KDE3:
- case base::nix::DESKTOP_ENVIRONMENT_KDE4:
- command_line.SetProgram(base::FilePath("kmix"));
- break;
- case base::nix::DESKTOP_ENVIRONMENT_UNITY:
- command_line.SetProgram(base::FilePath("gnome-control-center"));
- command_line.AppendArg("sound");
- command_line.AppendArg("input");
- break;
- default:
- LOG(ERROR) << "Failed to show audio input settings: we don't know "
- << "what command to use for your desktop environment.";
- return;
- }
- base::LaunchProcess(command_line, base::LaunchOptions(), NULL);
-}
-
-// Implementation of AudioManager.
-bool AudioManagerLinux::HasAudioOutputDevices() {
- return HasAnyAlsaAudioDevice(kStreamPlayback);
-}
-
-bool AudioManagerLinux::HasAudioInputDevices() {
- return HasAnyAlsaAudioDevice(kStreamCapture);
-}
-
-AudioManagerLinux::AudioManagerLinux()
- : wrapper_(new AlsaWrapper()) {
- SetMaxOutputStreamsAllowed(kMaxOutputStreams);
-}
-
-AudioManagerLinux::~AudioManagerLinux() {
- Shutdown();
-}
-
-void AudioManagerLinux::ShowAudioInputSettings() {
- ShowLinuxAudioInputSettings();
-}
-
-void AudioManagerLinux::GetAudioInputDeviceNames(
- AudioDeviceNames* device_names) {
- DCHECK(device_names->empty());
- GetAlsaAudioDevices(kStreamCapture, device_names);
-}
-
-void AudioManagerLinux::GetAudioOutputDeviceNames(
- AudioDeviceNames* device_names) {
- DCHECK(device_names->empty());
- GetAlsaAudioDevices(kStreamPlayback, device_names);
-}
-
-AudioParameters AudioManagerLinux::GetInputStreamParameters(
- const std::string& device_id) {
- static const int kDefaultInputBufferSize = 1024;
-
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
- kDefaultSampleRate, 16, kDefaultInputBufferSize);
-}
-
-void AudioManagerLinux::GetAlsaAudioDevices(
- StreamType type,
- media::AudioDeviceNames* device_names) {
- // Constants specified by the ALSA API for device hints.
- static const char kPcmInterfaceName[] = "pcm";
- int card = -1;
-
- // Loop through the sound cards to get ALSA device hints.
- while (!wrapper_->CardNext(&card) && card >= 0) {
- void** hints = NULL;
- int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
- if (!error) {
- GetAlsaDevicesInfo(type, hints, device_names);
-
- // Destroy the hints now that we're done with it.
- wrapper_->DeviceNameFreeHint(hints);
- } else {
- DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: "
- << wrapper_->StrError(error);
- }
- }
-}
-
-void AudioManagerLinux::GetAlsaDevicesInfo(
- AudioManagerLinux::StreamType type,
- void** hints,
- media::AudioDeviceNames* device_names) {
- static const char kIoHintName[] = "IOID";
- static const char kNameHintName[] = "NAME";
- static const char kDescriptionHintName[] = "DESC";
-
- const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type);
-
- for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
- // Only examine devices of the right type. Valid values are
- // "Input", "Output", and NULL which means both input and output.
- scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
- kIoHintName));
- if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0)
- continue;
-
- // Found a device, prepend the default device since we always want
- // it to be on the top of the list for all platforms. And there is
- // no duplicate counting here since it is only done if the list is
- // still empty. Note, pulse has exclusively opened the default
- // device, so we must open the device via the "default" moniker.
- if (device_names->empty()) {
- device_names->push_front(media::AudioDeviceName(
- AudioManagerBase::kDefaultDeviceName,
- AudioManagerBase::kDefaultDeviceId));
- }
-
- // Get the unique device name for the device.
- scoped_ptr_malloc<char> unique_device_name(
- wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
-
- // Find out if the device is available.
- if (IsAlsaDeviceAvailable(type, unique_device_name.get())) {
- // Get the description for the device.
- scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
- *hint_iter, kDescriptionHintName));
-
- media::AudioDeviceName name;
- name.unique_id = unique_device_name.get();
- if (desc) {
- // Use the more user friendly description as name.
- // Replace '\n' with '-'.
- char* pret = strchr(desc.get(), '\n');
- if (pret)
- *pret = '-';
- name.device_name = desc.get();
- } else {
- // Virtual devices don't necessarily have descriptions.
- // Use their names instead.
- name.device_name = unique_device_name.get();
- }
-
- // Store the device information.
- device_names->push_back(name);
- }
- }
-}
-
-// static
-bool AudioManagerLinux::IsAlsaDeviceAvailable(
- AudioManagerLinux::StreamType type,
- const char* device_name) {
- if (!device_name)
- return false;
-
- // We do prefix matches on the device name to see whether to include
- // it or not.
- if (type == kStreamCapture) {
- // Check if the device is in the list of invalid devices.
- for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
- if (strncmp(kInvalidAudioInputDevices[i], device_name,
- strlen(kInvalidAudioInputDevices[i])) == 0)
- return false;
- }
- return true;
- } else {
- DCHECK_EQ(kStreamPlayback, type);
- // We prefer the device type that maps straight to hardware but
- // goes through software conversion if needed (e.g. incompatible
- // sample rate).
- // TODO(joi): Should we prefer "hw" instead?
- static const char kDeviceTypeDesired[] = "plughw";
- return strncmp(kDeviceTypeDesired,
- device_name,
- arraysize(kDeviceTypeDesired) - 1) == 0;
- }
-}
-
-// static
-const char* AudioManagerLinux::UnwantedDeviceTypeWhenEnumerating(
- AudioManagerLinux::StreamType wanted_type) {
- return wanted_type == kStreamPlayback ? "Input" : "Output";
-}
-
-bool AudioManagerLinux::HasAnyAlsaAudioDevice(
- AudioManagerLinux::StreamType stream) {
- static const char kPcmInterfaceName[] = "pcm";
- static const char kIoHintName[] = "IOID";
- void** hints = NULL;
- bool has_device = false;
- int card = -1;
-
- // Loop through the sound cards.
- // Don't use snd_device_name_hint(-1,..) since there is a access violation
- // inside this ALSA API with libasound.so.2.0.0.
- while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) {
- int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
- if (!error) {
- for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
- // Only examine devices that are |stream| capable. Valid values are
- // "Input", "Output", and NULL which means both input and output.
- scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
- kIoHintName));
- const char* unwanted_type = UnwantedDeviceTypeWhenEnumerating(stream);
- if (io != NULL && strcmp(unwanted_type, io.get()) == 0)
- continue; // Wrong type, skip the device.
-
- // Found an input device.
- has_device = true;
- break;
- }
-
- // Destroy the hints now that we're done with it.
- wrapper_->DeviceNameFreeHint(hints);
- hints = NULL;
- } else {
- DLOG(WARNING) << "HasAnyAudioDevice: unable to get device hints: "
- << wrapper_->StrError(error);
- }
- }
-
- return has_device;
-}
-
-AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream(
- const AudioParameters& params) {
- DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
- return MakeOutputStream(params);
-}
-
-AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream(
- const AudioParameters& params,
- const std::string& device_id,
- const std::string& input_device_id) {
- DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
- DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
- // TODO(xians): Use input_device_id for unified IO.
- return MakeOutputStream(params);
-}
-
-AudioInputStream* AudioManagerLinux::MakeLinearInputStream(
- const AudioParameters& params, const std::string& device_id) {
- DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
- return MakeInputStream(params, device_id);
-}
-
-AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream(
- const AudioParameters& params, const std::string& device_id) {
- DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
- return MakeInputStream(params, device_id);
-}
-
-AudioParameters AudioManagerLinux::GetPreferredOutputStreamParameters(
- const std::string& output_device_id,
- const AudioParameters& input_params) {
- // TODO(tommi): Support |output_device_id|.
- DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
- static const int kDefaultOutputBufferSize = 2048;
- ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
- int sample_rate = kDefaultSampleRate;
- int buffer_size = kDefaultOutputBufferSize;
- int bits_per_sample = 16;
- int input_channels = 0;
- if (input_params.IsValid()) {
- // Some clients, such as WebRTC, have a more limited use case and work
- // acceptably with a smaller buffer size. The check below allows clients
- // which want to try a smaller buffer size on Linux to do so.
- // TODO(dalecurtis): This should include bits per channel and channel layout
- // eventually.
- sample_rate = input_params.sample_rate();
- bits_per_sample = input_params.bits_per_sample();
- channel_layout = input_params.channel_layout();
- input_channels = input_params.input_channels();
- buffer_size = std::min(input_params.frames_per_buffer(), buffer_size);
- }
-
- int user_buffer_size = GetUserBufferSize();
- if (user_buffer_size)
- buffer_size = user_buffer_size;
-
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels,
- sample_rate, bits_per_sample, buffer_size);
-}
-
-AudioOutputStream* AudioManagerLinux::MakeOutputStream(
- const AudioParameters& params) {
- std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice;
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAlsaOutputDevice)) {
- device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kAlsaOutputDevice);
- }
- return new AlsaPcmOutputStream(device_name, params, wrapper_.get(), this);
-}
-
-AudioInputStream* AudioManagerLinux::MakeInputStream(
- const AudioParameters& params, const std::string& device_id) {
- std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ?
- AlsaPcmInputStream::kAutoSelectDevice : device_id;
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) {
- device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kAlsaInputDevice);
- }
-
- return new AlsaPcmInputStream(this, device_name, params, wrapper_.get());
-}
-
AudioManager* CreateAudioManager() {
#if defined(USE_CRAS)
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseCras)) {
@@ -381,8 +42,12 @@ AudioManager* CreateAudioManager() {
}
#endif
+#if defined(USE_ALSA)
UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kAlsa, kAudioIOMax);
- return new AudioManagerLinux();
+ return new AudioManagerAlsa();
+#else
+ return new FakeAudioManager();
+#endif
}
} // namespace media