1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/alsa/audio_manager_alsa.h" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/command_line.h" 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/environment.h" 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/files/file_path.h" 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/logging.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/metrics/histogram.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/nix/xdg_util.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/process/launch.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/stl_util.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/audio_output_dispatcher.h" 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/audio_parameters.h" 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(USE_CRAS) 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/cras/audio_manager_cras.h" 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/alsa/alsa_input.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/alsa/alsa_output.h" 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/alsa/alsa_wrapper.h" 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(USE_PULSEAUDIO) 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/audio/pulse/audio_manager_pulse.h" 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/base/channel_layout.h" 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/base/limits.h" 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "media/base/media_switches.h" 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace media { 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Maximum number of output streams that can be open simultaneously. 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static const int kMaxOutputStreams = 50; 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Default sample rate for input and output streams. 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static const int kDefaultSampleRate = 48000; 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Since "default", "pulse" and "dmix" devices are virtual devices mapped to 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// real devices, we remove them from the list to avoiding duplicate counting. 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// In addition, note that we support no more than 2 channels for recording, 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// hence surround devices are not stored in the list. 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)static const char* kInvalidAudioInputDevices[] = { 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "default", 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "dmix", 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "null", 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "pulse", 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "surround", 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioManagerAlsa::ShowLinuxAudioInputSettings() { 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<base::Environment> env(base::Environment::Create()); 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CommandLine command_line(CommandLine::NO_PROGRAM); 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (base::nix::GetDesktopEnvironment(env.get())) { 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_GNOME: 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command_line.SetProgram(base::FilePath("gnome-volume-control")); 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_KDE3: 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_KDE4: 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command_line.SetProgram(base::FilePath("kmix")); 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case base::nix::DESKTOP_ENVIRONMENT_UNITY: 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command_line.SetProgram(base::FilePath("gnome-control-center")); 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command_line.AppendArg("sound"); 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command_line.AppendArg("input"); 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG(ERROR) << "Failed to show audio input settings: we don't know " 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << "what command to use for your desktop environment."; 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::LaunchProcess(command_line, base::LaunchOptions(), NULL); 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Implementation of AudioManager. 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool AudioManagerAlsa::HasAudioOutputDevices() { 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return HasAnyAlsaAudioDevice(kStreamPlayback); 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool AudioManagerAlsa::HasAudioInputDevices() { 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return HasAnyAlsaAudioDevice(kStreamCapture); 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AudioManagerAlsa::AudioManagerAlsa(AudioLogFactory* audio_log_factory) 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : AudioManagerBase(audio_log_factory), 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) wrapper_(new AlsaWrapper()) { 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SetMaxOutputStreamsAllowed(kMaxOutputStreams); 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioManagerAlsa::~AudioManagerAlsa() { 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Shutdown(); 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioManagerAlsa::ShowAudioInputSettings() { 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ShowLinuxAudioInputSettings(); 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioManagerAlsa::GetAudioInputDeviceNames( 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioDeviceNames* device_names) { 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(device_names->empty()); 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetAlsaAudioDevices(kStreamCapture, device_names); 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioManagerAlsa::GetAudioOutputDeviceNames( 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioDeviceNames* device_names) { 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(device_names->empty()); 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetAlsaAudioDevices(kStreamPlayback, device_names); 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioParameters AudioManagerAlsa::GetInputStreamParameters( 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& device_id) { 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const int kDefaultInputBufferSize = 1024; 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return AudioParameters( 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) kDefaultSampleRate, 16, kDefaultInputBufferSize); 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioManagerAlsa::GetAlsaAudioDevices( 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) StreamType type, 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) media::AudioDeviceNames* device_names) { 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Constants specified by the ALSA API for device hints. 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kPcmInterfaceName[] = "pcm"; 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int card = -1; 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Loop through the sound cards to get ALSA device hints. 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) while (!wrapper_->CardNext(&card) && card >= 0) { 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void** hints = NULL; 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!error) { 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetAlsaDevicesInfo(type, hints, device_names); 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Destroy the hints now that we're done with it. 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) wrapper_->DeviceNameFreeHint(hints); 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: " 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << wrapper_->StrError(error); 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AudioManagerAlsa::GetAlsaDevicesInfo( 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioManagerAlsa::StreamType type, 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void** hints, 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) media::AudioDeviceNames* device_names) { 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kIoHintName[] = "IOID"; 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kNameHintName[] = "NAME"; 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kDescriptionHintName[] = "DESC"; 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type); 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Only examine devices of the right type. Valid values are 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // "Input", "Output", and NULL which means both input and output. 155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<char, base::FreeDeleter> io(wrapper_->DeviceNameGetHint( 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *hint_iter, kIoHintName)); 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0) 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) continue; 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Found a device, prepend the default device since we always want 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // it to be on the top of the list for all platforms. And there is 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // no duplicate counting here since it is only done if the list is 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // still empty. Note, pulse has exclusively opened the default 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // device, so we must open the device via the "default" moniker. 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (device_names->empty()) { 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) device_names->push_front(media::AudioDeviceName( 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioManagerBase::kDefaultDeviceName, 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioManagerBase::kDefaultDeviceId)); 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Get the unique device name for the device. 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<char, base::FreeDeleter> unique_device_name( 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Find out if the device is available. 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (IsAlsaDeviceAvailable(type, unique_device_name.get())) { 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Get the description for the device. 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<char, base::FreeDeleter> desc(wrapper_->DeviceNameGetHint( 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *hint_iter, kDescriptionHintName)); 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) media::AudioDeviceName name; 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) name.unique_id = unique_device_name.get(); 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (desc) { 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Use the more user friendly description as name. 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Replace '\n' with '-'. 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) char* pret = strchr(desc.get(), '\n'); 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (pret) 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *pret = '-'; 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) name.device_name = desc.get(); 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Virtual devices don't necessarily have descriptions. 192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Use their names instead. 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) name.device_name = unique_device_name.get(); 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Store the device information. 197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) device_names->push_back(name); 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool AudioManagerAlsa::IsAlsaDeviceAvailable( 204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioManagerAlsa::StreamType type, 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char* device_name) { 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!device_name) 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We do prefix matches on the device name to see whether to include 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // it or not. 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (type == kStreamCapture) { 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Check if the device is in the list of invalid devices. 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) { 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (strncmp(kInvalidAudioInputDevices[i], device_name, 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) strlen(kInvalidAudioInputDevices[i])) == 0) 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(kStreamPlayback, type); 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We prefer the device type that maps straight to hardware but 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // goes through software conversion if needed (e.g. incompatible 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // sample rate). 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(joi): Should we prefer "hw" instead? 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kDeviceTypeDesired[] = "plughw"; 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return strncmp(kDeviceTypeDesired, 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) device_name, 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) arraysize(kDeviceTypeDesired) - 1) == 0; 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const char* AudioManagerAlsa::UnwantedDeviceTypeWhenEnumerating( 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioManagerAlsa::StreamType wanted_type) { 235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return wanted_type == kStreamPlayback ? "Input" : "Output"; 236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool AudioManagerAlsa::HasAnyAlsaAudioDevice( 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AudioManagerAlsa::StreamType stream) { 240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kPcmInterfaceName[] = "pcm"; 241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const char kIoHintName[] = "IOID"; 242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void** hints = NULL; 243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool has_device = false; 244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int card = -1; 245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Loop through the sound cards. 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Don't use snd_device_name_hint(-1,..) since there is a access violation 248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // inside this ALSA API with libasound.so.2.0.0. 249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) { 250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!error) { 252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Only examine devices that are |stream| capable. Valid values are 254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // "Input", "Output", and NULL which means both input and output. 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<char, base::FreeDeleter> io(wrapper_->DeviceNameGetHint( 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) *hint_iter, kIoHintName)); 257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char* unwanted_type = UnwantedDeviceTypeWhenEnumerating(stream); 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (io != NULL && strcmp(unwanted_type, io.get()) == 0) 259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) continue; // Wrong type, skip the device. 260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Found an input device. 262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) has_device = true; 263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Destroy the hints now that we're done with it. 267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) wrapper_->DeviceNameFreeHint(hints); 268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) hints = NULL; 269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DLOG(WARNING) << "HasAnyAudioDevice: unable to get device hints: " 271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) << wrapper_->StrError(error); 272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return has_device; 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioOutputStream* AudioManagerAlsa::MakeLinearOutputStream( 279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& params) { 280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return MakeOutputStream(params); 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioOutputStream* AudioManagerAlsa::MakeLowLatencyOutputStream( 285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& params, 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& device_id) { 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return MakeOutputStream(params); 290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioInputStream* AudioManagerAlsa::MakeLinearInputStream( 293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return MakeInputStream(params, device_id); 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioInputStream* AudioManagerAlsa::MakeLowLatencyInputStream( 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return MakeInputStream(params, device_id); 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioParameters AudioManagerAlsa::GetPreferredOutputStreamParameters( 305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& output_device_id, 306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& input_params) { 307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(tommi): Support |output_device_id|. 308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!"; 309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static const int kDefaultOutputBufferSize = 2048; 310f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 311f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int sample_rate = kDefaultSampleRate; 312f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int buffer_size = kDefaultOutputBufferSize; 313f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int bits_per_sample = 16; 314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (input_params.IsValid()) { 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Some clients, such as WebRTC, have a more limited use case and work 316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // acceptably with a smaller buffer size. The check below allows clients 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // which want to try a smaller buffer size on Linux to do so. 318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(dalecurtis): This should include bits per channel and channel layout 319f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // eventually. 320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) sample_rate = input_params.sample_rate(); 321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bits_per_sample = input_params.bits_per_sample(); 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) channel_layout = input_params.channel_layout(); 323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) buffer_size = std::min(input_params.frames_per_buffer(), buffer_size); 324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 325f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int user_buffer_size = GetUserBufferSize(); 327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (user_buffer_size) 328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) buffer_size = user_buffer_size; 329f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 330f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return AudioParameters( 3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sample_rate, bits_per_sample, buffer_size, AudioParameters::NO_EFFECTS); 333f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioOutputStream* AudioManagerAlsa::MakeOutputStream( 336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& params) { 337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice; 338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch( 339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switches::kAlsaOutputDevice)) { 340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switches::kAlsaOutputDevice); 342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return new AlsaPcmOutputStream(device_name, params, wrapper_.get(), this); 344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AudioInputStream* AudioManagerAlsa::MakeInputStream( 347f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 348f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ? 349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AlsaPcmInputStream::kAutoSelectDevice : device_id; 350f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) { 351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switches::kAlsaInputDevice); 353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 354f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 355f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return new AlsaPcmInputStream(this, device_name, params, wrapper_.get()); 356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 357f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 358f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace media 359