audio_manager_win.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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 3// found in the LICENSE file. 4 5#include "media/audio/audio_io.h" 6 7#include <windows.h> 8#include <objbase.h> // This has to be before initguid.h 9#include <initguid.h> 10#include <mmsystem.h> 11#include <setupapi.h> 12 13#include "base/bind.h" 14#include "base/bind_helpers.h" 15#include "base/command_line.h" 16#include "base/files/file_path.h" 17#include "base/memory/scoped_ptr.h" 18#include "base/message_loop/message_loop.h" 19#include "base/path_service.h" 20#include "base/process/launch.h" 21#include "base/strings/string_number_conversions.h" 22#include "base/strings/string_util.h" 23#include "base/win/windows_version.h" 24#include "media/audio/audio_parameters.h" 25#include "media/audio/win/audio_device_listener_win.h" 26#include "media/audio/win/audio_low_latency_input_win.h" 27#include "media/audio/win/audio_low_latency_output_win.h" 28#include "media/audio/win/audio_manager_win.h" 29#include "media/audio/win/audio_unified_win.h" 30#include "media/audio/win/core_audio_util_win.h" 31#include "media/audio/win/device_enumeration_win.h" 32#include "media/audio/win/wavein_input_win.h" 33#include "media/audio/win/waveout_output_win.h" 34#include "media/base/bind_to_loop.h" 35#include "media/base/channel_layout.h" 36#include "media/base/limits.h" 37#include "media/base/media_switches.h" 38 39// Libraries required for the SetupAPI and Wbem APIs used here. 40#pragma comment(lib, "setupapi.lib") 41 42// The following are defined in various DDK headers, and we (re)define them here 43// to avoid adding the DDK as a chrome dependency. 44#define DRV_QUERYDEVICEINTERFACE 0x80c 45#define DRVM_MAPPER_PREFERRED_GET 0x2015 46#define DRV_QUERYDEVICEINTERFACESIZE 0x80d 47DEFINE_GUID(AM_KSCATEGORY_AUDIO, 0x6994ad04, 0x93ef, 0x11d0, 48 0xa3, 0xcc, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96); 49 50namespace media { 51 52// Maximum number of output streams that can be open simultaneously. 53static const int kMaxOutputStreams = 50; 54 55// Up to 8 channels can be passed to the driver. This should work, given the 56// right drivers, but graceful error handling is needed. 57static const int kWinMaxChannels = 8; 58 59// We use 3 buffers for recording audio so that if a recording callback takes 60// some time to return we won't lose audio. More buffers while recording are 61// ok because they don't introduce any delay in recording, unlike in playback 62// where you first need to fill in that number of buffers before starting to 63// play. 64static const int kNumInputBuffers = 3; 65 66// Buffer size to use for input and output stream when a proper size can't be 67// determined from the system 68static const int kFallbackBufferSize = 2048; 69 70static int GetVersionPartAsInt(DWORDLONG num) { 71 return static_cast<int>(num & 0xffff); 72} 73 74// Returns a string containing the given device's description and installed 75// driver version. 76static string16 GetDeviceAndDriverInfo(HDEVINFO device_info, 77 SP_DEVINFO_DATA* device_data) { 78 // Save the old install params setting and set a flag for the 79 // SetupDiBuildDriverInfoList below to return only the installed drivers. 80 SP_DEVINSTALL_PARAMS old_device_install_params; 81 old_device_install_params.cbSize = sizeof(old_device_install_params); 82 SetupDiGetDeviceInstallParams(device_info, device_data, 83 &old_device_install_params); 84 SP_DEVINSTALL_PARAMS device_install_params = old_device_install_params; 85 device_install_params.FlagsEx |= DI_FLAGSEX_INSTALLEDDRIVER; 86 SetupDiSetDeviceInstallParams(device_info, device_data, 87 &device_install_params); 88 89 SP_DRVINFO_DATA driver_data; 90 driver_data.cbSize = sizeof(driver_data); 91 string16 device_and_driver_info; 92 if (SetupDiBuildDriverInfoList(device_info, device_data, 93 SPDIT_COMPATDRIVER)) { 94 if (SetupDiEnumDriverInfo(device_info, device_data, SPDIT_COMPATDRIVER, 0, 95 &driver_data)) { 96 DWORDLONG version = driver_data.DriverVersion; 97 device_and_driver_info = string16(driver_data.Description) + L" v" + 98 base::IntToString16(GetVersionPartAsInt((version >> 48))) + L"." + 99 base::IntToString16(GetVersionPartAsInt((version >> 32))) + L"." + 100 base::IntToString16(GetVersionPartAsInt((version >> 16))) + L"." + 101 base::IntToString16(GetVersionPartAsInt(version)); 102 } 103 SetupDiDestroyDriverInfoList(device_info, device_data, SPDIT_COMPATDRIVER); 104 } 105 106 SetupDiSetDeviceInstallParams(device_info, device_data, 107 &old_device_install_params); 108 109 return device_and_driver_info; 110} 111 112static int NumberOfWaveOutBuffers() { 113 // Use the user provided buffer count if provided. 114 int buffers = 0; 115 std::string buffers_str(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 116 switches::kWaveOutBuffers)); 117 if (base::StringToInt(buffers_str, &buffers) && buffers > 0) { 118 return buffers; 119 } 120 121 // Use 4 buffers for Vista, 3 for everyone else: 122 // - The entire Windows audio stack was rewritten for Windows Vista and wave 123 // out performance was degraded compared to XP. 124 // - The regression was fixed in Windows 7 and most configurations will work 125 // with 2, but some (e.g., some Sound Blasters) still need 3. 126 // - Some XP configurations (even multi-processor ones) also need 3. 127 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3; 128} 129 130AudioManagerWin::AudioManagerWin() { 131 if (!CoreAudioUtil::IsSupported()) { 132 // Use the Wave API for device enumeration if XP or lower. 133 enumeration_type_ = kWaveEnumeration; 134 } else { 135 // Use the MMDevice API for device enumeration if Vista or higher. 136 enumeration_type_ = kMMDeviceEnumeration; 137 } 138 139 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 140 141 // Task must be posted last to avoid races from handing out "this" to the 142 // audio thread. 143 GetMessageLoop()->PostTask(FROM_HERE, base::Bind( 144 &AudioManagerWin::CreateDeviceListener, base::Unretained(this))); 145} 146 147AudioManagerWin::~AudioManagerWin() { 148 // It's safe to post a task here since Shutdown() will wait for all tasks to 149 // complete before returning. 150 GetMessageLoop()->PostTask(FROM_HERE, base::Bind( 151 &AudioManagerWin::DestroyDeviceListener, base::Unretained(this))); 152 Shutdown(); 153} 154 155bool AudioManagerWin::HasAudioOutputDevices() { 156 return (::waveOutGetNumDevs() != 0); 157} 158 159bool AudioManagerWin::HasAudioInputDevices() { 160 return (::waveInGetNumDevs() != 0); 161} 162 163void AudioManagerWin::CreateDeviceListener() { 164 // AudioDeviceListenerWin must be initialized on a COM thread and should only 165 // be used if WASAPI / Core Audio is supported. 166 if (CoreAudioUtil::IsSupported()) { 167 output_device_listener_.reset(new AudioDeviceListenerWin(BindToLoop( 168 GetMessageLoop(), base::Bind( 169 &AudioManagerWin::NotifyAllOutputDeviceChangeListeners, 170 base::Unretained(this))))); 171 } 172} 173 174void AudioManagerWin::DestroyDeviceListener() { 175 output_device_listener_.reset(); 176} 177 178string16 AudioManagerWin::GetAudioInputDeviceModel() { 179 // Get the default audio capture device and its device interface name. 180 DWORD device_id = 0; 181 waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER), 182 DRVM_MAPPER_PREFERRED_GET, 183 reinterpret_cast<DWORD_PTR>(&device_id), NULL); 184 ULONG device_interface_name_size = 0; 185 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 186 DRV_QUERYDEVICEINTERFACESIZE, 187 reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0); 188 size_t bytes_in_char16 = sizeof(string16::value_type); 189 DCHECK_EQ(0u, device_interface_name_size % bytes_in_char16); 190 if (device_interface_name_size <= bytes_in_char16) 191 return string16(); // No audio capture device. 192 193 string16 device_interface_name; 194 string16::value_type* name_ptr = WriteInto(&device_interface_name, 195 device_interface_name_size / bytes_in_char16); 196 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 197 DRV_QUERYDEVICEINTERFACE, 198 reinterpret_cast<DWORD_PTR>(name_ptr), 199 static_cast<DWORD_PTR>(device_interface_name_size)); 200 201 // Enumerate all audio devices and find the one matching the above device 202 // interface name. 203 HDEVINFO device_info = SetupDiGetClassDevs( 204 &AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); 205 if (device_info == INVALID_HANDLE_VALUE) 206 return string16(); 207 208 DWORD interface_index = 0; 209 SP_DEVICE_INTERFACE_DATA interface_data; 210 interface_data.cbSize = sizeof(interface_data); 211 while (SetupDiEnumDeviceInterfaces(device_info, 0, &AM_KSCATEGORY_AUDIO, 212 interface_index++, &interface_data)) { 213 // Query the size of the struct, allocate it and then query the data. 214 SP_DEVINFO_DATA device_data; 215 device_data.cbSize = sizeof(device_data); 216 DWORD interface_detail_size = 0; 217 SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 0, 0, 218 &interface_detail_size, &device_data); 219 if (!interface_detail_size) 220 continue; 221 222 scoped_ptr<char[]> interface_detail_buffer(new char[interface_detail_size]); 223 SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail = 224 reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>( 225 interface_detail_buffer.get()); 226 interface_detail->cbSize = interface_detail_size; 227 if (!SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 228 interface_detail, 229 interface_detail_size, NULL, 230 &device_data)) 231 return string16(); 232 233 bool device_found = (device_interface_name == interface_detail->DevicePath); 234 235 if (device_found) 236 return GetDeviceAndDriverInfo(device_info, &device_data); 237 } 238 239 return string16(); 240} 241 242void AudioManagerWin::ShowAudioInputSettings() { 243 std::wstring program; 244 std::string argument; 245 if (!CoreAudioUtil::IsSupported()) { 246 program = L"sndvol32.exe"; 247 argument = "-R"; 248 } else { 249 program = L"control.exe"; 250 argument = "mmsys.cpl,,1"; 251 } 252 253 base::FilePath path; 254 PathService::Get(base::DIR_SYSTEM, &path); 255 path = path.Append(program); 256 CommandLine command_line(path); 257 command_line.AppendArg(argument); 258 base::LaunchProcess(command_line, base::LaunchOptions(), NULL); 259} 260 261void AudioManagerWin::GetAudioDeviceNamesImpl( 262 bool input, 263 AudioDeviceNames* device_names) { 264 DCHECK(device_names->empty()); 265 DCHECK(enumeration_type() != kUninitializedEnumeration); 266 // Enumerate all active audio-endpoint capture devices. 267 if (enumeration_type() == kWaveEnumeration) { 268 // Utilize the Wave API for Windows XP. 269 if (input) 270 GetInputDeviceNamesWinXP(device_names); 271 else 272 GetOutputDeviceNamesWinXP(device_names); 273 } else { 274 // Utilize the MMDevice API (part of Core Audio) for Vista and higher. 275 if (input) 276 GetInputDeviceNamesWin(device_names); 277 else 278 GetOutputDeviceNamesWin(device_names); 279 } 280 281 // Always add default device parameters as first element. 282 if (!device_names->empty()) { 283 AudioDeviceName name; 284 name.device_name = AudioManagerBase::kDefaultDeviceName; 285 name.unique_id = AudioManagerBase::kDefaultDeviceId; 286 device_names->push_front(name); 287 } 288} 289 290void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) { 291 GetAudioDeviceNamesImpl(true, device_names); 292} 293 294void AudioManagerWin::GetAudioOutputDeviceNames( 295 AudioDeviceNames* device_names) { 296 GetAudioDeviceNamesImpl(false, device_names); 297} 298 299AudioParameters AudioManagerWin::GetInputStreamParameters( 300 const std::string& device_id) { 301 int sample_rate = 48000; 302 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 303 if (CoreAudioUtil::IsSupported()) { 304 int hw_sample_rate = WASAPIAudioInputStream::HardwareSampleRate(device_id); 305 if (hw_sample_rate) 306 sample_rate = hw_sample_rate; 307 channel_layout = 308 WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ? 309 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; 310 } 311 312 // TODO(Henrika): improve the default buffer size value for input stream. 313 return AudioParameters( 314 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 315 sample_rate, 16, kFallbackBufferSize); 316} 317 318std::string AudioManagerWin::GetAssociatedOutputDeviceID( 319 const std::string& input_device_id) { 320 if (!CoreAudioUtil::IsSupported()) { 321 NOTIMPLEMENTED() 322 << "GetAssociatedOutputDeviceID is not supported on this OS"; 323 return std::string(); 324 } 325 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); 326} 327 328// Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR 329// mode. 330// - PCMWaveOutAudioOutputStream: Based on the waveOut API. 331AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( 332 const AudioParameters& params) { 333 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 334 if (params.channels() > kWinMaxChannels) 335 return NULL; 336 337 return new PCMWaveOutAudioOutputStream(this, 338 params, 339 NumberOfWaveOutBuffers(), 340 WAVE_MAPPER); 341} 342 343// Factory for the implementations of AudioOutputStream for 344// AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most 345// windows user's needs. 346// - PCMWaveOutAudioOutputStream: Based on the waveOut API. 347// - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. 348AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( 349 const AudioParameters& params, 350 const std::string& device_id, 351 const std::string& input_device_id) { 352 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 353 if (params.channels() > kWinMaxChannels) 354 return NULL; 355 356 if (!CoreAudioUtil::IsSupported()) { 357 // Fall back to Windows Wave implementation on Windows XP or lower. 358 DLOG_IF(ERROR, !device_id.empty() && 359 device_id != AudioManagerBase::kDefaultDeviceId) 360 << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; 361 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; 362 return new PCMWaveOutAudioOutputStream( 363 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); 364 } 365 366 // TODO(rtoy): support more than stereo input. 367 if (params.input_channels() > 0) { 368 DVLOG(1) << "WASAPIUnifiedStream is created."; 369 DLOG_IF(ERROR, !device_id.empty() && 370 device_id != AudioManagerBase::kDefaultDeviceId) 371 << "Opening by device id not supported by WASAPIUnifiedStream"; 372 return new WASAPIUnifiedStream(this, params, input_device_id); 373 } 374 375 // Pass an empty string to indicate that we want the default device 376 // since we consistently only check for an empty string in 377 // WASAPIAudioOutputStream. 378 return new WASAPIAudioOutputStream(this, 379 device_id == AudioManagerBase::kDefaultDeviceId ? 380 std::string() : device_id, 381 params, eConsole); 382} 383 384// Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR 385// mode. 386AudioInputStream* AudioManagerWin::MakeLinearInputStream( 387 const AudioParameters& params, const std::string& device_id) { 388 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 389 return CreatePCMWaveInAudioInputStream(params, device_id); 390} 391 392// Factory for the implementations of AudioInputStream for 393// AUDIO_PCM_LOW_LATENCY mode. 394AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 395 const AudioParameters& params, const std::string& device_id) { 396 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 397 AudioInputStream* stream = NULL; 398 if (!CoreAudioUtil::IsSupported()) { 399 // Fall back to Windows Wave implementation on Windows XP or lower. 400 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; 401 stream = CreatePCMWaveInAudioInputStream(params, device_id); 402 } else { 403 stream = new WASAPIAudioInputStream(this, params, device_id); 404 } 405 406 return stream; 407} 408 409std::string AudioManagerWin::GetDefaultOutputDeviceID() { 410 if (!CoreAudioUtil::IsSupported()) 411 return std::string(); 412 return CoreAudioUtil::GetDefaultOutputDeviceID(); 413} 414 415AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 416 const std::string& output_device_id, 417 const AudioParameters& input_params) { 418 const bool core_audio_supported = CoreAudioUtil::IsSupported(); 419 DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty()) 420 << "CoreAudio is required to open non-default devices."; 421 422 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 423 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 424 int sample_rate = 48000; 425 int buffer_size = kFallbackBufferSize; 426 int bits_per_sample = 16; 427 int input_channels = 0; 428 bool use_input_params = !core_audio_supported; 429 if (core_audio_supported) { 430 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 431 // TODO(rtoy): tune these values for best possible WebAudio 432 // performance. WebRTC works well at 48kHz and a buffer size of 480 433 // samples will be used for this case. Note that exclusive mode is 434 // experimental. This sample rate will be combined with a buffer size of 435 // 256 samples, which corresponds to an output delay of ~5.33ms. 436 sample_rate = 48000; 437 buffer_size = 256; 438 if (input_params.IsValid()) 439 channel_layout = input_params.channel_layout(); 440 } else { 441 AudioParameters params; 442 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( 443 output_device_id.empty() ? 444 GetDefaultOutputDeviceID() : output_device_id, 445 ¶ms); 446 if (SUCCEEDED(hr)) { 447 bits_per_sample = params.bits_per_sample(); 448 buffer_size = params.frames_per_buffer(); 449 channel_layout = params.channel_layout(); 450 sample_rate = params.sample_rate(); 451 } else { 452 use_input_params = true; 453 } 454 } 455 } 456 457 if (input_params.IsValid()) { 458 // If the user has enabled checking supported channel layouts or we don't 459 // have a valid channel layout yet, try to use the input layout. See bugs 460 // http://crbug.com/259165 and http://crbug.com/311906 for more details. 461 if (core_audio_supported && 462 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || 463 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { 464 // Check if it is possible to open up at the specified input channel 465 // layout but avoid checking if the specified layout is the same as the 466 // hardware (preferred) layout. We do this extra check to avoid the 467 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 468 if (input_params.channel_layout() != channel_layout) { 469 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the 470 // operations that have already been done such as opening up a client 471 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do 472 // that once. Then here, we can check the layout from the data we 473 // already hold. 474 if (CoreAudioUtil::IsChannelLayoutSupported( 475 output_device_id, eRender, eConsole, 476 input_params.channel_layout())) { 477 // Open up using the same channel layout as the source if it is 478 // supported by the hardware. 479 channel_layout = input_params.channel_layout(); 480 VLOG(1) << "Hardware channel layout is not used; using same layout" 481 << " as the source instead (" << channel_layout << ")"; 482 } 483 } 484 } 485 input_channels = input_params.input_channels(); 486 if (use_input_params) { 487 // If WASAPI isn't supported we'll fallback to WaveOut, which will take 488 // care of resampling and bits per sample changes. By setting these 489 // equal to the input values, AudioOutputResampler will skip resampling 490 // and bit per sample differences (since the input parameters will match 491 // the output parameters). 492 bits_per_sample = input_params.bits_per_sample(); 493 buffer_size = input_params.frames_per_buffer(); 494 channel_layout = input_params.channel_layout(); 495 sample_rate = input_params.sample_rate(); 496 } 497 } 498 499 int user_buffer_size = GetUserBufferSize(); 500 if (user_buffer_size) 501 buffer_size = user_buffer_size; 502 503 return AudioParameters( 504 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, 505 sample_rate, bits_per_sample, buffer_size); 506} 507 508AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( 509 const AudioParameters& params, 510 const std::string& device_id) { 511 std::string xp_device_id = device_id; 512 if (device_id != AudioManagerBase::kDefaultDeviceId && 513 enumeration_type_ == kMMDeviceEnumeration) { 514 xp_device_id = ConvertToWinXPInputDeviceId(device_id); 515 if (xp_device_id.empty()) { 516 DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID " 517 << device_id; 518 return NULL; 519 } 520 } 521 522 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, 523 xp_device_id); 524} 525 526/// static 527AudioManager* CreateAudioManager() { 528 return new AudioManagerWin(); 529} 530 531} // namespace media 532