OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 | 35 |
36 // Default sample rate for input and output streams. | 36 // Default sample rate for input and output streams. |
37 static const int kDefaultSampleRate = 48000; | 37 static const int kDefaultSampleRate = 48000; |
38 | 38 |
39 // Since "default", "pulse" and "dmix" devices are virtual devices mapped to | 39 // Since "default", "pulse" and "dmix" devices are virtual devices mapped to |
40 // real devices, we remove them from the list to avoiding duplicate counting. | 40 // real devices, we remove them from the list to avoiding duplicate counting. |
41 // In addition, note that we support no more than 2 channels for recording, | 41 // In addition, note that we support no more than 2 channels for recording, |
42 // hence surround devices are not stored in the list. | 42 // hence surround devices are not stored in the list. |
43 static const char* kInvalidAudioInputDevices[] = { | 43 static const char* kInvalidAudioInputDevices[] = { |
44 "default", | 44 "default", |
| 45 "dmix", |
45 "null", | 46 "null", |
46 "pulse", | 47 "pulse", |
47 "dmix", | |
48 "surround", | 48 "surround", |
49 }; | 49 }; |
50 | 50 |
51 enum LinuxAudioIO { | 51 enum LinuxAudioIO { |
52 kPulse, | 52 kPulse, |
53 kAlsa, | 53 kAlsa, |
54 kCras, | 54 kCras, |
55 kAudioIOMax // Must always be last! | 55 kAudioIOMax // Must always be last! |
56 }; | 56 }; |
57 | 57 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 Shutdown(); | 98 Shutdown(); |
99 } | 99 } |
100 | 100 |
101 void AudioManagerLinux::ShowAudioInputSettings() { | 101 void AudioManagerLinux::ShowAudioInputSettings() { |
102 ShowLinuxAudioInputSettings(); | 102 ShowLinuxAudioInputSettings(); |
103 } | 103 } |
104 | 104 |
105 void AudioManagerLinux::GetAudioInputDeviceNames( | 105 void AudioManagerLinux::GetAudioInputDeviceNames( |
106 media::AudioDeviceNames* device_names) { | 106 media::AudioDeviceNames* device_names) { |
107 DCHECK(device_names->empty()); | 107 DCHECK(device_names->empty()); |
108 GetAlsaAudioInputDevices(device_names); | 108 GetAlsaAudioDevices(kStreamCapture, device_names); |
| 109 } |
| 110 |
| 111 void AudioManagerLinux::GetAudioOutputDeviceNames( |
| 112 media::AudioDeviceNames* device_names) { |
| 113 DCHECK(device_names->empty()); |
| 114 GetAlsaAudioDevices(kStreamPlayback, device_names); |
109 } | 115 } |
110 | 116 |
111 AudioParameters AudioManagerLinux::GetInputStreamParameters( | 117 AudioParameters AudioManagerLinux::GetInputStreamParameters( |
112 const std::string& device_id) { | 118 const std::string& device_id) { |
113 static const int kDefaultInputBufferSize = 1024; | 119 static const int kDefaultInputBufferSize = 1024; |
114 | 120 |
115 return AudioParameters( | 121 return AudioParameters( |
116 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, | 122 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, |
117 kDefaultSampleRate, 16, kDefaultInputBufferSize); | 123 kDefaultSampleRate, 16, kDefaultInputBufferSize); |
118 } | 124 } |
119 | 125 |
120 void AudioManagerLinux::GetAlsaAudioInputDevices( | 126 void AudioManagerLinux::GetAlsaAudioDevices( |
| 127 StreamType type, |
121 media::AudioDeviceNames* device_names) { | 128 media::AudioDeviceNames* device_names) { |
122 // Constants specified by the ALSA API for device hints. | 129 // Constants specified by the ALSA API for device hints. |
123 static const char kPcmInterfaceName[] = "pcm"; | 130 static const char kPcmInterfaceName[] = "pcm"; |
124 int card = -1; | 131 int card = -1; |
125 | 132 |
126 // Loop through the sound cards to get ALSA device hints. | 133 // Loop through the sound cards to get ALSA device hints. |
127 while (!wrapper_->CardNext(&card) && card >= 0) { | 134 while (!wrapper_->CardNext(&card) && card >= 0) { |
128 void** hints = NULL; | 135 void** hints = NULL; |
129 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); | 136 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); |
130 if (!error) { | 137 if (!error) { |
131 GetAlsaDevicesInfo(hints, device_names); | 138 GetAlsaDevicesInfo(type, hints, device_names); |
132 | 139 |
133 // Destroy the hints now that we're done with it. | 140 // Destroy the hints now that we're done with it. |
134 wrapper_->DeviceNameFreeHint(hints); | 141 wrapper_->DeviceNameFreeHint(hints); |
135 } else { | 142 } else { |
136 DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: " | 143 DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: " |
137 << wrapper_->StrError(error); | 144 << wrapper_->StrError(error); |
138 } | 145 } |
139 } | 146 } |
140 } | 147 } |
141 | 148 |
142 void AudioManagerLinux::GetAlsaDevicesInfo( | 149 void AudioManagerLinux::GetAlsaDevicesInfo( |
143 void** hints, media::AudioDeviceNames* device_names) { | 150 AudioManagerLinux::StreamType type, |
| 151 void** hints, |
| 152 media::AudioDeviceNames* device_names) { |
144 static const char kIoHintName[] = "IOID"; | 153 static const char kIoHintName[] = "IOID"; |
145 static const char kNameHintName[] = "NAME"; | 154 static const char kNameHintName[] = "NAME"; |
146 static const char kDescriptionHintName[] = "DESC"; | 155 static const char kDescriptionHintName[] = "DESC"; |
147 static const char kOutputDevice[] = "Output"; | 156 |
| 157 const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type); |
148 | 158 |
149 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { | 159 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { |
150 // Only examine devices that are input capable. Valid values are | 160 // Only examine devices of the right type. Valid values are |
151 // "Input", "Output", and NULL which means both input and output. | 161 // "Input", "Output", and NULL which means both input and output. |
152 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, | 162 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, |
153 kIoHintName)); | 163 kIoHintName)); |
154 if (io != NULL && strcmp(kOutputDevice, io.get()) == 0) | 164 if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0) |
155 continue; | 165 continue; |
156 | 166 |
157 // Found an input device, prepend the default device since we always want | 167 // Found a device, prepend the default device since we always want |
158 // it to be on the top of the list for all platforms. And there is no | 168 // it to be on the top of the list for all platforms. And there is |
159 // duplicate counting here since it is only done if the list is still empty. | 169 // no duplicate counting here since it is only done if the list is |
160 // Note, pulse has exclusively opened the default device, so we must open | 170 // still empty. Note, pulse has exclusively opened the default |
161 // the device via the "default" moniker. | 171 // device, so we must open the device via the "default" moniker. |
162 if (device_names->empty()) { | 172 if (device_names->empty()) { |
163 device_names->push_front(media::AudioDeviceName( | 173 device_names->push_front(media::AudioDeviceName( |
164 AudioManagerBase::kDefaultDeviceName, | 174 AudioManagerBase::kDefaultDeviceName, |
165 AudioManagerBase::kDefaultDeviceId)); | 175 AudioManagerBase::kDefaultDeviceId)); |
166 } | 176 } |
167 | 177 |
168 // Get the unique device name for the device. | 178 // Get the unique device name for the device. |
169 scoped_ptr_malloc<char> unique_device_name( | 179 scoped_ptr_malloc<char> unique_device_name( |
170 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); | 180 wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName)); |
171 | 181 |
172 // Find out if the device is available. | 182 // Find out if the device is available. |
173 if (IsAlsaDeviceAvailable(unique_device_name.get())) { | 183 if (IsAlsaDeviceAvailable(type, unique_device_name.get())) { |
174 // Get the description for the device. | 184 // Get the description for the device. |
175 scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint( | 185 scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint( |
176 *hint_iter, kDescriptionHintName)); | 186 *hint_iter, kDescriptionHintName)); |
177 | 187 |
178 media::AudioDeviceName name; | 188 media::AudioDeviceName name; |
179 name.unique_id = unique_device_name.get(); | 189 name.unique_id = unique_device_name.get(); |
180 if (desc) { | 190 if (desc) { |
181 // Use the more user friendly description as name. | 191 // Use the more user friendly description as name. |
182 // Replace '\n' with '-'. | 192 // Replace '\n' with '-'. |
183 char* pret = strchr(desc.get(), '\n'); | 193 char* pret = strchr(desc.get(), '\n'); |
184 if (pret) | 194 if (pret) |
185 *pret = '-'; | 195 *pret = '-'; |
186 name.device_name = desc.get(); | 196 name.device_name = desc.get(); |
187 } else { | 197 } else { |
188 // Virtual devices don't necessarily have descriptions. | 198 // Virtual devices don't necessarily have descriptions. |
189 // Use their names instead. | 199 // Use their names instead. |
190 name.device_name = unique_device_name.get(); | 200 name.device_name = unique_device_name.get(); |
191 } | 201 } |
192 | 202 |
193 // Store the device information. | 203 // Store the device information. |
194 device_names->push_back(name); | 204 device_names->push_back(name); |
195 } | 205 } |
196 } | 206 } |
197 } | 207 } |
198 | 208 |
199 bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) { | 209 // static |
| 210 bool AudioManagerLinux::IsAlsaDeviceAvailable( |
| 211 AudioManagerLinux::StreamType type, |
| 212 const char* device_name) { |
200 if (!device_name) | 213 if (!device_name) |
201 return false; | 214 return false; |
202 | 215 |
203 // Check if the device is in the list of invalid devices. | 216 // We do prefix matches on the device name to see whether to include |
204 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) { | 217 // it or not. |
205 if (strncmp(kInvalidAudioInputDevices[i], device_name, | 218 if (type == kStreamCapture) { |
206 strlen(kInvalidAudioInputDevices[i])) == 0) | 219 // Check if the device is in the list of invalid devices. |
207 return false; | 220 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) { |
| 221 if (strncmp(kInvalidAudioInputDevices[i], device_name, |
| 222 strlen(kInvalidAudioInputDevices[i])) == 0) |
| 223 return false; |
| 224 } |
| 225 return true; |
| 226 } else { |
| 227 DCHECK_EQ(kStreamPlayback, type); |
| 228 // We prefer the device type that maps straight to hardware but |
| 229 // goes through software conversion if needed (e.g. incompatible |
| 230 // sample rate). |
| 231 // TODO(joi): Should we prefer "hw" instead? |
| 232 static const char kDeviceTypeDesired[] = "plughw"; |
| 233 return strncmp(kDeviceTypeDesired, |
| 234 device_name, |
| 235 arraysize(kDeviceTypeDesired) - 1) == 0; |
208 } | 236 } |
209 | |
210 return true; | |
211 } | 237 } |
212 | 238 |
213 bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) { | 239 // static |
| 240 const char* AudioManagerLinux::UnwantedDeviceTypeWhenEnumerating( |
| 241 AudioManagerLinux::StreamType wanted_type) { |
| 242 return wanted_type == kStreamPlayback ? "Input" : "Output"; |
| 243 } |
| 244 |
| 245 bool AudioManagerLinux::HasAnyAlsaAudioDevice( |
| 246 AudioManagerLinux::StreamType stream) { |
214 static const char kPcmInterfaceName[] = "pcm"; | 247 static const char kPcmInterfaceName[] = "pcm"; |
215 static const char kIoHintName[] = "IOID"; | 248 static const char kIoHintName[] = "IOID"; |
216 const char* kNotWantedDevice = | |
217 (stream == kStreamPlayback ? "Input" : "Output"); | |
218 void** hints = NULL; | 249 void** hints = NULL; |
219 bool has_device = false; | 250 bool has_device = false; |
220 int card = -1; | 251 int card = -1; |
221 | 252 |
222 // Loop through the sound cards. | 253 // Loop through the sound cards. |
223 // Don't use snd_device_name_hint(-1,..) since there is a access violation | 254 // Don't use snd_device_name_hint(-1,..) since there is a access violation |
224 // inside this ALSA API with libasound.so.2.0.0. | 255 // inside this ALSA API with libasound.so.2.0.0. |
225 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) { | 256 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) { |
226 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); | 257 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); |
227 if (!error) { | 258 if (!error) { |
228 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { | 259 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { |
229 // Only examine devices that are |stream| capable. Valid values are | 260 // Only examine devices that are |stream| capable. Valid values are |
230 // "Input", "Output", and NULL which means both input and output. | 261 // "Input", "Output", and NULL which means both input and output. |
231 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, | 262 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, |
232 kIoHintName)); | 263 kIoHintName)); |
233 if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0) | 264 const char* unwanted_type = UnwantedDeviceTypeWhenEnumerating(stream); |
| 265 if (io != NULL && strcmp(unwanted_type, io.get()) == 0) |
234 continue; // Wrong type, skip the device. | 266 continue; // Wrong type, skip the device. |
235 | 267 |
236 // Found an input device. | 268 // Found an input device. |
237 has_device = true; | 269 has_device = true; |
238 break; | 270 break; |
239 } | 271 } |
240 | 272 |
241 // Destroy the hints now that we're done with it. | 273 // Destroy the hints now that we're done with it. |
242 wrapper_->DeviceNameFreeHint(hints); | 274 wrapper_->DeviceNameFreeHint(hints); |
243 hints = NULL; | 275 hints = NULL; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kPulse, kAudioIOMax); | 380 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kPulse, kAudioIOMax); |
349 return manager; | 381 return manager; |
350 } | 382 } |
351 #endif | 383 #endif |
352 | 384 |
353 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kAlsa, kAudioIOMax); | 385 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kAlsa, kAudioIOMax); |
354 return new AudioManagerLinux(); | 386 return new AudioManagerLinux(); |
355 } | 387 } |
356 | 388 |
357 } // namespace media | 389 } // namespace media |
OLD | NEW |