diff options
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* |