audio_manager_win.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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 << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; 360 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; 361 return new PCMWaveOutAudioOutputStream( 362 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); 363 } 364 365 // TODO(rtoy): support more than stereo input. 366 if (params.input_channels() > 0) { 367 DVLOG(1) << "WASAPIUnifiedStream is created."; 368 DLOG_IF(ERROR, !device_id.empty()) 369 << "Opening by device id not supported by WASAPIUnifiedStream"; 370 return new WASAPIUnifiedStream(this, params, input_device_id); 371 } 372 373 return new WASAPIAudioOutputStream(this, device_id, params, eConsole); 374} 375 376// Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR 377// mode. 378AudioInputStream* AudioManagerWin::MakeLinearInputStream( 379 const AudioParameters& params, const std::string& device_id) { 380 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 381 return CreatePCMWaveInAudioInputStream(params, device_id); 382} 383 384// Factory for the implementations of AudioInputStream for 385// AUDIO_PCM_LOW_LATENCY mode. 386AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 387 const AudioParameters& params, const std::string& device_id) { 388 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 389 AudioInputStream* stream = NULL; 390 if (!CoreAudioUtil::IsSupported()) { 391 // Fall back to Windows Wave implementation on Windows XP or lower. 392 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; 393 stream = CreatePCMWaveInAudioInputStream(params, device_id); 394 } else { 395 stream = new WASAPIAudioInputStream(this, params, device_id); 396 } 397 398 return stream; 399} 400 401std::string AudioManagerWin::GetDefaultOutputDeviceID() { 402 if (!CoreAudioUtil::IsSupported()) 403 return std::string(); 404 return CoreAudioUtil::GetDefaultOutputDeviceID(); 405} 406 407AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 408 const std::string& output_device_id, 409 const AudioParameters& input_params) { 410 const bool core_audio_supported = CoreAudioUtil::IsSupported(); 411 DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty()) 412 << "CoreAudio is required to open non-default devices."; 413 414 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 415 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 416 int sample_rate = 48000; 417 int buffer_size = kFallbackBufferSize; 418 int bits_per_sample = 16; 419 int input_channels = 0; 420 bool use_input_params = !core_audio_supported; 421 if (core_audio_supported) { 422 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 423 // TODO(rtoy): tune these values for best possible WebAudio 424 // performance. WebRTC works well at 48kHz and a buffer size of 480 425 // samples will be used for this case. Note that exclusive mode is 426 // experimental. This sample rate will be combined with a buffer size of 427 // 256 samples, which corresponds to an output delay of ~5.33ms. 428 sample_rate = 48000; 429 buffer_size = 256; 430 if (input_params.IsValid()) 431 channel_layout = input_params.channel_layout(); 432 } else { 433 AudioParameters params; 434 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( 435 output_device_id.empty() ? 436 GetDefaultOutputDeviceID() : output_device_id, 437 ¶ms); 438 if (SUCCEEDED(hr)) { 439 bits_per_sample = params.bits_per_sample(); 440 buffer_size = params.frames_per_buffer(); 441 channel_layout = params.channel_layout(); 442 sample_rate = params.sample_rate(); 443 } else { 444 use_input_params = true; 445 } 446 } 447 } 448 449 if (input_params.IsValid()) { 450 if (core_audio_supported && 451 cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts)) { 452 // Check if it is possible to open up at the specified input channel 453 // layout but avoid checking if the specified layout is the same as the 454 // hardware (preferred) layout. We do this extra check to avoid the 455 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 456 if (input_params.channel_layout() != channel_layout) { 457 // TODO(henrika): Use |output_device_id| here. 458 // Internally, IsChannelLayoutSupported does many of the operations 459 // that have already been done such as opening up a client and fetching 460 // the WAVEFORMATPCMEX format. Ideally we should only do that once and 461 // do it for the requested device. Then here, we can check the layout 462 // from the data we already hold. 463 if (CoreAudioUtil::IsChannelLayoutSupported( 464 eRender, eConsole, input_params.channel_layout())) { 465 // Open up using the same channel layout as the source if it is 466 // supported by the hardware. 467 channel_layout = input_params.channel_layout(); 468 VLOG(1) << "Hardware channel layout is not used; using same layout" 469 << " as the source instead (" << channel_layout << ")"; 470 } 471 } 472 } 473 input_channels = input_params.input_channels(); 474 if (use_input_params) { 475 // If WASAPI isn't supported we'll fallback to WaveOut, which will take 476 // care of resampling and bits per sample changes. By setting these 477 // equal to the input values, AudioOutputResampler will skip resampling 478 // and bit per sample differences (since the input parameters will match 479 // the output parameters). 480 bits_per_sample = input_params.bits_per_sample(); 481 buffer_size = input_params.frames_per_buffer(); 482 channel_layout = input_params.channel_layout(); 483 sample_rate = input_params.sample_rate(); 484 } 485 } 486 487 int user_buffer_size = GetUserBufferSize(); 488 if (user_buffer_size) 489 buffer_size = user_buffer_size; 490 491 return AudioParameters( 492 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, 493 sample_rate, bits_per_sample, buffer_size); 494} 495 496AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( 497 const AudioParameters& params, 498 const std::string& device_id) { 499 std::string xp_device_id = device_id; 500 if (device_id != AudioManagerBase::kDefaultDeviceId && 501 enumeration_type_ == kMMDeviceEnumeration) { 502 xp_device_id = ConvertToWinXPInputDeviceId(device_id); 503 if (xp_device_id.empty()) { 504 DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID " 505 << device_id; 506 return NULL; 507 } 508 } 509 510 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, 511 xp_device_id); 512} 513 514/// static 515AudioManager* CreateAudioManager() { 516 return new AudioManagerWin(); 517} 518 519} // namespace media 520