Chromium Code Reviews| 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 |