Chromium Code Reviews| Index: media/audio/win/audio_manager_win.cc |
| diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc |
| index 4c46fc1155ab111c20f6eade1b559709736eca7f..6b0c5dc7aff9a8ee55669c5c702370cbf5ccd0f6 100644 |
| --- a/media/audio/win/audio_manager_win.cc |
| +++ b/media/audio/win/audio_manager_win.cc |
| @@ -31,7 +31,6 @@ |
| #include "media/audio/win/audio_low_latency_output_win.h" |
| #include "media/audio/win/core_audio_util_win.h" |
| #include "media/audio/win/device_enumeration_win.h" |
| -#include "media/audio/win/wavein_input_win.h" |
| #include "media/audio/win/waveout_output_win.h" |
| #include "media/base/audio_parameters.h" |
| #include "media/base/bind_to_current_loop.h" |
| @@ -44,8 +43,18 @@ |
| #define DRV_QUERYDEVICEINTERFACE 0x80c |
| #define DRVM_MAPPER_PREFERRED_GET 0x2015 |
| #define DRV_QUERYDEVICEINTERFACESIZE 0x80d |
| -DEFINE_GUID(AM_KSCATEGORY_AUDIO, 0x6994ad04, 0x93ef, 0x11d0, |
| - 0xa3, 0xcc, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96); |
| +DEFINE_GUID(AM_KSCATEGORY_AUDIO, |
| + 0x6994ad04, |
| + 0x93ef, |
| + 0x11d0, |
| + 0xa3, |
| + 0xcc, |
| + 0x00, |
| + 0xa0, |
| + 0xc9, |
| + 0x22, |
| + 0x31, |
| + 0x96); |
| namespace media { |
| @@ -56,13 +65,6 @@ static const int kMaxOutputStreams = 50; |
| // right drivers, but graceful error handling is needed. |
| static const int kWinMaxChannels = 8; |
| -// We use 3 buffers for recording audio so that if a recording callback takes |
| -// some time to return we won't lose audio. More buffers while recording are |
| -// ok because they don't introduce any delay in recording, unlike in playback |
| -// where you first need to fill in that number of buffers before starting to |
| -// play. |
| -static const int kNumInputBuffers = 3; |
| - |
| // Buffer size to use for input and output stream when a proper size can't be |
| // determined from the system |
| static const int kFallbackBufferSize = 2048; |
| @@ -94,7 +96,8 @@ static base::string16 GetDeviceAndDriverInfo(HDEVINFO device_info, |
| if (SetupDiEnumDriverInfo(device_info, device_data, SPDIT_COMPATDRIVER, 0, |
| &driver_data)) { |
| DWORDLONG version = driver_data.DriverVersion; |
| - device_and_driver_info = base::string16(driver_data.Description) + L" v" + |
| + device_and_driver_info = |
| + base::string16(driver_data.Description) + L" v" + |
| base::IntToString16(GetVersionPartAsInt((version >> 48))) + L"." + |
| base::IntToString16(GetVersionPartAsInt((version >> 32))) + L"." + |
| base::IntToString16(GetVersionPartAsInt((version >> 16))) + L"." + |
| @@ -134,13 +137,13 @@ AudioManagerWin::AudioManagerWin( |
| AudioLogFactory* audio_log_factory) |
| : AudioManagerBase(std::move(task_runner), |
| std::move(worker_task_runner), |
| - audio_log_factory), |
| - // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing |
| - // multiple initializations. This is however not thread safe. |
| - // So, here we call it explicitly before we kick off the audio thread |
| - // or do any other work. |
| - enumeration_type_(CoreAudioUtil::IsSupported() ? kMMDeviceEnumeration |
| - : kWaveEnumeration) { |
| + audio_log_factory) { |
| + // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing |
| + // multiple initializations. This is however not thread safe. |
| + // So, here we call it explicitly before we kick off the audio thread |
| + // or do any other work. |
| + CoreAudioUtil::IsSupported(); |
| + |
| SetMaxOutputStreamsAllowed(kMaxOutputStreams); |
| // WARNING: This is executed on the UI loop, do not add any code here which |
| @@ -149,8 +152,9 @@ AudioManagerWin::AudioManagerWin( |
| // Task must be posted last to avoid races from handing out "this" to the |
| // audio thread. |
| - GetTaskRunner()->PostTask(FROM_HERE, base::Bind( |
| - &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); |
| + GetTaskRunner()->PostTask( |
| + FROM_HERE, base::Bind(&AudioManagerWin::InitializeOnAudioThread, |
| + base::Unretained(this))); |
| } |
| AudioManagerWin::~AudioManagerWin() { |
| @@ -168,13 +172,10 @@ bool AudioManagerWin::HasAudioInputDevices() { |
| void AudioManagerWin::InitializeOnAudioThread() { |
| DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| - if (core_audio_supported()) { |
| - // AudioDeviceListenerWin must be initialized on a COM thread and should |
| - // only be used if WASAPI / Core Audio is supported. |
| - output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( |
| - base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, |
| - base::Unretained(this))))); |
| - } |
| + // AudioDeviceListenerWin must be initialized on a COM thread. |
| + output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( |
| + base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, |
| + base::Unretained(this))))); |
| } |
| base::string16 AudioManagerWin::GetAudioInputDeviceModel() { |
| @@ -193,10 +194,9 @@ base::string16 AudioManagerWin::GetAudioInputDeviceModel() { |
| return base::string16(); // No audio capture device. |
| base::string16 device_interface_name; |
| - base::string16::value_type* name_ptr = base::WriteInto(&device_interface_name, |
| - device_interface_name_size / bytes_in_char16); |
| - waveInMessage(reinterpret_cast<HWAVEIN>(device_id), |
| - DRV_QUERYDEVICEINTERFACE, |
| + base::string16::value_type* name_ptr = base::WriteInto( |
| + &device_interface_name, device_interface_name_size / bytes_in_char16); |
| + waveInMessage(reinterpret_cast<HWAVEIN>(device_id), DRV_QUERYDEVICEINTERFACE, |
| reinterpret_cast<DWORD_PTR>(name_ptr), |
| static_cast<DWORD_PTR>(device_interface_name_size)); |
| @@ -227,10 +227,9 @@ base::string16 AudioManagerWin::GetAudioInputDeviceModel() { |
| reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>( |
| interface_detail_buffer.get()); |
| interface_detail->cbSize = interface_detail_size; |
| - if (!SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, |
| - interface_detail, |
| - interface_detail_size, NULL, |
| - &device_data)) |
| + if (!SetupDiGetDeviceInterfaceDetail( |
| + device_info, &interface_data, interface_detail, |
| + interface_detail_size, NULL, &device_data)) |
| return base::string16(); |
| bool device_found = (device_interface_name == interface_detail->DevicePath); |
| @@ -243,46 +242,25 @@ base::string16 AudioManagerWin::GetAudioInputDeviceModel() { |
| } |
| void AudioManagerWin::ShowAudioInputSettings() { |
| - std::wstring program; |
| - std::string argument; |
| - if (!core_audio_supported()) { |
| - program = L"sndvol32.exe"; |
| - argument = "-R"; |
| - } else { |
| - program = L"control.exe"; |
| - argument = "mmsys.cpl,,1"; |
| - } |
| - |
| base::FilePath path; |
| PathService::Get(base::DIR_SYSTEM, &path); |
| - path = path.Append(program); |
| + path = path.Append(L"control.exe"); |
| base::CommandLine command_line(path); |
| - command_line.AppendArg(argument); |
| + command_line.AppendArg("mmsys.cpl,,1"); |
| base::LaunchProcess(command_line, base::LaunchOptions()); |
| } |
| -void AudioManagerWin::GetAudioDeviceNamesImpl( |
| - bool input, |
| - AudioDeviceNames* device_names) { |
| +void AudioManagerWin::GetAudioDeviceNamesImpl(bool input, |
| + AudioDeviceNames* device_names) { |
| DCHECK(device_names->empty()); |
| // Enumerate all active audio-endpoint capture devices. |
| - if (enumeration_type() == kWaveEnumeration) { |
| - // Utilize the Wave API for Windows XP. |
| - if (input) |
| - GetInputDeviceNamesWinXP(device_names); |
| - else |
| - GetOutputDeviceNamesWinXP(device_names); |
| - } else { |
| - // Utilize the MMDevice API (part of Core Audio) for Vista and higher. |
| - if (input) |
| - GetInputDeviceNamesWin(device_names); |
| - else |
| - GetOutputDeviceNamesWin(device_names); |
| - } |
| + if (input) |
| + GetInputDeviceNamesWin(device_names); |
| + else |
| + GetOutputDeviceNamesWin(device_names); |
| if (!device_names->empty()) { |
| - if (enumeration_type() == kMMDeviceEnumeration) |
| - device_names->push_front(AudioDeviceName::CreateCommunications()); |
| + device_names->push_front(AudioDeviceName::CreateCommunications()); |
| // Always add default device parameters as first element. |
| device_names->push_front(AudioDeviceName::CreateDefault()); |
| @@ -300,15 +278,14 @@ void AudioManagerWin::GetAudioOutputDeviceNames( |
| AudioParameters AudioManagerWin::GetInputStreamParameters( |
| const std::string& device_id) { |
| - HRESULT hr = E_FAIL; |
| AudioParameters parameters; |
| - if (core_audio_supported()) { |
| - hr = CoreAudioUtil::GetPreferredAudioParameters(device_id, false, |
| - ¶meters); |
| - } |
| + HRESULT hr = |
| + CoreAudioUtil::GetPreferredAudioParameters(device_id, false, ¶meters); |
| if (FAILED(hr) || !parameters.IsValid()) { |
| - // Windows Wave implementation is being used. |
| + // Fall back on default parameters. |
| + // TODO(tommi): Is this necessary? I'd guess that things would go wrong |
| + // elsewhere if we weren't able to get the preferred audio parameters. |
|
henrika (OOO until Aug 14)
2017/01/25 12:43:33
Possibly add a LOG(WARNING) just in case.
tommi (sloooow) - chröme
2017/01/25 21:44:33
Done.
|
| parameters = |
| AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, |
| CHANNEL_LAYOUT_STEREO, 48000, 16, kFallbackBufferSize); |
| @@ -323,11 +300,6 @@ AudioParameters AudioManagerWin::GetInputStreamParameters( |
| std::string AudioManagerWin::GetAssociatedOutputDeviceID( |
| const std::string& input_device_id) { |
| - if (!core_audio_supported()) { |
| - NOTIMPLEMENTED() |
| - << "GetAssociatedOutputDeviceID is not supported on this OS"; |
| - return std::string(); |
| - } |
| return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); |
| } |
| @@ -345,9 +317,7 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( |
| if (params.channels() > kWinMaxChannels) |
| return NULL; |
| - return new PCMWaveOutAudioOutputStream(this, |
| - params, |
| - NumberOfWaveOutBuffers(), |
| + return new PCMWaveOutAudioOutputStream(this, params, NumberOfWaveOutBuffers(), |
| WAVE_MAPPER); |
| } |
| @@ -364,16 +334,6 @@ AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( |
| if (params.channels() > kWinMaxChannels) |
| return NULL; |
| - if (!core_audio_supported()) { |
| - // Fall back to Windows Wave implementation on Windows XP or lower. |
| - DLOG_IF(ERROR, !device_id.empty() && |
| - device_id != AudioDeviceDescription::kDefaultDeviceId) |
| - << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; |
| - DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; |
| - return new PCMWaveOutAudioOutputStream( |
| - this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); |
| - } |
| - |
| // Pass an empty string to indicate that we want the default device |
| // since we consistently only check for an empty string in |
| // WASAPIAudioOutputStream. |
| @@ -394,7 +354,7 @@ AudioInputStream* AudioManagerWin::MakeLinearInputStream( |
| const std::string& device_id, |
| const LogCallback& log_callback) { |
| DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
| - return CreatePCMWaveInAudioInputStream(params, device_id); |
| + return MakeLowLatencyInputStream(params, device_id, log_callback); |
| } |
| // Factory for the implementations of AudioInputStream for |
| @@ -403,71 +363,54 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( |
| const AudioParameters& params, |
| const std::string& device_id, |
| const LogCallback& log_callback) { |
| - DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| + // Used for both AUDIO_PCM_LOW_LATENCY and AUDIO_PCM_LINEAR. |
|
henrika (OOO until Aug 14)
2017/01/25 12:43:33
Just FYI, I can only find one client (Pepper) that
tommi (sloooow) - chröme
2017/01/25 21:44:33
Yes, Dale knows a bit about that code. I think it
|
| DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; |
| - AudioInputStream* stream = NULL; |
| - UMA_HISTOGRAM_BOOLEAN("Media.WindowsCoreAudioInput", core_audio_supported()); |
| - if (!core_audio_supported()) { |
| - // Fall back to Windows Wave implementation on Windows XP or lower. |
| - DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; |
| - stream = CreatePCMWaveInAudioInputStream(params, device_id); |
| - } else { |
| - stream = new WASAPIAudioInputStream(this, params, device_id); |
| - } |
| - |
| - return stream; |
| + return new WASAPIAudioInputStream(this, params, device_id); |
| } |
| std::string AudioManagerWin::GetDefaultOutputDeviceID() { |
| - if (!core_audio_supported()) |
| - return std::string(); |
| return CoreAudioUtil::GetDefaultOutputDeviceID(); |
| } |
| AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( |
| const std::string& output_device_id, |
| const AudioParameters& input_params) { |
| - DLOG_IF(ERROR, !core_audio_supported() && !output_device_id.empty()) |
| - << "CoreAudio is required to open non-default devices."; |
| - |
| const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
| int sample_rate = 48000; |
| int buffer_size = kFallbackBufferSize; |
| int bits_per_sample = 16; |
| int effects = AudioParameters::NO_EFFECTS; |
| - bool use_input_params = !core_audio_supported(); |
| - if (core_audio_supported()) { |
| - if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { |
| - // TODO(rtoy): tune these values for best possible WebAudio |
| - // performance. WebRTC works well at 48kHz and a buffer size of 480 |
| - // samples will be used for this case. Note that exclusive mode is |
| - // experimental. This sample rate will be combined with a buffer size of |
| - // 256 samples, which corresponds to an output delay of ~5.33ms. |
| - sample_rate = 48000; |
| - buffer_size = 256; |
| - if (input_params.IsValid()) |
| - channel_layout = input_params.channel_layout(); |
| + bool use_input_params = false; |
| + if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { |
| + // TODO(rtoy): tune these values for best possible WebAudio |
| + // performance. WebRTC works well at 48kHz and a buffer size of 480 |
| + // samples will be used for this case. Note that exclusive mode is |
| + // experimental. This sample rate will be combined with a buffer size of |
| + // 256 samples, which corresponds to an output delay of ~5.33ms. |
| + sample_rate = 48000; |
| + buffer_size = 256; |
| + if (input_params.IsValid()) |
| + channel_layout = input_params.channel_layout(); |
| + } else { |
| + AudioParameters params; |
| + HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( |
| + output_device_id.empty() ? GetDefaultOutputDeviceID() |
| + : output_device_id, |
| + true, ¶ms); |
| + if (SUCCEEDED(hr)) { |
| + bits_per_sample = params.bits_per_sample(); |
| + buffer_size = params.frames_per_buffer(); |
| + channel_layout = params.channel_layout(); |
| + sample_rate = params.sample_rate(); |
| + effects = params.effects(); |
| } else { |
| - AudioParameters params; |
| - HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( |
| - output_device_id.empty() ? GetDefaultOutputDeviceID() |
| - : output_device_id, |
| - true, ¶ms); |
| - if (SUCCEEDED(hr)) { |
| - bits_per_sample = params.bits_per_sample(); |
| - buffer_size = params.frames_per_buffer(); |
| - channel_layout = params.channel_layout(); |
| - sample_rate = params.sample_rate(); |
| - effects = params.effects(); |
| - } else { |
| - // TODO(tommi): This should never happen really and I'm not sure that |
| - // setting use_input_params is the right thing to do since WASAPI i |
| - // definitely supported (see core_audio_supported() above) and |
| - // |use_input_params| is only for cases when it isn't supported. |
| - DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr; |
| - use_input_params = true; |
| - } |
| + // TODO(tommi): This should never happen really and I'm not sure that |
| + // setting use_input_params is the right thing to do since WASAPI i |
| + // definitely supported (see core_audio_supported() above) and |
| + // |use_input_params| is only for cases when it isn't supported. |
| + DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr; |
| + use_input_params = true; |
| } |
| } |
| @@ -475,9 +418,8 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( |
| // If the user has enabled checking supported channel layouts or we don't |
| // have a valid channel layout yet, try to use the input layout. See bugs |
| // http://crbug.com/259165 and http://crbug.com/311906 for more details. |
| - if (core_audio_supported() && |
| - (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || |
| - channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { |
| + if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || |
| + channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { |
| // Check if it is possible to open up at the specified input channel |
| // layout but avoid checking if the specified layout is the same as the |
| // hardware (preferred) layout. We do this extra check to avoid the |
| @@ -524,25 +466,7 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( |
| return params; |
| } |
| -AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( |
| - const AudioParameters& params, |
| - const std::string& device_id) { |
| - std::string xp_device_id = device_id; |
| - if (device_id != AudioDeviceDescription::kDefaultDeviceId && |
| - enumeration_type_ == kMMDeviceEnumeration) { |
| - xp_device_id = ConvertToWinXPInputDeviceId(device_id); |
| - if (xp_device_id.empty()) { |
| - DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID " |
| - << device_id; |
| - return NULL; |
| - } |
| - } |
| - |
| - return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, |
| - xp_device_id); |
| -} |
| - |
| -/// static |
| +// static |
| ScopedAudioManagerPtr CreateAudioManager( |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, |