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

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: rebase Created 9 years, 1 month 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
« no previous file with comments | « media/audio/linux/audio_manager_linux.h ('k') | media/media.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 DCHECK(device_names->empty());
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) {
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');
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])))
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(&device_handle,
273 device_name,
274 SND_PCM_STREAM_CAPTURE,
275 SND_PCM_NONBLOCK))
276 return false;
277 if (wrapper_->PcmClose(device_handle))
278 return false;
279
280 return true;
281 }
282
283 bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
284 static const char kPcmInterfaceName[] = "pcm";
285 static const char kIoHintName[] = "IOID";
286 const char* kNotWantedDevice =
287 (stream == kStreamPlayback ? "Input" : "Output");
288 void** hints = NULL;
289 bool has_device = false;
290 int card = -1;
291
292 // Loop through the sound cards.
293 // Don't use snd_device_name_hint(-1,..) since there is a access violation
294 // inside this ALSA API with libasound.so.2.0.0.
295 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) {
296 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
297 if (!error) {
298 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
299 // Only examine devices that are |stream| capable. Valid values are
300 // "Input", "Output", and NULL which means both input and output.
301 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
302 kIoHintName));
303 if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
304 continue; // Wrong type, skip the device.
305
306 // Found an input device.
307 has_device = true;
308 break;
309 }
310
311 // Destroy the hints now that we're done with it.
312 wrapper_->DeviceNameFreeHint(hints);
313 hints = NULL;
314 } else {
315 DLOG(WARNING) << "HasAnyAudioDevice: unable to get device hints: "
316 << wrapper_->StrError(error);
317 }
318 }
319
320 return has_device;
248 } 321 }
249 322
250 // static 323 // static
251 AudioManager* AudioManager::CreateAudioManager() { 324 AudioManager* AudioManager::CreateAudioManager() {
252 return new AudioManagerLinux(); 325 return new AudioManagerLinux();
253 } 326 }
OLDNEW
« no previous file with comments | « media/audio/linux/audio_manager_linux.h ('k') | media/media.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698