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

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

Issue 8162015: The first step to add device selection to linux. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: 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 21 matching lines...) Expand all
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[] = {
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 // Empty the name list.
henrika (OOO until Aug 14) 2011/10/07 12:07:51 remove
no longer working on chromium 2011/10/10 13:49:24 Done.
217 if (HasAudioInputDevices()) { 177 device_names->clear();
218 // Add the default device to the list. 178
219 // We use index 0 to make up the unique_id to identify the 179 GetAlsaAudioInputDevices(device_names);
220 // default devices. 180
221 media::AudioDeviceName name; 181 if (!device_names->empty()) {
222 name.device_name = AudioManagerBase::kDefaultDeviceName; 182 // Pre-pend the default device to the list.
henrika (OOO until Aug 14) 2011/10/07 12:07:51 Perhaps extend the comments why this is needed.
scherkus (not reviewing) 2011/10/07 16:54:45 nit: Pre-pend -> Prepend also agree w/ henrik on
no longer working on chromium 2011/10/10 13:49:24 Done.
no longer working on chromium 2011/10/10 13:49:24 Done.
223 name.unique_id = "0"; 183 // We use index 0 to make up the unique_id to identify the default devices.
224 device_names->push_back(name); 184 device_names->push_front(media::AudioDeviceName(
185 AudioManagerBase::kDefaultDeviceName, "0"));
henrika (OOO until Aug 14) 2011/10/07 12:07:51 indent by 4
no longer working on chromium 2011/10/10 13:49:24 Done.
225 } 186 }
226 } 187 }
227 188
228 bool AudioManagerLinux::HasAnyValidAudioInputDevice(void** hints) { 189 void AudioManagerLinux::GetAlsaAudioInputDevices(
190 media::AudioDeviceNames* device_names) {
191
scherkus (not reviewing) 2011/10/07 16:54:45 nit: remove blank line
no longer working on chromium 2011/10/10 13:49:24 Done.
192 // Constants specified by the ALSA API for device hints.
193 static const char kPcmInterfaceName[] = "pcm";
194 void** hints = NULL;
195 int card = -1;
196
197 // Loop through the sound cards to get Alsa device hints.
henrika (OOO until Aug 14) 2011/10/07 12:07:51 ALSA?
no longer working on chromium 2011/10/10 13:49:24 Done.
198 while (!wrapper_->CardNext(&card) && (card >= 0)) {
199 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
henrika (OOO until Aug 14) 2011/10/07 12:07:51 Do you allocate memory here? I think you should m
no longer working on chromium 2011/10/10 13:49:24 Done.
200 if (!error) {
201 // Get devices
henrika (OOO until Aug 14) 2011/10/07 12:07:51 remove
no longer working on chromium 2011/10/10 13:49:24 Done.
202 GetAlsaDevicesInfo(hints, device_names);
203
204 // Destroy the hints now that we're done with it.
205 wrapper_->DeviceNameFreeHint(hints);
206 hints = NULL;
henrika (OOO until Aug 14) 2011/10/07 12:07:51 remove
no longer working on chromium 2011/10/10 13:49:24 Done.
207 } else {
208 LOG(WARNING) << "GetAudioInputDevices error: unable to get device hints: "
henrika (OOO until Aug 14) 2011/10/07 12:07:51 DLOG
no longer working on chromium 2011/10/10 13:49:24 Done.
209 << wrapper_->StrError(error);
210 }
211 }
212 }
213
214 void AudioManagerLinux::GetAlsaDevicesInfo(
215 void** hints, media::AudioDeviceNames* device_names) {
229 static const char kIoHintName[] = "IOID"; 216 static const char kIoHintName[] = "IOID";
230 static const char kNameHintName[] = "NAME"; 217 static const char kNameHintName[] = "NAME";
218 static const char kDescriptionHintName[] = "DESC";
231 static const char kOutputDevice[] = "Output"; 219 static const char kOutputDevice[] = "Output";
232 220
233 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { 221 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
234 // Only examine devices that are input capable. Valid values are 222 // Only examine devices that are input capable. Valid values are
235 // "Input", "Output", and NULL which means both input and output. 223 // "Input", "Output", and NULL which means both input and output.
236 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, 224 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
237 kIoHintName)); 225 kIoHintName));
238 if (io != NULL && strcmp(kOutputDevice, io.get()) == 0) 226 if (io != NULL && strcmp(kOutputDevice, io.get()) == 0)
239 continue; 227 continue;
240 228
241 scoped_ptr_malloc<char> hint_device_name( 229 // Get the unique device name for the device.
230 scoped_ptr_malloc<char> unique_device_name(
242 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); 231 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
243 if (IsValidAudioInputDevice(hint_device_name.get())) 232 // Find out if the device is available.
henrika (OOO until Aug 14) 2011/10/07 12:07:51 empty line before
no longer working on chromium 2011/10/10 13:49:24 Done.
244 return true; 233 if (IsAlsaDeviceAvailable(unique_device_name.get())) {
234 // Get the description for the device.
235 scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
236 *hint_iter, kDescriptionHintName));
237
238 media::AudioDeviceName name;
239 name.unique_id = unique_device_name.get();
240 if (desc.get()) {
241 // Use the more user friendly description as name.
242 // Replace '\n' with '-'.
243 char* pret = strchr(desc.get(), '\n');
244 if (pret)
245 *pret = '-';
246 name.device_name = desc.get();
247 } else {
248 // Virtual devices don't necessarily have descriptions.
249 // Use their names instead.
250 name.device_name = unique_device_name.get();
251 }
252
253 // Store the device information.
254 device_names->push_back(name);
255 }
256 }
257 }
258
259 bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) {
260 if (!device_name)
261 return false;
262
263 // Check if the device is in the list of invalid devices.
264 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
265 if (!strncmp(kInvalidAudioInputDevices[i], device_name,
266 strlen(kInvalidAudioInputDevices[i])))
scherkus (not reviewing) 2011/10/07 16:54:45 indent by 1 more space
no longer working on chromium 2011/10/10 13:49:24 Done.
267 return false;
245 } 268 }
246 269
247 return false; 270 // The only way to check if the device is available is to open/close the
271 // device, return false if it fails either of operations.
272 snd_pcm_t* device_handle = NULL;
273 if (wrapper_->PcmOpen(&device_handle, device_name,
scherkus (not reviewing) 2011/10/07 16:54:45 how long does this take to run? The call stack is
no longer working on chromium 2011/10/10 13:49:24 I have totally 3 physical devices attached to PC,
274 SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK) < 0 ||
275 wrapper_->PcmClose(device_handle) < 0) {
scherkus (not reviewing) 2011/10/07 16:54:45 could you re-write this to be more explicit? usin
no longer working on chromium 2011/10/10 13:49:24 Done.
276 return false;
277 }
278
279 return true;
280 }
281
282 bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
283 static const char kPcmInterfaceName[] = "pcm";
284 static const char kIoHintName[] = "IOID";
285 static const char* kNotWantedDevice =
286 (stream == kStreamPlayback ? "Input" : "Output");
287 void** hints = NULL;
288 bool has_device = false;
289 int card = -1;
290
291 // Loop through the sound cards.
292 // Don't use snd_device_name_hint(-1,..) since there is a access violation
293 // inside this ALSA API with libasound.so.2.0.0.
scherkus (not reviewing) 2011/10/07 16:54:45 do you know whether we can do a compile time/run t
no longer working on chromium 2011/10/10 13:49:24 I am not sure, probably yes. But I am not sure if
294 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) {
295 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
296 if(!error) {
scherkus (not reviewing) 2011/10/07 16:54:45 space between if and (
no longer working on chromium 2011/10/10 13:49:24 Done.
297 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
298 // Only examine devices that are |stream| capable. Valid values are
299 // "Input", "Output", and NULL which means both input and output.
300 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
301 kIoHintName));
302 if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
303 continue; // Wrong type, skip the device.
304
305 // Found an input device.
306 has_device = true;
307 break;
308 }
309 // Destroy the hints now that we're done with it.
scherkus (not reviewing) 2011/10/07 16:54:45 nit: blank line before this one
no longer working on chromium 2011/10/10 13:49:24 Done.
310 wrapper_->DeviceNameFreeHint(hints);
311 hints = NULL;
312 } else {
313 LOG(WARNING) << "HasAnyAudioDevice warning: unable to get device hints: "
henrika (OOO until Aug 14) 2011/10/07 12:07:51 DLOG
henrika (OOO until Aug 14) 2011/10/07 12:07:51 remove warning
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