diff options
author | spang@chromium.org <spang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-28 06:00:33 +0000 |
---|---|---|
committer | spang@chromium.org <spang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-28 06:00:33 +0000 |
commit | 8117a12e805a3243141cf3c7cb0f2cdd0538b47f (patch) | |
tree | 77ca52f1d5086608d87064fa4e500d793b528fb5 | |
parent | 0a72447fb90b7d8ab0ab07119098a46ba84f0c86 (diff) | |
download | chromium_src-8117a12e805a3243141cf3c7cb0f2cdd0538b47f.zip chromium_src-8117a12e805a3243141cf3c7cb0f2cdd0538b47f.tar.gz chromium_src-8117a12e805a3243141cf3c7cb0f2cdd0538b47f.tar.bz2 |
Support use_alsa==0 on Linux
This moves the ALSA audio code from media/audio/linux to
media/audio/alsa and splits Linux's CreateAudioManager() into a new
file. This function chooses which AudioManager subclass to use on Linux.
When use_alsa==0 on Linux, the fallback audio manager is changed from
ALSA to a new fake implementation that always has an empty set of devices
and will only return fake streams.
This allows us to compile with no audio support on Linux. In particular,
we can compile for targets that don't have the ALSA libraries available.
Obviously, it's not (yet) possible to play audio in this configuration.
BUG=318315, 318413
Review URL: https://codereview.chromium.org/89793003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237696 0039d316-1c4b-4281-b951-d872f2087c98
22 files changed, 595 insertions, 431 deletions
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc index a67237a..03e95e0 100644 --- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc @@ -13,14 +13,16 @@ #include "content/common/media/media_stream_options.h" #include "content/public/test/test_browser_thread_bundle.h" #include "media/audio/audio_manager_base.h" -#if defined(OS_ANDROID) +#if defined(USE_ALSA) +#include "media/audio/alsa/audio_manager_alsa.h" +#elif defined(OS_ANDROID) #include "media/audio/android/audio_manager_android.h" -#elif defined(OS_LINUX) || defined(OS_OPENBSD) -#include "media/audio/linux/audio_manager_linux.h" #elif defined(OS_MACOSX) #include "media/audio/mac/audio_manager_mac.h" #elif defined(OS_WIN) #include "media/audio/win/audio_manager_win.h" +#else +#include "media/audio/fake_audio_manager.h" #endif #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,14 +31,16 @@ using testing::_; namespace content { -#if defined(OS_LINUX) || defined(OS_OPENBSD) -typedef media::AudioManagerLinux AudioManagerPlatform; +#if defined(USE_ALSA) +typedef media::AudioManagerAlsa AudioManagerPlatform; #elif defined(OS_MACOSX) typedef media::AudioManagerMac AudioManagerPlatform; #elif defined(OS_WIN) typedef media::AudioManagerWin AudioManagerPlatform; #elif defined(OS_ANDROID) typedef media::AudioManagerAndroid AudioManagerPlatform; +#else +typedef media::FakeAudioManager AudioManagerPlatform; #endif diff --git a/media/audio/linux/alsa_input.cc b/media/audio/alsa/alsa_input.cc index 929cbe7..9dcbf2b 100644 --- a/media/audio/linux/alsa_input.cc +++ b/media/audio/alsa/alsa_input.cc @@ -1,19 +1,19 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 "media/audio/linux/alsa_input.h" +#include "media/audio/alsa/alsa_input.h" #include "base/basictypes.h" #include "base/bind.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/time/time.h" +#include "media/audio/alsa/alsa_output.h" +#include "media/audio/alsa/alsa_util.h" +#include "media/audio/alsa/alsa_wrapper.h" +#include "media/audio/alsa/audio_manager_alsa.h" #include "media/audio/audio_manager.h" -#include "media/audio/linux/alsa_output.h" -#include "media/audio/linux/alsa_util.h" -#include "media/audio/linux/alsa_wrapper.h" -#include "media/audio/linux/audio_manager_linux.h" namespace media { @@ -24,7 +24,7 @@ static const char kDefaultDevice2[] = "plug:default"; const char AlsaPcmInputStream::kAutoSelectDevice[] = ""; -AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerLinux* audio_manager, +AlsaPcmInputStream::AlsaPcmInputStream(AudioManagerBase* audio_manager, const std::string& device_name, const AudioParameters& params, AlsaWrapper* wrapper) diff --git a/media/audio/linux/alsa_input.h b/media/audio/alsa/alsa_input.h index 888e478..6e9aad90 100644 --- a/media/audio/linux/alsa_input.h +++ b/media/audio/alsa/alsa_input.h @@ -1,9 +1,9 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 MEDIA_AUDIO_LINUX_ALSA_INPUT_H_ -#define MEDIA_AUDIO_LINUX_ALSA_INPUT_H_ +#ifndef MEDIA_AUDIO_ALSA_ALSA_INPUT_H_ +#define MEDIA_AUDIO_ALSA_ALSA_INPUT_H_ #include <alsa/asoundlib.h> @@ -20,7 +20,7 @@ namespace media { class AlsaWrapper; -class AudioManagerLinux; +class AudioManagerBase; // Provides an input stream for audio capture based on the ALSA PCM interface. // This object is not thread safe and all methods should be invoked in the @@ -34,7 +34,7 @@ class AlsaPcmInputStream : public AgcAudioStream<AudioInputStream> { // Create a PCM Output stream for the ALSA device identified by // |device_name|. If unsure of what to use for |device_name|, use // |kAutoSelectDevice|. - AlsaPcmInputStream(AudioManagerLinux* audio_manager, + AlsaPcmInputStream(AudioManagerBase* audio_manager, const std::string& device_name, const AudioParameters& params, AlsaWrapper* wrapper); @@ -69,7 +69,7 @@ class AlsaPcmInputStream : public AgcAudioStream<AudioInputStream> { // want circular references. Additionally, stream objects live on the audio // thread, which is owned by the audio manager and we don't want to addref // the manager from that thread. - AudioManagerLinux* audio_manager_; + AudioManagerBase* audio_manager_; std::string device_name_; AudioParameters params_; int bytes_per_buffer_; @@ -89,4 +89,4 @@ class AlsaPcmInputStream : public AgcAudioStream<AudioInputStream> { } // namespace media -#endif // MEDIA_AUDIO_LINUX_ALSA_INPUT_H_ +#endif // MEDIA_AUDIO_ALSA_ALSA_INPUT_H_ diff --git a/media/audio/linux/alsa_output.cc b/media/audio/alsa/alsa_output.cc index fa83835..eccf8ee 100644 --- a/media/audio/linux/alsa_output.cc +++ b/media/audio/alsa/alsa_output.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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. // @@ -32,7 +32,7 @@ // view, it will seem that the device has just clogged and stopped requesting // data. -#include "media/audio/linux/alsa_output.h" +#include "media/audio/alsa/alsa_output.h" #include <algorithm> @@ -42,9 +42,9 @@ #include "base/message_loop/message_loop.h" #include "base/stl_util.h" #include "base/time/time.h" -#include "media/audio/linux/alsa_util.h" -#include "media/audio/linux/alsa_wrapper.h" -#include "media/audio/linux/audio_manager_linux.h" +#include "media/audio/alsa/alsa_util.h" +#include "media/audio/alsa/alsa_wrapper.h" +#include "media/audio/alsa/audio_manager_alsa.h" #include "media/base/channel_mixer.h" #include "media/base/data_buffer.h" #include "media/base/seekable_buffer.h" @@ -134,7 +134,7 @@ const uint32 AlsaPcmOutputStream::kMinLatencyMicros = 40 * 1000; AlsaPcmOutputStream::AlsaPcmOutputStream(const std::string& device_name, const AudioParameters& params, AlsaWrapper* wrapper, - AudioManagerLinux* manager) + AudioManagerBase* manager) : requested_device_name_(device_name), pcm_format_(alsa_util::BitsToFormat(params.bits_per_sample())), channels_(params.channels()), diff --git a/media/audio/linux/alsa_output.h b/media/audio/alsa/alsa_output.h index 841615d..65a23f7 100644 --- a/media/audio/linux/alsa_output.h +++ b/media/audio/alsa/alsa_output.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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. // @@ -18,8 +18,8 @@ // the audio thread. When modifying the code in this class, please read the // threading assumptions at the top of the implementation. -#ifndef MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ -#define MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ +#ifndef MEDIA_AUDIO_ALSA_ALSA_OUTPUT_H_ +#define MEDIA_AUDIO_ALSA_ALSA_OUTPUT_H_ #include <alsa/asoundlib.h> @@ -40,7 +40,7 @@ class MessageLoop; namespace media { class AlsaWrapper; -class AudioManagerLinux; +class AudioManagerBase; class ChannelMixer; class SeekableBuffer; @@ -70,7 +70,7 @@ class MEDIA_EXPORT AlsaPcmOutputStream : public AudioOutputStream { AlsaPcmOutputStream(const std::string& device_name, const AudioParameters& params, AlsaWrapper* wrapper, - AudioManagerLinux* manager); + AudioManagerBase* manager); virtual ~AlsaPcmOutputStream(); @@ -187,7 +187,7 @@ class MEDIA_EXPORT AlsaPcmOutputStream : public AudioOutputStream { AlsaWrapper* wrapper_; // Audio manager that created us. Used to report that we've been closed. - AudioManagerLinux* manager_; + AudioManagerBase* manager_; // Message loop to use for polling. The object is owned by the AudioManager. // We hold a reference to the audio thread message loop since @@ -225,4 +225,4 @@ MEDIA_EXPORT std::ostream& operator<<(std::ostream& os, }; // namespace media -#endif // MEDIA_AUDIO_LINUX_ALSA_OUTPUT_H_ +#endif // MEDIA_AUDIO_ALSA_ALSA_OUTPUT_H_ diff --git a/media/audio/linux/alsa_output_unittest.cc b/media/audio/alsa/alsa_output_unittest.cc index 82fbab9..9d83b56 100644 --- a/media/audio/linux/alsa_output_unittest.cc +++ b/media/audio/alsa/alsa_output_unittest.cc @@ -1,12 +1,12 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 "base/message_loop/message_loop.h" #include "base/strings/stringprintf.h" -#include "media/audio/linux/alsa_output.h" -#include "media/audio/linux/alsa_wrapper.h" -#include "media/audio/linux/audio_manager_linux.h" +#include "media/audio/alsa/alsa_output.h" +#include "media/audio/alsa/alsa_wrapper.h" +#include "media/audio/alsa/audio_manager_alsa.h" #include "media/base/data_buffer.h" #include "media/base/seekable_buffer.h" #include "testing/gmock/include/gmock/gmock.h" @@ -76,7 +76,7 @@ class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { MOCK_METHOD1(OnError, void(AudioOutputStream* stream)); }; -class MockAudioManagerLinux : public AudioManagerLinux { +class MockAudioManagerAlsa : public AudioManagerAlsa { public: MOCK_METHOD0(Init, void()); MOCK_METHOD0(HasAudioOutputDevices, bool()); @@ -109,7 +109,7 @@ class MockAudioManagerLinux : public AudioManagerLinux { class AlsaPcmOutputStreamTest : public testing::Test { protected: AlsaPcmOutputStreamTest() { - mock_manager_.reset(new StrictMock<MockAudioManagerLinux>()); + mock_manager_.reset(new StrictMock<MockAudioManagerAlsa>()); } virtual ~AlsaPcmOutputStreamTest() { @@ -171,7 +171,7 @@ class AlsaPcmOutputStreamTest : public testing::Test { static void* kFakeHints[]; StrictMock<MockAlsaWrapper> mock_alsa_wrapper_; - scoped_ptr<StrictMock<MockAudioManagerLinux> > mock_manager_; + scoped_ptr<StrictMock<MockAudioManagerAlsa> > mock_manager_; base::MessageLoop message_loop_; scoped_refptr<media::DataBuffer> packet_; diff --git a/media/audio/linux/alsa_util.cc b/media/audio/alsa/alsa_util.cc index 176ef69..f26cbd3 100644 --- a/media/audio/linux/alsa_util.cc +++ b/media/audio/alsa/alsa_util.cc @@ -1,13 +1,13 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 "media/audio/linux/alsa_util.h" +#include "media/audio/alsa/alsa_util.h" #include <string> #include "base/logging.h" -#include "media/audio/linux/alsa_wrapper.h" +#include "media/audio/alsa/alsa_wrapper.h" namespace alsa_util { diff --git a/media/audio/linux/alsa_util.h b/media/audio/alsa/alsa_util.h index 53cf80a..a23ab31 100644 --- a/media/audio/linux/alsa_util.h +++ b/media/audio/alsa/alsa_util.h @@ -1,9 +1,9 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 MEDIA_AUDIO_LINUX_ALSA_UTIL_H_ -#define MEDIA_AUDIO_LINUX_ALSA_UTIL_H_ +#ifndef MEDIA_AUDIO_ALSA_ALSA_UTIL_H_ +#define MEDIA_AUDIO_ALSA_ALSA_UTIL_H_ #include <alsa/asoundlib.h> #include <string> @@ -44,4 +44,4 @@ snd_mixer_elem_t* LoadCaptureMixerElement(media::AlsaWrapper* wrapper, } // namespace alsa_util -#endif // MEDIA_AUDIO_LINUX_ALSA_UTIL_H_ +#endif // MEDIA_AUDIO_ALSA_ALSA_UTIL_H_ diff --git a/media/audio/linux/alsa_wrapper.cc b/media/audio/alsa/alsa_wrapper.cc index c1ce359..969f3c4 100644 --- a/media/audio/linux/alsa_wrapper.cc +++ b/media/audio/alsa/alsa_wrapper.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 "media/audio/linux/alsa_wrapper.h" +#include "media/audio/alsa/alsa_wrapper.h" #include <alsa/asoundlib.h> diff --git a/media/audio/linux/alsa_wrapper.h b/media/audio/alsa/alsa_wrapper.h index 30d9463..4b3c295 100644 --- a/media/audio/linux/alsa_wrapper.h +++ b/media/audio/alsa/alsa_wrapper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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. // @@ -6,6 +6,9 @@ // we want to use. It's purpose is to allow injection of a mock so that the // higher level code is testable. +#ifndef MEDIA_AUDIO_ALSA_ALSA_WRAPPER_H_ +#define MEDIA_AUDIO_ALSA_ALSA_WRAPPER_H_ + #include <alsa/asoundlib.h> #include "base/basictypes.h" @@ -79,3 +82,5 @@ class MEDIA_EXPORT AlsaWrapper { }; } // namespace media + +#endif // MEDIA_AUDIO_ALSA_ALSA_WRAPPER_H_ diff --git a/media/audio/alsa/audio_manager_alsa.cc b/media/audio/alsa/audio_manager_alsa.cc new file mode 100644 index 0000000..6c9696a --- /dev/null +++ b/media/audio/alsa/audio_manager_alsa.cc @@ -0,0 +1,361 @@ +// Copyright 2013 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 "media/audio/alsa/audio_manager_alsa.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_CRAS) +#include "media/audio/cras/audio_manager_cras.h" +#endif +#include "media/audio/alsa/alsa_input.h" +#include "media/audio/alsa/alsa_output.h" +#include "media/audio/alsa/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", +}; + +// static +void AudioManagerAlsa::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 AudioManagerAlsa::HasAudioOutputDevices() { + return HasAnyAlsaAudioDevice(kStreamPlayback); +} + +bool AudioManagerAlsa::HasAudioInputDevices() { + return HasAnyAlsaAudioDevice(kStreamCapture); +} + +AudioManagerAlsa::AudioManagerAlsa() + : wrapper_(new AlsaWrapper()) { + SetMaxOutputStreamsAllowed(kMaxOutputStreams); +} + +AudioManagerAlsa::~AudioManagerAlsa() { + Shutdown(); +} + +void AudioManagerAlsa::ShowAudioInputSettings() { + ShowLinuxAudioInputSettings(); +} + +void AudioManagerAlsa::GetAudioInputDeviceNames( + AudioDeviceNames* device_names) { + DCHECK(device_names->empty()); + GetAlsaAudioDevices(kStreamCapture, device_names); +} + +void AudioManagerAlsa::GetAudioOutputDeviceNames( + AudioDeviceNames* device_names) { + DCHECK(device_names->empty()); + GetAlsaAudioDevices(kStreamPlayback, device_names); +} + +AudioParameters AudioManagerAlsa::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 AudioManagerAlsa::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 AudioManagerAlsa::GetAlsaDevicesInfo( + AudioManagerAlsa::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 AudioManagerAlsa::IsAlsaDeviceAvailable( + AudioManagerAlsa::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* AudioManagerAlsa::UnwantedDeviceTypeWhenEnumerating( + AudioManagerAlsa::StreamType wanted_type) { + return wanted_type == kStreamPlayback ? "Input" : "Output"; +} + +bool AudioManagerAlsa::HasAnyAlsaAudioDevice( + AudioManagerAlsa::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* AudioManagerAlsa::MakeLinearOutputStream( + const AudioParameters& params) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); + return MakeOutputStream(params); +} + +AudioOutputStream* AudioManagerAlsa::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* AudioManagerAlsa::MakeLinearInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); + return MakeInputStream(params, device_id); +} + +AudioInputStream* AudioManagerAlsa::MakeLowLatencyInputStream( + const AudioParameters& params, const std::string& device_id) { + DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); + return MakeInputStream(params, device_id); +} + +AudioParameters AudioManagerAlsa::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* AudioManagerAlsa::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* AudioManagerAlsa::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()); +} + +} // namespace media diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/alsa/audio_manager_alsa.h index ab284df..c8ed7c1 100644 --- a/media/audio/linux/audio_manager_linux.h +++ b/media/audio/alsa/audio_manager_alsa.h @@ -1,9 +1,9 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2013 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 MEDIA_AUDIO_LINUX_AUDIO_MANAGER_LINUX_H_ -#define MEDIA_AUDIO_LINUX_AUDIO_MANAGER_LINUX_H_ +#ifndef MEDIA_AUDIO_ALSA_AUDIO_MANAGER_ALSA_H_ +#define MEDIA_AUDIO_ALSA_AUDIO_MANAGER_ALSA_H_ #include <string> #include "base/compiler_specific.h" @@ -15,9 +15,9 @@ namespace media { class AlsaWrapper; -class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { +class MEDIA_EXPORT AudioManagerAlsa : public AudioManagerBase { public: - AudioManagerLinux(); + AudioManagerAlsa(); static void ShowLinuxAudioInputSettings(); @@ -45,7 +45,7 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; protected: - virtual ~AudioManagerLinux(); + virtual ~AudioManagerAlsa(); virtual AudioParameters GetPreferredOutputStreamParameters( const std::string& output_device_id, @@ -86,9 +86,9 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { scoped_ptr<AlsaWrapper> wrapper_; - DISALLOW_COPY_AND_ASSIGN(AudioManagerLinux); + DISALLOW_COPY_AND_ASSIGN(AudioManagerAlsa); }; } // namespace media -#endif // MEDIA_AUDIO_LINUX_AUDIO_MANAGER_LINUX_H_ +#endif // MEDIA_AUDIO_ALSA_AUDIO_MANAGER_ALSA_H_ diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc index 994353e..a187e3b 100644 --- a/media/audio/audio_low_latency_input_output_unittest.cc +++ b/media/audio/audio_low_latency_input_output_unittest.cc @@ -18,8 +18,8 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_LINUX) || defined(OS_OPENBSD) -#include "media/audio/linux/audio_manager_linux.h" +#if defined(USE_ALSA) +#include "media/audio/alsa/audio_manager_alsa.h" #elif defined(OS_MACOSX) #include "media/audio/mac/audio_manager_mac.h" #elif defined(OS_WIN) @@ -27,18 +27,22 @@ #include "media/audio/win/core_audio_util_win.h" #elif defined(OS_ANDROID) #include "media/audio/android/audio_manager_android.h" +#else +#include "media/audio/fake_audio_manager.h" #endif namespace media { -#if defined(OS_LINUX) || defined(OS_OPENBSD) -typedef AudioManagerLinux AudioManagerAnyPlatform; +#if defined(USE_ALSA) +typedef AudioManagerAlsa AudioManagerAnyPlatform; #elif defined(OS_MACOSX) typedef AudioManagerMac AudioManagerAnyPlatform; #elif defined(OS_WIN) typedef AudioManagerWin AudioManagerAnyPlatform; #elif defined(OS_ANDROID) typedef AudioManagerAndroid AudioManagerAnyPlatform; +#else +typedef FakeAudioManager AudioManagerAnyPlatform; #endif // Limits the number of delay measurements we can store in an array and diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc index 4747c2e..e96cef1 100644 --- a/media/audio/audio_manager_unittest.cc +++ b/media/audio/audio_manager_unittest.cc @@ -9,9 +9,9 @@ #include "media/audio/audio_manager_base.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_LINUX) -#include "media/audio/linux/audio_manager_linux.h" -#endif // defined(OS_LINUX) +#if defined(USE_ALSA) +#include "media/audio/alsa/audio_manager_alsa.h" +#endif // defined(USE_ALSA) #if defined(OS_WIN) #include "base/win/scoped_com_initializer.h" @@ -288,8 +288,8 @@ TEST_F(AudioManagerTest, EnumerateInputDevicesAlsa) { if (!CanRunInputTest()) return; - VLOG(2) << "Testing AudioManagerLinux."; - audio_manager_.reset(new AudioManagerLinux()); + VLOG(2) << "Testing AudioManagerAlsa."; + audio_manager_.reset(new AudioManagerAlsa()); AudioDeviceNames device_names; audio_manager_->GetAudioInputDeviceNames(&device_names); CheckDeviceNames(device_names); @@ -299,8 +299,8 @@ TEST_F(AudioManagerTest, EnumerateOutputDevicesAlsa) { if (!CanRunOutputTest()) return; - VLOG(2) << "Testing AudioManagerLinux."; - audio_manager_.reset(new AudioManagerLinux()); + VLOG(2) << "Testing AudioManagerAlsa."; + audio_manager_.reset(new AudioManagerAlsa()); AudioDeviceNames device_names; audio_manager_->GetAudioOutputDeviceNames(&device_names); CheckDeviceNames(device_names); diff --git a/media/audio/cras/cras_input.cc b/media/audio/cras/cras_input.cc index fd574dc..c41f364 100644 --- a/media/audio/cras/cras_input.cc +++ b/media/audio/cras/cras_input.cc @@ -10,9 +10,9 @@ #include "base/bind.h" #include "base/logging.h" #include "base/time/time.h" +#include "media/audio/alsa/alsa_util.h" #include "media/audio/audio_manager.h" #include "media/audio/cras/audio_manager_cras.h" -#include "media/audio/linux/alsa_util.h" namespace media { diff --git a/media/audio/cras/cras_unified.cc b/media/audio/cras/cras_unified.cc index 906f209..c85cf59 100644 --- a/media/audio/cras/cras_unified.cc +++ b/media/audio/cras/cras_unified.cc @@ -8,8 +8,8 @@ #include "base/command_line.h" #include "base/logging.h" +#include "media/audio/alsa/alsa_util.h" #include "media/audio/cras/audio_manager_cras.h" -#include "media/audio/linux/alsa_util.h" namespace media { diff --git a/media/audio/fake_audio_manager.cc b/media/audio/fake_audio_manager.cc new file mode 100644 index 0000000..c346289 --- /dev/null +++ b/media/audio/fake_audio_manager.cc @@ -0,0 +1,68 @@ +// Copyright 2013 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 "media/audio/fake_audio_manager.h" + +namespace media { + +FakeAudioManager::FakeAudioManager() {} + +FakeAudioManager::~FakeAudioManager() { + Shutdown(); +} + +// Implementation of AudioManager. +bool FakeAudioManager::HasAudioOutputDevices() { return false; } + +bool FakeAudioManager::HasAudioInputDevices() { return false; } + +// Implementation of AudioManagerBase. +AudioOutputStream* FakeAudioManager::MakeLinearOutputStream( + const AudioParameters& params) { + return FakeAudioOutputStream::MakeFakeStream(this, params); +} + +AudioOutputStream* FakeAudioManager::MakeLowLatencyOutputStream( + const AudioParameters& params, + const std::string& device_id, + const std::string& input_device_id) { + return FakeAudioOutputStream::MakeFakeStream(this, params); +} + +AudioInputStream* FakeAudioManager::MakeLinearInputStream( + const AudioParameters& params, + const std::string& device_id) { + return FakeAudioInputStream::MakeFakeStream(this, params); +} + +AudioInputStream* FakeAudioManager::MakeLowLatencyInputStream( + const AudioParameters& params, + const std::string& device_id) { + return FakeAudioInputStream::MakeFakeStream(this, params); +} + +AudioParameters FakeAudioManager::GetPreferredOutputStreamParameters( + const std::string& output_device_id, + const AudioParameters& input_params) { + static const int kDefaultOutputBufferSize = 2048; + static const int kDefaultSampleRate = 48000; + 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()) { + 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); + } + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + sample_rate, bits_per_sample, buffer_size); +} + +} // namespace media diff --git a/media/audio/fake_audio_manager.h b/media/audio/fake_audio_manager.h new file mode 100644 index 0000000..d230739 --- /dev/null +++ b/media/audio/fake_audio_manager.h @@ -0,0 +1,51 @@ +// Copyright 2013 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 MEDIA_AUDIO_FAKE_AUDIO_MANAGER_H_ +#define MEDIA_AUDIO_FAKE_AUDIO_MANAGER_H_ + +#include <string> +#include "base/compiler_specific.h" +#include "media/audio/audio_manager_base.h" +#include "media/audio/fake_audio_input_stream.h" +#include "media/audio/fake_audio_output_stream.h" + +namespace media { + +class MEDIA_EXPORT FakeAudioManager : public AudioManagerBase { + public: + FakeAudioManager(); + + // Implementation of AudioManager. + virtual bool HasAudioOutputDevices() OVERRIDE; + virtual bool HasAudioInputDevices() OVERRIDE; + + // Implementation of AudioManagerBase. + virtual AudioOutputStream* MakeLinearOutputStream( + const AudioParameters& params) OVERRIDE; + virtual AudioOutputStream* MakeLowLatencyOutputStream( + const AudioParameters& params, + const std::string& device_id, + const std::string& input_device_id) OVERRIDE; + virtual AudioInputStream* MakeLinearInputStream(const AudioParameters& params, + const std::string& device_id) + OVERRIDE; + virtual AudioInputStream* MakeLowLatencyInputStream( + const AudioParameters& params, + const std::string& device_id) OVERRIDE; + + protected: + virtual ~FakeAudioManager(); + + virtual AudioParameters GetPreferredOutputStreamParameters( + const std::string& output_device_id, + const AudioParameters& input_params) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(FakeAudioManager); +}; + +} // namespace media + +#endif // MEDIA_AUDIO_FAKE_AUDIO_MANAGER_H_ 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 diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc index 4aac9c5..c5b78d7 100644 --- a/media/audio/pulse/audio_manager_pulse.cc +++ b/media/audio/pulse/audio_manager_pulse.cc @@ -10,8 +10,8 @@ #include "base/logging.h" #include "base/nix/xdg_util.h" #include "base/stl_util.h" +#include "media/audio/alsa/audio_manager_alsa.h" #include "media/audio/audio_parameters.h" -#include "media/audio/linux/audio_manager_linux.h" #include "media/audio/pulse/pulse_input.h" #include "media/audio/pulse/pulse_output.h" #include "media/audio/pulse/pulse_unified.h" @@ -77,7 +77,7 @@ bool AudioManagerPulse::HasAudioInputDevices() { } void AudioManagerPulse::ShowAudioInputSettings() { - AudioManagerLinux::ShowLinuxAudioInputSettings(); + AudioManagerAlsa::ShowLinuxAudioInputSettings(); } void AudioManagerPulse::GetAudioDeviceNames( diff --git a/media/media.gyp b/media/media.gyp index d1e638a..8c3a2af 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -22,7 +22,7 @@ 'media_use_libvpx%': 1, }], # ALSA usage. - ['OS=="linux" or OS=="freebsd" or OS=="solaris"', { + ['(OS=="linux" or OS=="freebsd" or OS=="solaris") and embedded!=1', { 'use_alsa%': 1, }, { 'use_alsa%': 0, @@ -62,6 +62,16 @@ ], 'sources': [ 'audio/agc_audio_stream.h', + 'audio/alsa/alsa_input.cc', + 'audio/alsa/alsa_input.h', + 'audio/alsa/alsa_output.cc', + 'audio/alsa/alsa_output.h', + 'audio/alsa/alsa_util.cc', + 'audio/alsa/alsa_util.h', + 'audio/alsa/alsa_wrapper.cc', + 'audio/alsa/alsa_wrapper.h', + 'audio/alsa/audio_manager_alsa.cc', + 'audio/alsa/audio_manager_alsa.h', 'audio/android/audio_manager_android.cc', 'audio/android/audio_manager_android.h', 'audio/android/opensles_input.cc', @@ -115,16 +125,10 @@ 'audio/fake_audio_consumer.h', 'audio/fake_audio_input_stream.cc', 'audio/fake_audio_input_stream.h', + 'audio/fake_audio_manager.cc', + 'audio/fake_audio_manager.h', 'audio/fake_audio_output_stream.cc', 'audio/fake_audio_output_stream.h', - 'audio/linux/alsa_input.cc', - 'audio/linux/alsa_input.h', - 'audio/linux/alsa_output.cc', - 'audio/linux/alsa_output.h', - 'audio/linux/alsa_util.cc', - 'audio/linux/alsa_util.h', - 'audio/linux/alsa_wrapper.cc', - 'audio/linux/alsa_wrapper.h', 'audio/linux/audio_manager_linux.cc', 'audio/linux/audio_manager_linux.h', 'audio/mac/aggregate_device_manager.cc', @@ -573,9 +577,11 @@ '-lasound', ], }, + 'defines': [ + 'USE_ALSA', + ], }, { # use_alsa==0 - 'sources/': [ ['exclude', '/alsa_'], - ['exclude', '/audio_manager_linux'] ], + 'sources/': [ ['exclude', '(^|/)alsa/'], ], }], ['OS!="openbsd"', { 'sources!': [ @@ -875,6 +881,7 @@ ], 'sources': [ 'audio/android/audio_android_unittest.cc', + 'audio/alsa/alsa_output_unittest.cc', 'audio/audio_input_controller_unittest.cc', 'audio/audio_input_unittest.cc', 'audio/audio_input_volume_unittest.cc', @@ -886,7 +893,6 @@ 'audio/audio_parameters_unittest.cc', 'audio/audio_power_monitor_unittest.cc', 'audio/fake_audio_consumer_unittest.cc', - 'audio/linux/alsa_output_unittest.cc', 'audio/mac/audio_auhal_mac_unittest.cc', 'audio/mac/audio_device_listener_mac_unittest.cc', 'audio/mac/audio_low_latency_input_mac_unittest.cc', @@ -1064,7 +1070,7 @@ }], ['use_alsa==0', { 'sources!': [ - 'audio/linux/alsa_output_unittest.cc', + 'audio/alsa/alsa_output_unittest.cc', 'audio/audio_low_latency_input_output_unittest.cc', ], }], diff --git a/tools/valgrind/tsan/suppressions.txt b/tools/valgrind/tsan/suppressions.txt index 7e25d0b..6497f29 100644 --- a/tools/valgrind/tsan/suppressions.txt +++ b/tools/valgrind/tsan/suppressions.txt @@ -1069,7 +1069,7 @@ { bug_256792 ThreadSanitizer:Race - fun:media::AudioManagerLinux::~AudioManagerLinux + fun:media::AudioManagerAlsa::~AudioManagerAlsa fun:content::MockAudioManager::~MockAudioManager fun:content::MockAudioManager::~MockAudioManager fun:base::DefaultDeleter* |