Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |