| 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..b5b262fb414afd8158980ca12e84270969c68633 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,18 +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.
|
| - parameters =
|
| - AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
|
| - CHANNEL_LAYOUT_STEREO, 48000, 16, kFallbackBufferSize);
|
| + LOG(WARNING) << "Unable to get preferred audio params for " << device_id
|
| + << " 0x" << std::hex << hr;
|
| + return parameters;
|
| }
|
|
|
| int user_buffer_size = GetUserBufferSize();
|
| @@ -323,11 +297,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 +314,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 +331,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 +351,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,81 +360,67 @@ 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.
|
| 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();
|
| - } 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(henrika): Remove kEnableExclusiveAudio and related code. It doesn't
|
| + // look like it's used.
|
| + 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 (FAILED(hr)) {
|
| + // This can happen when CoreAudio isn't supported or available
|
| + // (e.g. certain installations of Windows Server 2008 R2).
|
| + // Instead of returning the input_params, we'll return invalid
|
| + // AudioParameters to make sure that an attempt to create this output
|
| + // stream, won't succeed. This behavior is also consistent with
|
| + // GetInputStreamParameters.
|
| + DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr;
|
| + return AudioParameters();
|
| }
|
| +
|
| + 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();
|
| }
|
|
|
| if (input_params.IsValid()) {
|
| // 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
|
| @@ -501,17 +444,6 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
|
| }
|
|
|
| effects |= input_params.effects();
|
| - if (use_input_params) {
|
| - // If WASAPI isn't supported we'll fallback to WaveOut, which will take
|
| - // care of resampling and bits per sample changes. By setting these
|
| - // equal to the input values, AudioOutputResampler will skip resampling
|
| - // and bit per sample differences (since the input parameters will match
|
| - // the output parameters).
|
| - bits_per_sample = input_params.bits_per_sample();
|
| - buffer_size = input_params.frames_per_buffer();
|
| - channel_layout = input_params.channel_layout();
|
| - sample_rate = input_params.sample_rate();
|
| - }
|
| }
|
|
|
| int user_buffer_size = GetUserBufferSize();
|
| @@ -524,25 +456,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,
|
|
|