Commit d344256e authored by joi@chromium.org's avatar joi@chromium.org

Output device enumeration for Alsa, plus unit test.

TBR=vrk@chromium.org
BUG=276894

Review URL: https://chromiumcodereview.appspot.com/23480030

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221704 0039d316-1c4b-4281-b951-d872f2087c98
parent 42654b64
......@@ -317,7 +317,7 @@ void AudioManagerBase::GetAudioInputDeviceNames(
void AudioManagerBase::GetAudioOutputDeviceNames(
AudioDeviceNames* device_names) {
// TODO(joi): Remove this and keep pure virtual once implemented everywhere.
NOTIMPLEMENTED();
NOTREACHED() << "Don't use this yet, it's not ready on all platforms!";
}
void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
......
......@@ -7,21 +7,19 @@
#include "media/audio/audio_manager.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_PULSEAUDIO)
#include "media/audio/pulse/audio_manager_pulse.h"
#endif
#endif // defined(USE_PULSEAUDIO)
namespace media {
// TODO(joi): Remove guards once implemented for all platforms.
TEST(AudioManagerTest, GetAudioOutputDeviceNames) {
#if defined(USE_PULSEAUDIO)
scoped_ptr<AudioManager> audio_manager_pulse(AudioManagerPulse::Create());
if (!audio_manager_pulse)
return;
void GetAudioOutputDeviceNamesImpl(AudioManager* audio_manager) {
AudioDeviceNames device_names;
audio_manager_pulse->GetAudioOutputDeviceNames(&device_names);
audio_manager->GetAudioOutputDeviceNames(&device_names);
VLOG(2) << "Got " << device_names.size() << " audio output devices.";
for (AudioDeviceNames::iterator it = device_names.begin();
......@@ -31,7 +29,26 @@ TEST(AudioManagerTest, GetAudioOutputDeviceNames) {
EXPECT_FALSE(it->device_name.empty());
VLOG(2) << "Device ID(" << it->unique_id << "), label: " << it->device_name;
}
}
TEST(AudioManagerTest, GetAudioOutputDeviceNames) {
#if defined(USE_PULSEAUDIO)
{
VLOG(2) << "Testing AudioManagerPulse.";
scoped_ptr<AudioManager> pulse_audio_manager(AudioManagerPulse::Create());
if (pulse_audio_manager.get())
GetAudioOutputDeviceNamesImpl(pulse_audio_manager.get());
else
LOG(WARNING) << "No pulseaudio on this system.";
}
#endif // defined(USE_PULSEAUDIO)
#if defined(USE_ALSA)
{
VLOG(2) << "Testing AudioManagerLinux.";
scoped_ptr<AudioManager> alsa_audio_manager(new AudioManagerLinux());
GetAudioOutputDeviceNamesImpl(alsa_audio_manager.get());
}
#endif // defined(USE_ALSA)
}
} // namespace media
......@@ -42,9 +42,9 @@ static const int kDefaultSampleRate = 48000;
// hence surround devices are not stored in the list.
static const char* kInvalidAudioInputDevices[] = {
"default",
"dmix",
"null",
"pulse",
"dmix",
"surround",
};
......@@ -105,7 +105,13 @@ void AudioManagerLinux::ShowAudioInputSettings() {
void AudioManagerLinux::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
GetAlsaAudioInputDevices(device_names);
GetAlsaAudioDevices(kStreamCapture, device_names);
}
void AudioManagerLinux::GetAudioOutputDeviceNames(
media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
GetAlsaAudioDevices(kStreamPlayback, device_names);
}
AudioParameters AudioManagerLinux::GetInputStreamParameters(
......@@ -117,7 +123,8 @@ AudioParameters AudioManagerLinux::GetInputStreamParameters(
kDefaultSampleRate, 16, kDefaultInputBufferSize);
}
void AudioManagerLinux::GetAlsaAudioInputDevices(
void AudioManagerLinux::GetAlsaAudioDevices(
StreamType type,
media::AudioDeviceNames* device_names) {
// Constants specified by the ALSA API for device hints.
static const char kPcmInterfaceName[] = "pcm";
......@@ -128,37 +135,40 @@ void AudioManagerLinux::GetAlsaAudioInputDevices(
void** hints = NULL;
int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
if (!error) {
GetAlsaDevicesInfo(hints, device_names);
GetAlsaDevicesInfo(type, hints, device_names);
// Destroy the hints now that we're done with it.
wrapper_->DeviceNameFreeHint(hints);
} else {
DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: "
DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: "
<< wrapper_->StrError(error);
}
}
}
void AudioManagerLinux::GetAlsaDevicesInfo(
void** hints, media::AudioDeviceNames* device_names) {
AudioManagerLinux::StreamType type,
void** hints,
media::AudioDeviceNames* device_names) {
static const char kIoHintName[] = "IOID";
static const char kNameHintName[] = "NAME";
static const char kDescriptionHintName[] = "DESC";
static const char kOutputDevice[] = "Output";
const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type);
for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
// Only examine devices that are input capable. Valid values are
// 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(kOutputDevice, io.get()) == 0)
if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0)
continue;
// Found an input 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.
// 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,
......@@ -170,7 +180,7 @@ void AudioManagerLinux::GetAlsaDevicesInfo(
wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
// Find out if the device is available.
if (IsAlsaDeviceAvailable(unique_device_name.get())) {
if (IsAlsaDeviceAvailable(type, unique_device_name.get())) {
// Get the description for the device.
scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
*hint_iter, kDescriptionHintName));
......@@ -196,25 +206,46 @@ void AudioManagerLinux::GetAlsaDevicesInfo(
}
}
bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) {
// static
bool AudioManagerLinux::IsAlsaDeviceAvailable(
AudioManagerLinux::StreamType type,
const char* device_name) {
if (!device_name)
return false;
// 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;
// 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;
}
}
return true;
// static
const char* AudioManagerLinux::UnwantedDeviceTypeWhenEnumerating(
AudioManagerLinux::StreamType wanted_type) {
return wanted_type == kStreamPlayback ? "Input" : "Output";
}
bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
bool AudioManagerLinux::HasAnyAlsaAudioDevice(
AudioManagerLinux::StreamType stream) {
static const char kPcmInterfaceName[] = "pcm";
static const char kIoHintName[] = "IOID";
const char* kNotWantedDevice =
(stream == kStreamPlayback ? "Input" : "Output");
void** hints = NULL;
bool has_device = false;
int card = -1;
......@@ -230,7 +261,8 @@ bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
// "Input", "Output", and NULL which means both input and output.
scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
kIoHintName));
if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
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.
......
......@@ -27,6 +27,8 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
virtual void ShowAudioInputSettings() OVERRIDE;
virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
OVERRIDE;
virtual void GetAudioOutputDeviceNames(media::AudioDeviceNames* device_names)
OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
......@@ -55,14 +57,22 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
kStreamCapture,
};
// Gets a list of available ALSA input devices.
void GetAlsaAudioInputDevices(media::AudioDeviceNames* device_names);
// Gets a list of available ALSA devices.
void GetAlsaAudioDevices(StreamType type,
media::AudioDeviceNames* device_names);
// Gets the ALSA devices' names and ids.
void GetAlsaDevicesInfo(void** hint, media::AudioDeviceNames* device_names);
// Gets the ALSA devices' names and ids that support streams of the
// given type.
void GetAlsaDevicesInfo(StreamType type,
void** hint,
media::AudioDeviceNames* device_names);
// Checks if the specific ALSA device is available.
bool IsAlsaDeviceAvailable(const char* device_name);
static bool IsAlsaDeviceAvailable(StreamType type,
const char* device_name);
static const char* UnwantedDeviceTypeWhenEnumerating(
StreamType wanted_type);
// Returns true if a device is present for the given stream type.
bool HasAnyAlsaAudioDevice(StreamType stream);
......
......@@ -1042,6 +1042,11 @@
'base/media_file_checker_unittest.cc',
],
}],
['use_alsa==1', {
'defines': [
'USE_ALSA',
],
}],
['use_pulseaudio==1', {
'defines': [
'USE_PULSEAUDIO',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment