Move media/audio files into media namespace
[chromium-blink-merge.git] / media / audio / linux / audio_manager_linux.cc
blob0b34aaa81186e0e6a491895c8364c5817cab0e39
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/audio/linux/audio_manager_linux.h"
7 #include "base/command_line.h"
8 #include "base/environment.h"
9 #include "base/logging.h"
10 #include "base/nix/xdg_util.h"
11 #include "base/process_util.h"
12 #include "base/stl_util.h"
13 #include "media/audio/audio_output_dispatcher.h"
14 #include "media/audio/linux/alsa_input.h"
15 #include "media/audio/linux/alsa_output.h"
16 #include "media/audio/linux/alsa_wrapper.h"
17 #if defined(USE_PULSEAUDIO)
18 #include "media/audio/pulse/pulse_output.h"
19 #endif
20 #if defined(USE_CRAS)
21 #include "media/audio/linux/cras_output.h"
22 #endif
23 #include "media/base/limits.h"
24 #include "media/base/media_switches.h"
26 namespace media {
28 // Maximum number of output streams that can be open simultaneously.
29 static const int kMaxOutputStreams = 50;
31 // Since "default", "pulse" and "dmix" devices are virtual devices mapped to
32 // real devices, we remove them from the list to avoiding duplicate counting.
33 // In addition, note that we support no more than 2 channels for recording,
34 // hence surround devices are not stored in the list.
35 static const char* kInvalidAudioInputDevices[] = {
36 "default",
37 "null",
38 "pulse",
39 "dmix",
42 // Implementation of AudioManager.
43 bool AudioManagerLinux::HasAudioOutputDevices() {
44 return HasAnyAlsaAudioDevice(kStreamPlayback);
47 bool AudioManagerLinux::HasAudioInputDevices() {
48 return HasAnyAlsaAudioDevice(kStreamCapture);
51 AudioManagerLinux::AudioManagerLinux() {
52 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
55 AudioManagerLinux::~AudioManagerLinux() {
56 Shutdown();
59 void AudioManagerLinux::Init() {
60 AudioManagerBase::Init();
61 wrapper_.reset(new AlsaWrapper());
64 void AudioManagerLinux::MuteAll() {
65 NOTIMPLEMENTED();
68 void AudioManagerLinux::UnMuteAll() {
69 NOTIMPLEMENTED();
72 bool AudioManagerLinux::CanShowAudioInputSettings() {
73 scoped_ptr<base::Environment> env(base::Environment::Create());
74 base::nix::DesktopEnvironment desktop = base::nix::GetDesktopEnvironment(
75 env.get());
76 return (desktop == base::nix::DESKTOP_ENVIRONMENT_GNOME ||
77 desktop == base::nix::DESKTOP_ENVIRONMENT_KDE3 ||
78 desktop == base::nix::DESKTOP_ENVIRONMENT_KDE4);
81 void AudioManagerLinux::ShowAudioInputSettings() {
82 scoped_ptr<base::Environment> env(base::Environment::Create());
83 base::nix::DesktopEnvironment desktop = base::nix::GetDesktopEnvironment(
84 env.get());
85 std::string command((desktop == base::nix::DESKTOP_ENVIRONMENT_GNOME) ?
86 "gnome-volume-control" : "kmix");
87 base::LaunchProcess(CommandLine(FilePath(command)), base::LaunchOptions(),
88 NULL);
91 void AudioManagerLinux::GetAudioInputDeviceNames(
92 media::AudioDeviceNames* device_names) {
93 DCHECK(device_names->empty());
94 GetAlsaAudioInputDevices(device_names);
97 void AudioManagerLinux::GetAlsaAudioInputDevices(
98 media::AudioDeviceNames* device_names) {
99 // Constants specified by the ALSA API for device hints.
100 static const char kPcmInterfaceName[] = "pcm";
101 int card = -1;
103 // Loop through the sound cards to get ALSA device hints.
104 while (!wrapper_->CardNext(&card) && card >= 0) {
105 void** hints = NULL;
106 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
107 if (!error) {
108 GetAlsaDevicesInfo(hints, device_names);
110 // Destroy the hints now that we're done with it.
111 wrapper_->DeviceNameFreeHint(hints);
112 } else {
113 DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: "
114 << wrapper_->StrError(error);
119 void AudioManagerLinux::GetAlsaDevicesInfo(
120 void** hints, media::AudioDeviceNames* device_names) {
121 static const char kIoHintName[] = "IOID";
122 static const char kNameHintName[] = "NAME";
123 static const char kDescriptionHintName[] = "DESC";
124 static const char kOutputDevice[] = "Output";
126 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
127 // Only examine devices that are input capable. Valid values are
128 // "Input", "Output", and NULL which means both input and output.
129 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
130 kIoHintName));
131 if (io != NULL && strcmp(kOutputDevice, io.get()) == 0)
132 continue;
134 // Found an input device, prepend the default device since we always want
135 // it to be on the top of the list for all platforms. And there is no
136 // duplicate counting here since it is only done if the list is still empty.
137 // Note, pulse has exclusively opened the default device, so we must open
138 // the device via the "default" moniker.
139 if (device_names->empty()) {
140 device_names->push_front(media::AudioDeviceName(
141 AudioManagerBase::kDefaultDeviceName,
142 AudioManagerBase::kDefaultDeviceId));
145 // Get the unique device name for the device.
146 scoped_ptr_malloc<char> unique_device_name(
147 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
149 // Find out if the device is available.
150 if (IsAlsaDeviceAvailable(unique_device_name.get())) {
151 // Get the description for the device.
152 scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
153 *hint_iter, kDescriptionHintName));
155 media::AudioDeviceName name;
156 name.unique_id = unique_device_name.get();
157 if (desc.get()) {
158 // Use the more user friendly description as name.
159 // Replace '\n' with '-'.
160 char* pret = strchr(desc.get(), '\n');
161 if (pret)
162 *pret = '-';
163 name.device_name = desc.get();
164 } else {
165 // Virtual devices don't necessarily have descriptions.
166 // Use their names instead.
167 name.device_name = unique_device_name.get();
170 // Store the device information.
171 device_names->push_back(name);
176 bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) {
177 static const char kNotWantedSurroundDevices[] = "surround";
179 if (!device_name)
180 return false;
182 // Check if the device is in the list of invalid devices.
183 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
184 if ((strcmp(kInvalidAudioInputDevices[i], device_name) == 0) ||
185 (strncmp(kNotWantedSurroundDevices, device_name,
186 arraysize(kNotWantedSurroundDevices) - 1) == 0))
187 return false;
190 // The only way to check if the device is available is to open/close the
191 // device. Return false if it fails either of operations.
192 snd_pcm_t* device_handle = NULL;
193 if (wrapper_->PcmOpen(&device_handle,
194 device_name,
195 SND_PCM_STREAM_CAPTURE,
196 SND_PCM_NONBLOCK))
197 return false;
198 if (wrapper_->PcmClose(device_handle))
199 return false;
201 return true;
204 bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
205 static const char kPcmInterfaceName[] = "pcm";
206 static const char kIoHintName[] = "IOID";
207 const char* kNotWantedDevice =
208 (stream == kStreamPlayback ? "Input" : "Output");
209 void** hints = NULL;
210 bool has_device = false;
211 int card = -1;
213 // Loop through the sound cards.
214 // Don't use snd_device_name_hint(-1,..) since there is a access violation
215 // inside this ALSA API with libasound.so.2.0.0.
216 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) {
217 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
218 if (!error) {
219 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
220 // Only examine devices that are |stream| capable. Valid values are
221 // "Input", "Output", and NULL which means both input and output.
222 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
223 kIoHintName));
224 if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
225 continue; // Wrong type, skip the device.
227 // Found an input device.
228 has_device = true;
229 break;
232 // Destroy the hints now that we're done with it.
233 wrapper_->DeviceNameFreeHint(hints);
234 hints = NULL;
235 } else {
236 DLOG(WARNING) << "HasAnyAudioDevice: unable to get device hints: "
237 << wrapper_->StrError(error);
241 return has_device;
244 AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream(
245 const AudioParameters& params) {
246 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
247 return MakeOutputStream(params);
250 AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream(
251 const AudioParameters& params) {
252 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
253 return MakeOutputStream(params);
256 AudioInputStream* AudioManagerLinux::MakeLinearInputStream(
257 const AudioParameters& params, const std::string& device_id) {
258 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
259 return MakeInputStream(params, device_id);
262 AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream(
263 const AudioParameters& params, const std::string& device_id) {
264 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
265 return MakeInputStream(params, device_id);
268 AudioOutputStream* AudioManagerLinux::MakeOutputStream(
269 const AudioParameters& params) {
270 AudioOutputStream* stream = NULL;
271 #if defined(USE_CRAS)
272 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseCras)) {
273 stream = new CrasOutputStream(params, this);
274 } else {
275 #endif
276 #if defined(USE_PULSEAUDIO)
277 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUsePulseAudio)) {
278 stream = new PulseAudioOutputStream(params, this);
279 } else {
280 #endif
281 std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice;
282 if (CommandLine::ForCurrentProcess()->HasSwitch(
283 switches::kAlsaOutputDevice)) {
284 device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
285 switches::kAlsaOutputDevice);
287 stream = new AlsaPcmOutputStream(device_name, params, wrapper_.get(), this);
288 #if defined(USE_PULSEAUDIO)
290 #endif
291 #if defined(USE_CRAS)
293 #endif
294 DCHECK(stream);
295 return stream;
298 AudioInputStream* AudioManagerLinux::MakeInputStream(
299 const AudioParameters& params, const std::string& device_id) {
301 std::string device_name = (device_id == AudioManagerBase::kDefaultDeviceId) ?
302 AlsaPcmInputStream::kAutoSelectDevice : device_id;
303 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) {
304 device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
305 switches::kAlsaInputDevice);
308 return new AlsaPcmInputStream(this, device_name, params, wrapper_.get());
311 AudioManager* CreateAudioManager() {
312 return new AudioManagerLinux();
315 } // namespace media