Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Side by Side Diff: media/audio/linux/audio_manager_linux.cc

Issue 8361031: Reland the CL 8162015. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: adding MEDIA_EXPORT to AudioDeviceName Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/linux/audio_manager_linux.h" 5 #include "media/audio/linux/audio_manager_linux.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/environment.h" 8 #include "base/environment.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/nix/xdg_util.h" 10 #include "base/nix/xdg_util.h"
(...skipping 13 matching lines...) Expand all
24 24
25 // Maximum number of output streams that can be open simultaneously. 25 // Maximum number of output streams that can be open simultaneously.
26 static const size_t kMaxOutputStreams = 50; 26 static const size_t kMaxOutputStreams = 50;
27 27
28 static const int kMaxInputChannels = 2; 28 static const int kMaxInputChannels = 2;
29 29
30 // Since "default", "pulse" and "dmix" devices are virtual devices mapped to 30 // Since "default", "pulse" and "dmix" devices are virtual devices mapped to
31 // real devices, we remove them from the list to avoiding duplicate counting. 31 // real devices, we remove them from the list to avoiding duplicate counting.
32 // In addition, note that we support no more than 2 channels for recording, 32 // In addition, note that we support no more than 2 channels for recording,
33 // hence surround devices are not stored in the list. 33 // hence surround devices are not stored in the list.
34 static const char* kInvalidAudioInputDevices[] = { 34 static const char* kInvalidAudioInputDevices[] = {
tommi (sloooow) - chröme 2011/10/24 07:05:01 nit: I'm wondering if this could be [][] instead o
no longer working on chromium 2011/10/25 20:35:53 Sorry, I don't fully understand here. I need the s
35 "default", 35 "default",
36 "null", 36 "null",
37 "pulse", 37 "pulse",
38 "dmix", 38 "dmix",
39 "surround", 39 "surround",
40 }; 40 };
41 41
42 static bool IsValidAudioInputDevice(const char* device_name) {
43 if (!device_name)
44 return false;
45
46 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
47 if (strcmp(kInvalidAudioInputDevices[i], device_name) == 0)
48 return false;
49 }
50
51 return true;
52 }
53
54 // Implementation of AudioManager. 42 // Implementation of AudioManager.
55 bool AudioManagerLinux::HasAudioOutputDevices() { 43 bool AudioManagerLinux::HasAudioOutputDevices() {
56 // TODO(ajwong): Make this actually query audio devices. 44 return HasAnyAlsaAudioDevice(kStreamPlayback);
57 return true;
58 } 45 }
59 46
60 bool AudioManagerLinux::HasAudioInputDevices() { 47 bool AudioManagerLinux::HasAudioInputDevices() {
61 if (!initialized()) { 48 return HasAnyAlsaAudioDevice(kStreamCapture);
62 return false;
63 }
64
65 // Constants specified by the ALSA API for device hints.
66 static const char kPcmInterfaceName[] = "pcm";
67 bool has_device = false;
68 void** hints = NULL;
69 int card = -1;
70
71 // Loop through the sound cards to get Alsa device hints.
72 // Don't use snd_device_name_hint(-1,..) since there is a access violation
73 // inside this ALSA API with libasound.so.2.0.0.
74 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) {
75 int error = wrapper_->DeviceNameHint(card,
76 kPcmInterfaceName,
77 &hints);
78 if (error == 0) {
79 has_device = HasAnyValidAudioInputDevice(hints);
80
81 // Destroy the hints now that we're done with it.
82 wrapper_->DeviceNameFreeHint(hints);
83 hints = NULL;
84 } else {
85 LOG(ERROR) << "Unable to get device hints: " << wrapper_->StrError(error);
86 }
87 }
88
89 return has_device;
90 } 49 }
91 50
92 AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream( 51 AudioOutputStream* AudioManagerLinux::MakeAudioOutputStream(
93 const AudioParameters& params) { 52 const AudioParameters& params) {
94 // Early return for testing hook. Do this before checking for 53 // Early return for testing hook. Do this before checking for
95 // |initialized_|. 54 // |initialized_|.
96 if (params.format == AudioParameters::AUDIO_MOCK) { 55 if (params.format == AudioParameters::AUDIO_MOCK) {
97 return FakeAudioOutputStream::MakeFakeStream(params); 56 return FakeAudioOutputStream::MakeFakeStream(params);
98 } 57 }
99 58
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 93
135 if (params.format == AudioParameters::AUDIO_MOCK) { 94 if (params.format == AudioParameters::AUDIO_MOCK) {
136 return FakeAudioInputStream::MakeFakeStream(params); 95 return FakeAudioInputStream::MakeFakeStream(params);
137 } else if (params.format != AudioParameters::AUDIO_PCM_LINEAR) { 96 } else if (params.format != AudioParameters::AUDIO_PCM_LINEAR) {
138 return NULL; 97 return NULL;
139 } 98 }
140 99
141 if (!initialized()) 100 if (!initialized())
142 return NULL; 101 return NULL;
143 102
103 // TODO(xians): Pass the device name From AudioInputController instead.
144 std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice; 104 std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice;
145 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) { 105 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAlsaInputDevice)) {
146 device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 106 device_name = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
147 switches::kAlsaInputDevice); 107 switches::kAlsaInputDevice);
148 } 108 }
149 109
150 AlsaPcmInputStream* stream = new AlsaPcmInputStream( 110 AlsaPcmInputStream* stream = new AlsaPcmInputStream(
151 device_name, params, wrapper_.get()); 111 device_name, params, wrapper_.get());
152 112
153 return stream; 113 return stream;
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 base::nix::DesktopEnvironment desktop = base::nix::GetDesktopEnvironment( 166 base::nix::DesktopEnvironment desktop = base::nix::GetDesktopEnvironment(
207 env.get()); 167 env.get());
208 std::string command((desktop == base::nix::DESKTOP_ENVIRONMENT_GNOME) ? 168 std::string command((desktop == base::nix::DESKTOP_ENVIRONMENT_GNOME) ?
209 "gnome-volume-control" : "kmix"); 169 "gnome-volume-control" : "kmix");
210 base::LaunchProcess(CommandLine(FilePath(command)), base::LaunchOptions(), 170 base::LaunchProcess(CommandLine(FilePath(command)), base::LaunchOptions(),
211 NULL); 171 NULL);
212 } 172 }
213 173
214 void AudioManagerLinux::GetAudioInputDeviceNames( 174 void AudioManagerLinux::GetAudioInputDeviceNames(
215 media::AudioDeviceNames* device_names) { 175 media::AudioDeviceNames* device_names) {
216 // TODO(xians): query a full list of valid devices. 176 device_names->clear();
tommi (sloooow) - chröme 2011/10/24 07:05:01 nit: you could also make it a requirement that the
no longer working on chromium 2011/10/25 20:35:53 Done.
217 if (HasAudioInputDevices()) { 177
218 // Add the default device to the list. 178 GetAlsaAudioInputDevices(device_names);
219 // We use index 0 to make up the unique_id to identify the 179
220 // default devices. 180 if (!device_names->empty()) {
221 media::AudioDeviceName name; 181 // Prepend the default device to the list since we always want it to be
222 name.device_name = AudioManagerBase::kDefaultDeviceName; 182 // on the top of the list for all platforms. There is no duplicate
223 name.unique_id = "0"; 183 // counting here since the default device has been abstracted out before.
224 device_names->push_back(name); 184 // We use index 0 to make up the unique_id to identify the default device.
185 device_names->push_front(media::AudioDeviceName(
186 AudioManagerBase::kDefaultDeviceName, "0"));
225 } 187 }
226 } 188 }
227 189
228 bool AudioManagerLinux::HasAnyValidAudioInputDevice(void** hints) { 190 void AudioManagerLinux::GetAlsaAudioInputDevices(
191 media::AudioDeviceNames* device_names) {
192 // Constants specified by the ALSA API for device hints.
193 static const char kPcmInterfaceName[] = "pcm";
194 int card = -1;
195
196 // Loop through the sound cards to get ALSA device hints.
197 while (!wrapper_->CardNext(&card) && (card >= 0)) {
tommi (sloooow) - chröme 2011/10/24 07:05:01 nit: no need for () around the second expression
no longer working on chromium 2011/10/25 20:35:53 Done.
198 void** hints = NULL;
199 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
200 if (!error) {
201 GetAlsaDevicesInfo(hints, device_names);
202
203 // Destroy the hints now that we're done with it.
204 wrapper_->DeviceNameFreeHint(hints);
205 } else {
206 DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: "
207 << wrapper_->StrError(error);
208 }
209 }
210 }
211
212 void AudioManagerLinux::GetAlsaDevicesInfo(
213 void** hints, media::AudioDeviceNames* device_names) {
229 static const char kIoHintName[] = "IOID"; 214 static const char kIoHintName[] = "IOID";
230 static const char kNameHintName[] = "NAME"; 215 static const char kNameHintName[] = "NAME";
216 static const char kDescriptionHintName[] = "DESC";
231 static const char kOutputDevice[] = "Output"; 217 static const char kOutputDevice[] = "Output";
232 218
233 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 219 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
234 // Only examine devices that are input capable. Valid values are 220 // Only examine devices that are input capable. Valid values are
235 // "Input", "Output", and NULL which means both input and output. 221 // "Input", "Output", and NULL which means both input and output.
236 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, 222 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
237 kIoHintName)); 223 kIoHintName));
238 if (io != NULL && strcmp(kOutputDevice, io.get()) == 0) 224 if (io != NULL && strcmp(kOutputDevice, io.get()) == 0)
239 continue; 225 continue;
240 226
241 scoped_ptr_malloc<char> hint_device_name( 227 // Get the unique device name for the device.
228 scoped_ptr_malloc<char> unique_device_name(
242 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); 229 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
243 if (IsValidAudioInputDevice(hint_device_name.get())) 230
244 return true; 231 // Find out if the device is available.
232 if (IsAlsaDeviceAvailable(unique_device_name.get())) {
233 // Get the description for the device.
234 scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
235 *hint_iter, kDescriptionHintName));
236
237 media::AudioDeviceName name;
238 name.unique_id = unique_device_name.get();
239 if (desc.get()) {
240 // Use the more user friendly description as name.
241 // Replace '\n' with '-'.
242 char* pret = strchr(desc.get(), '\n');
tommi (sloooow) - chröme 2011/10/24 07:05:01 nit: This won't replace all occurrences of \n but
no longer working on chromium 2011/10/25 20:35:53 It is not a problem here since the string only con
243 if (pret)
244 *pret = '-';
245 name.device_name = desc.get();
246 } else {
247 // Virtual devices don't necessarily have descriptions.
248 // Use their names instead.
249 name.device_name = unique_device_name.get();
250 }
251
252 // Store the device information.
253 device_names->push_back(name);
254 }
255 }
256 }
257
258 bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) {
259 if (!device_name)
260 return false;
261
262 // Check if the device is in the list of invalid devices.
263 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
264 if (!strncmp(kInvalidAudioInputDevices[i], device_name,
265 strlen(kInvalidAudioInputDevices[i])))
tommi (sloooow) - chröme 2011/10/24 07:05:01 nit: see comment at the top for the strlen call
266 return false;
245 } 267 }
246 268
247 return false; 269 // The only way to check if the device is available is to open/close the
270 // device. Return false if it fails either of operations.
271 snd_pcm_t* device_handle = NULL;
272 if (wrapper_->PcmOpen(
273 &device_handle, device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK))
tommi (sloooow) - chröme 2011/10/24 07:05:01 I think this should be indented 4 more spaces so t
274 return false;
275 if (wrapper_->PcmClose(device_handle))
276 return false;
277
278 return true;
279 }
280
281 bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
282 static const char kPcmInterfaceName[] = "pcm";
283 static const char kIoHintName[] = "IOID";
284 const char* kNotWantedDevice =
285 (stream == kStreamPlayback ? "Input" : "Output");
286 void** hints = NULL;
287 bool has_device = false;
288 int card = -1;
289
290 // Loop through the sound cards.
291 // Don't use snd_device_name_hint(-1,..) since there is a access violation
292 // inside this ALSA API with libasound.so.2.0.0.
293 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) {
294 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
295 if (!error) {
296 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
297 // Only examine devices that are |stream| capable. Valid values are
298 // "Input", "Output", and NULL which means both input and output.
299 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
300 kIoHintName));
301 if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
302 continue; // Wrong type, skip the device.
303
304 // Found an input device.
305 has_device = true;
306 break;
307 }
308
309 // Destroy the hints now that we're done with it.
310 wrapper_->DeviceNameFreeHint(hints);
311 hints = NULL;
312 } else {
313 DLOG(WARNING) << "HasAnyAudioDevice: unable to get device hints: "
314 << wrapper_->StrError(error);
315 }
316 }
317
318 return has_device;
248 } 319 }
249 320
250 // static 321 // static
251 AudioManager* AudioManager::CreateAudioManager() { 322 AudioManager* AudioManager::CreateAudioManager() {
252 return new AudioManagerLinux(); 323 return new AudioManagerLinux();
253 } 324 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698