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 bool AudioManagerLinux::IsAlsaDeviceAvailable( |
tommi (sloooow) - chröme
2013/09/04 14:32:51
nit: looks like this could also be a static utilit
Jói
2013/09/04 15:32:22
Becuase of the use of StreamType this has the same
| |
210 AudioManagerLinux::StreamType type, | |
211 const char* device_name) { | |
200 if (!device_name) | 212 if (!device_name) |
201 return false; | 213 return false; |
202 | 214 |
203 // Check if the device is in the list of invalid devices. | 215 if (type == kStreamCapture) { |
204 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) { | 216 // Check if the device is in the list of invalid devices. |
205 if (strncmp(kInvalidAudioInputDevices[i], device_name, | 217 for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) { |
206 strlen(kInvalidAudioInputDevices[i])) == 0) | 218 if (strncmp(kInvalidAudioInputDevices[i], device_name, |
tommi (sloooow) - chröme
2013/09/04 14:32:51
Don't we also have to check that the length of the
Jói
2013/09/04 15:32:22
Prefix matching is the intent. I added a comment.
tommi (sloooow) - chröme
2013/09/04 16:43:52
Great. thanks.
| |
207 return false; | 219 strlen(kInvalidAudioInputDevices[i])) == 0) |
220 return false; | |
221 } | |
222 | |
223 return true; | |
224 } else { | |
225 DCHECK_EQ(kStreamPlayback, type); | |
226 // We prefer the device type that maps straight to hardware but | |
227 // goes through software conversion if needed (e.g. incompatible | |
228 // sample rate). | |
229 // TODO(joi): Should we prefer "hw" instead? | |
230 static const char kDeviceTypeDesired[] = "plughw"; | |
231 return strncmp(kDeviceTypeDesired, | |
232 device_name, | |
233 arraysize(kDeviceTypeDesired) - 1) == 0; | |
208 } | 234 } |
209 | |
210 return true; | |
211 } | 235 } |
212 | 236 |
213 bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) { | 237 const char* AudioManagerLinux::UnwantedDeviceTypeWhenEnumerating( |
238 AudioManagerLinux::StreamType wanted_type) { | |
239 return wanted_type == kStreamPlayback ? "Input" : "Output"; | |
240 } | |
241 | |
242 bool AudioManagerLinux::HasAnyAlsaAudioDevice( | |
243 AudioManagerLinux::StreamType stream) { | |
214 static const char kPcmInterfaceName[] = "pcm"; | 244 static const char kPcmInterfaceName[] = "pcm"; |
215 static const char kIoHintName[] = "IOID"; | 245 static const char kIoHintName[] = "IOID"; |
216 const char* kNotWantedDevice = | |
217 (stream == kStreamPlayback ? "Input" : "Output"); | |
218 void** hints = NULL; | 246 void** hints = NULL; |
219 bool has_device = false; | 247 bool has_device = false; |
220 int card = -1; | 248 int card = -1; |
221 | 249 |
222 // Loop through the sound cards. | 250 // Loop through the sound cards. |
223 // Don't use snd_device_name_hint(-1,..) since there is a access violation | 251 // 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. | 252 // inside this ALSA API with libasound.so.2.0.0. |
225 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) { | 253 while (!wrapper_->CardNext(&card) && (card >= 0) && !has_device) { |
226 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); | 254 int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints); |
227 if (!error) { | 255 if (!error) { |
228 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { | 256 for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) { |
229 // Only examine devices that are |stream| capable. Valid values are | 257 // Only examine devices that are |stream| capable. Valid values are |
230 // "Input", "Output", and NULL which means both input and output. | 258 // "Input", "Output", and NULL which means both input and output. |
231 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, | 259 scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter, |
232 kIoHintName)); | 260 kIoHintName)); |
233 if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0) | 261 const char* unwanted_type = UnwantedDeviceTypeWhenEnumerating(stream); |
262 if (io != NULL && strcmp(unwanted_type, io.get()) == 0) | |
234 continue; // Wrong type, skip the device. | 263 continue; // Wrong type, skip the device. |
235 | 264 |
236 // Found an input device. | 265 // Found an input device. |
237 has_device = true; | 266 has_device = true; |
238 break; | 267 break; |
239 } | 268 } |
240 | 269 |
241 // Destroy the hints now that we're done with it. | 270 // Destroy the hints now that we're done with it. |
242 wrapper_->DeviceNameFreeHint(hints); | 271 wrapper_->DeviceNameFreeHint(hints); |
243 hints = NULL; | 272 hints = NULL; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
343 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kPulse, kAudioIOMax); | 372 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kPulse, kAudioIOMax); |
344 return manager; | 373 return manager; |
345 } | 374 } |
346 #endif | 375 #endif |
347 | 376 |
348 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kAlsa, kAudioIOMax); | 377 UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kAlsa, kAudioIOMax); |
349 return new AudioManagerLinux(); | 378 return new AudioManagerLinux(); |
350 } | 379 } |
351 | 380 |
352 } // namespace media | 381 } // namespace media |
OLD | NEW |