Commit 1d62ab1f authored by Henrik Grunell's avatar Henrik Grunell Committed by Commit Bot

Add Windows input audio voice capture DMO for voice processing.

Controlled by existing origin trial.

Bug: 845187
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I43e4e0d9f303086b50e9dd57ae547bfdcd79f204
Reviewed-on: https://chromium-review.googlesource.com/1065918
Commit-Queue: Henrik Grunell <grunell@chromium.org>
Reviewed-by: default avatarTommi <tommi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#560677}
parent 979ca1f9
...@@ -222,9 +222,13 @@ source_set("audio") { ...@@ -222,9 +222,13 @@ source_set("audio") {
] ]
libs += [ libs += [
"dmoguids.lib",
"dxguid.lib", "dxguid.lib",
"msdmo.lib",
"setupapi.lib", "setupapi.lib",
"strmiids.lib",
"winmm.lib", "winmm.lib",
"wmcodecdspuuid.lib",
] ]
} }
......
...@@ -33,6 +33,8 @@ class AudioOutputDispatcher; ...@@ -33,6 +33,8 @@ class AudioOutputDispatcher;
// AudioManagerBase provides AudioManager functions common for all platforms. // AudioManagerBase provides AudioManager functions common for all platforms.
class MEDIA_EXPORT AudioManagerBase : public AudioManager { class MEDIA_EXPORT AudioManagerBase : public AudioManager {
public: public:
enum class VoiceProcessingMode { kDisabled = 0, kEnabled = 1 };
~AudioManagerBase() override; ~AudioManagerBase() override;
AudioOutputStream* MakeAudioOutputStream( AudioOutputStream* MakeAudioOutputStream(
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "base/sys_info.h" #include "base/sys_info.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "media/audio/mac/audio_manager_mac.h"
#include "media/audio/mac/scoped_audio_unit.h" #include "media/audio/mac/scoped_audio_unit.h"
#include "media/base/audio_bus.h" #include "media/base/audio_bus.h"
#include "media/base/audio_timestamp_helper.h" #include "media/base/audio_timestamp_helper.h"
...@@ -165,7 +164,7 @@ AUAudioInputStream::AUAudioInputStream( ...@@ -165,7 +164,7 @@ AUAudioInputStream::AUAudioInputStream(
const AudioParameters& input_params, const AudioParameters& input_params,
AudioDeviceID audio_device_id, AudioDeviceID audio_device_id,
const AudioManager::LogCallback& log_callback, const AudioManager::LogCallback& log_callback,
VoiceProcessingMode voice_processing_mode) AudioManagerBase::VoiceProcessingMode voice_processing_mode)
: manager_(manager), : manager_(manager),
input_params_(input_params), input_params_(input_params),
number_of_frames_provided_(0), number_of_frames_provided_(0),
...@@ -184,7 +183,7 @@ AUAudioInputStream::AUAudioInputStream( ...@@ -184,7 +183,7 @@ AUAudioInputStream::AUAudioInputStream(
audio_unit_render_has_worked_(false), audio_unit_render_has_worked_(false),
noise_reduction_suppressed_(false), noise_reduction_suppressed_(false),
use_voice_processing_(voice_processing_mode == use_voice_processing_(voice_processing_mode ==
VoiceProcessingMode::ENABLED), AudioManagerBase::VoiceProcessingMode::kEnabled),
last_sample_time_(0.0), last_sample_time_(0.0),
last_number_of_frames_(0), last_number_of_frames_(0),
total_lost_frames_(0), total_lost_frames_(0),
......
...@@ -50,26 +50,23 @@ ...@@ -50,26 +50,23 @@
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "media/audio/agc_audio_stream.h" #include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_io.h" #include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h" #include "media/audio/mac/audio_manager_mac.h"
#include "media/base/audio_block_fifo.h" #include "media/base/audio_block_fifo.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
namespace media { namespace media {
class AudioManagerMac;
class MEDIA_EXPORT AUAudioInputStream class MEDIA_EXPORT AUAudioInputStream
: public AgcAudioStream<AudioInputStream> { : public AgcAudioStream<AudioInputStream> {
public: public:
enum class VoiceProcessingMode { DISABLED = 0, ENABLED = 1 };
// The ctor takes all the usual parameters, plus |manager| which is the // The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object. // the audio manager who is creating this object.
AUAudioInputStream(AudioManagerMac* manager, AUAudioInputStream(
const AudioParameters& input_params, AudioManagerMac* manager,
AudioDeviceID audio_device_id, const AudioParameters& input_params,
const AudioManager::LogCallback& log_callback, AudioDeviceID audio_device_id,
VoiceProcessingMode voice_processing_mode); const AudioManager::LogCallback& log_callback,
AudioManagerBase::VoiceProcessingMode voice_processing_mode);
// The dtor is typically called by the AudioManager only and it is usually // The dtor is typically called by the AudioManager only and it is usually
// triggered by calling AudioInputStream::Close(). // triggered by calling AudioInputStream::Close().
~AUAudioInputStream() override; ~AUAudioInputStream() override;
......
...@@ -795,11 +795,10 @@ AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( ...@@ -795,11 +795,10 @@ AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
return nullptr; return nullptr;
} }
using VoiceProcessingMode = AUAudioInputStream::VoiceProcessingMode;
VoiceProcessingMode voice_processing_mode = VoiceProcessingMode voice_processing_mode =
(params.effects() & AudioParameters::ECHO_CANCELLER) (params.effects() & AudioParameters::ECHO_CANCELLER)
? VoiceProcessingMode::ENABLED ? VoiceProcessingMode::kEnabled
: VoiceProcessingMode::DISABLED; : VoiceProcessingMode::kDisabled;
auto* stream = new AUAudioInputStream(this, params, audio_device_id, auto* stream = new AUAudioInputStream(this, params, audio_device_id,
log_callback, voice_processing_mode); log_callback, voice_processing_mode);
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <Audioclient.h> #include <Audioclient.h>
#include <MMDeviceAPI.h> #include <MMDeviceAPI.h>
#include <dmo.h>
#include <endpointvolume.h> #include <endpointvolume.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
...@@ -75,7 +76,7 @@ ...@@ -75,7 +76,7 @@
#include "base/win/scoped_com_initializer.h" #include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
#include "media/audio/agc_audio_stream.h" #include "media/audio/agc_audio_stream.h"
#include "media/audio/audio_manager.h" #include "media/audio/win/audio_manager_win.h"
#include "media/base/audio_converter.h" #include "media/base/audio_converter.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
...@@ -84,7 +85,6 @@ namespace media { ...@@ -84,7 +85,6 @@ namespace media {
class AudioBlockFifo; class AudioBlockFifo;
class AudioBus; class AudioBus;
class AudioManagerWin;
// AudioInputStream implementation using Windows Core Audio APIs. // AudioInputStream implementation using Windows Core Audio APIs.
class MEDIA_EXPORT WASAPIAudioInputStream class MEDIA_EXPORT WASAPIAudioInputStream
...@@ -94,10 +94,12 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -94,10 +94,12 @@ class MEDIA_EXPORT WASAPIAudioInputStream
public: public:
// The ctor takes all the usual parameters, plus |manager| which is the // The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object. // the audio manager who is creating this object.
WASAPIAudioInputStream(AudioManagerWin* manager, WASAPIAudioInputStream(
const AudioParameters& params, AudioManagerWin* manager,
const std::string& device_id, const AudioParameters& params,
const AudioManager::LogCallback& log_callback); const std::string& device_id,
const AudioManager::LogCallback& log_callback,
AudioManagerBase::VoiceProcessingMode voice_processing_mode);
// The dtor is typically called by the AudioManager only and it is usually // The dtor is typically called by the AudioManager only and it is usually
// triggered by calling AudioInputStream::Close(). // triggered by calling AudioInputStream::Close().
...@@ -117,16 +119,27 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -117,16 +119,27 @@ class MEDIA_EXPORT WASAPIAudioInputStream
bool started() const { return started_; } bool started() const { return started_; }
private: private:
// DelegateSimpleThread::Delegate implementation. // DelegateSimpleThread::Delegate implementation. Calls either
// RunWithAudioCaptureClient() or RunWithDmo().
void Run() override; void Run() override;
// Pulls capture data from the endpoint device and pushes it to the sink. // Waits for an event that the audio capture client has data ready.
bool RunWithAudioCaptureClient();
// Polls the DMO (voice processing component) for data every 5 ms.
bool RunWithDmo();
// Pulls capture data from the audio capture client and pushes it to the sink.
void PullCaptureDataAndPushToSink(); void PullCaptureDataAndPushToSink();
// Pulls capture data from the DMO and pushes it to the sink.
void PullDmoCaptureDataAndPushToSink();
// Issues the OnError() callback to the |sink_|. // Issues the OnError() callback to the |sink_|.
void HandleError(HRESULT err); void HandleError(HRESULT err);
// The Open() method is divided into these sub methods. // The Open() method is divided into these sub methods when not using the
// voice processing DMO.
HRESULT SetCaptureDevice(); HRESULT SetCaptureDevice();
HRESULT GetAudioEngineStreamFormat(); HRESULT GetAudioEngineStreamFormat();
// Returns whether the desired format is supported or not and writes the // Returns whether the desired format is supported or not and writes the
...@@ -134,14 +147,22 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -134,14 +147,22 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// function returns false with |*hr| == S_FALSE, the OS supports a closest // function returns false with |*hr| == S_FALSE, the OS supports a closest
// match but we don't support conversion to it. // match but we don't support conversion to it.
bool DesiredFormatIsSupported(HRESULT* hr); bool DesiredFormatIsSupported(HRESULT* hr);
void SetupConverterAndStoreFormatInfo();
HRESULT InitializeAudioEngine(); HRESULT InitializeAudioEngine();
void ReportOpenResult(HRESULT hr) const; void ReportOpenResult(HRESULT hr) const;
// Reports stats for format related audio client initilization // Reports stats for format related audio client initilization
// (IAudioClient::Initialize) errors, that is if |hr| is an error related to // (IAudioClient::Initialize) errors, that is if |hr| is an error related to
// the format. // the format.
void MaybeReportFormatRelatedInitError(HRESULT hr) const; void MaybeReportFormatRelatedInitError(HRESULT hr) const;
// The Open() method is divided into these sub methods when using the voice
// processing DMO. In addition, SetupConverterAndStoreFormatInfo() above is
// also called.
bool InitializeDmo();
bool SetDmoProperties();
bool SetDmoFormat();
bool CreateDummyRenderClientsForDmo();
// AudioConverter::InputCallback implementation. // AudioConverter::InputCallback implementation.
double ProvideInput(AudioBus* audio_bus, uint32_t frames_delayed) override; double ProvideInput(AudioBus* audio_bus, uint32_t frames_delayed) override;
...@@ -189,30 +210,35 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -189,30 +210,35 @@ class MEDIA_EXPORT WASAPIAudioInputStream
std::unique_ptr<base::DelegateSimpleThread> capture_thread_; std::unique_ptr<base::DelegateSimpleThread> capture_thread_;
// Contains the desired output audio format which is set up at construction, // Contains the desired output audio format which is set up at construction,
// that is the audio format this class should output data to the sink in. // that is the audio format this class should output data to the sink in, that
// is the format after the converter.
WAVEFORMATEX output_format_; WAVEFORMATEX output_format_;
// Contains the audio format we get data from the audio engine in. Set to // Contains the audio format we get data from the audio engine in. Set to
// |output_format_| at construction and might be changed to a close match // |output_format_| at construction and might be changed to a close match
// if the audio engine doesn't support the originally set format. // if the audio engine doesn't support the originally set format, or to the
// format the voice capture DMO outputs if it's used. Note that this is also
// the format after the fifo, i.e. the input format to the converter if any.
WAVEFORMATEX input_format_; WAVEFORMATEX input_format_;
bool opened_ = false; bool opened_ = false;
bool started_ = false; bool started_ = false;
StreamOpenResult open_result_ = OPEN_RESULT_OK; StreamOpenResult open_result_ = OPEN_RESULT_OK;
// Size in bytes of each audio frame (4 bytes for 16-bit stereo PCM) // Size in bytes of each audio frame before the converter (4 bytes for 16-bit
size_t frame_size_ = 0; // stereo PCM). Note that this is the same before and after the fifo.
size_t frame_size_bytes_ = 0;
// Size in audio frames of each audio packet where an audio packet // Size in audio frames of each audio packet (buffer) after the fifo but
// is defined as the block of data which the user received in each // before the converter.
// OnData() callback.
size_t packet_size_frames_ = 0; size_t packet_size_frames_ = 0;
// Size in bytes of each audio packet. // Size in bytes of each audio packet (buffer) after the fifo but before the
// converter.
size_t packet_size_bytes_ = 0; size_t packet_size_bytes_ = 0;
// Length of the audio endpoint buffer. // Length of the audio endpoint buffer, or the buffer size used for the DMO.
// That is, the buffer size before the fifo.
uint32_t endpoint_buffer_size_frames_ = 0; uint32_t endpoint_buffer_size_frames_ = 0;
// Contains the unique name of the selected endpoint device. // Contains the unique name of the selected endpoint device.
...@@ -295,6 +321,22 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -295,6 +321,22 @@ class MEDIA_EXPORT WASAPIAudioInputStream
UINT64 total_lost_frames_ = 0; UINT64 total_lost_frames_ = 0;
UINT64 largest_glitch_frames_ = 0; UINT64 largest_glitch_frames_ = 0;
// Indicates if the voice processing DMO should be used.
bool use_voice_processing_ = false;
// The voice processing DMO and its data buffer.
Microsoft::WRL::ComPtr<IMediaObject> voice_capture_dmo_;
Microsoft::WRL::ComPtr<IMediaBuffer> media_buffer_;
// Dummy rendering when using the DMO. The DMO requires audio rendering to the
// device it's set up to use, otherwise it won't produce any capture audio
// data. Normally, when the DMO is used there's a render stream, but it's not
// guaranteed so we need to support the lack of it. We do this by always
// opening a render client and rendering silence to it when the DMO is
// running.
Microsoft::WRL::ComPtr<IAudioClient> audio_client_for_render_;
Microsoft::WRL::ComPtr<IAudioRenderClient> audio_render_client_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream); DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream);
......
...@@ -170,11 +170,16 @@ static bool HasCoreAudioAndInputDevices(AudioManager* audio_man) { ...@@ -170,11 +170,16 @@ static bool HasCoreAudioAndInputDevices(AudioManager* audio_man) {
// also allows the user to modify the default settings. // also allows the user to modify the default settings.
class AudioInputStreamWrapper { class AudioInputStreamWrapper {
public: public:
explicit AudioInputStreamWrapper(AudioManager* audio_manager) explicit AudioInputStreamWrapper(AudioManager* audio_manager,
bool use_voice_processing)
: audio_man_(audio_manager) { : audio_man_(audio_manager) {
EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
AudioDeviceDescription::kDefaultDeviceId, false, &default_params_))); AudioDeviceDescription::kDefaultDeviceId, false, &default_params_)));
EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
if (use_voice_processing) {
default_params_.set_effects(default_params_.effects() |
AudioParameters::ECHO_CANCELLER);
}
frames_per_buffer_ = default_params_.frames_per_buffer(); frames_per_buffer_ = default_params_.frames_per_buffer();
} }
...@@ -222,8 +227,9 @@ class AudioInputStreamWrapper { ...@@ -222,8 +227,9 @@ class AudioInputStreamWrapper {
// Convenience method which creates a default AudioInputStream object. // Convenience method which creates a default AudioInputStream object.
static AudioInputStream* CreateDefaultAudioInputStream( static AudioInputStream* CreateDefaultAudioInputStream(
AudioManager* audio_manager) { AudioManager* audio_manager,
AudioInputStreamWrapper aisw(audio_manager); bool use_voice_processing) {
AudioInputStreamWrapper aisw(audio_manager, use_voice_processing);
AudioInputStream* ais = aisw.Create(); AudioInputStream* ais = aisw.Create();
return ais; return ais;
} }
...@@ -258,7 +264,9 @@ class ScopedAudioInputStream { ...@@ -258,7 +264,9 @@ class ScopedAudioInputStream {
DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream); DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream);
}; };
class WinAudioInputTest : public ::testing::Test { // The test class. The boolean parameter specifies if voice processing should be
// used.
class WinAudioInputTest : public ::testing::TestWithParam<bool> {
public: public:
WinAudioInputTest() { WinAudioInputTest() {
audio_manager_ = audio_manager_ =
...@@ -293,27 +301,27 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) { ...@@ -293,27 +301,27 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) {
} }
// Test Create(), Close() calling sequence. // Test Create(), Close() calling sequence.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
ScopedAudioInputStream ais( ScopedAudioInputStream ais(
CreateDefaultAudioInputStream(audio_manager_.get())); CreateDefaultAudioInputStream(audio_manager_.get(), GetParam()));
ais.Close(); ais.Close();
} }
// Test Open(), Close() calling sequence. // Test Open(), Close() calling sequence.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
ScopedAudioInputStream ais( ScopedAudioInputStream ais(
CreateDefaultAudioInputStream(audio_manager_.get())); CreateDefaultAudioInputStream(audio_manager_.get(), GetParam()));
EXPECT_TRUE(ais->Open()); EXPECT_TRUE(ais->Open());
ais.Close(); ais.Close();
} }
// Test Open(), Start(), Close() calling sequence. // Test Open(), Start(), Close() calling sequence.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
ScopedAudioInputStream ais( ScopedAudioInputStream ais(
CreateDefaultAudioInputStream(audio_manager_.get())); CreateDefaultAudioInputStream(audio_manager_.get(), GetParam()));
EXPECT_TRUE(ais->Open()); EXPECT_TRUE(ais->Open());
MockAudioInputCallback sink; MockAudioInputCallback sink;
ais->Start(&sink); ais->Start(&sink);
...@@ -321,10 +329,10 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { ...@@ -321,10 +329,10 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
} }
// Test Open(), Start(), Stop(), Close() calling sequence. // Test Open(), Start(), Stop(), Close() calling sequence.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
ScopedAudioInputStream ais( ScopedAudioInputStream ais(
CreateDefaultAudioInputStream(audio_manager_.get())); CreateDefaultAudioInputStream(audio_manager_.get(), GetParam()));
EXPECT_TRUE(ais->Open()); EXPECT_TRUE(ais->Open());
MockAudioInputCallback sink; MockAudioInputCallback sink;
ais->Start(&sink); ais->Start(&sink);
...@@ -333,10 +341,10 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { ...@@ -333,10 +341,10 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
} }
// Test some additional calling sequences. // Test some additional calling sequences.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
ScopedAudioInputStream ais( ScopedAudioInputStream ais(
CreateDefaultAudioInputStream(audio_manager_.get())); CreateDefaultAudioInputStream(audio_manager_.get(), GetParam()));
// Open(), Open() should fail the second time. // Open(), Open() should fail the second time.
EXPECT_TRUE(ais->Open()); EXPECT_TRUE(ais->Open());
...@@ -358,7 +366,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { ...@@ -358,7 +366,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) {
ais.Close(); ais.Close();
} }
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
int count = 0; int count = 0;
...@@ -367,7 +375,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { ...@@ -367,7 +375,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
// Create default WASAPI input stream which records in stereo using // Create default WASAPI input stream which records in stereo using
// the shared mixing rate. The default buffer size is 10ms. // the shared mixing rate. The default buffer size is 10ms.
AudioInputStreamWrapper aisw(audio_manager_.get()); AudioInputStreamWrapper aisw(audio_manager_.get(), GetParam());
ScopedAudioInputStream ais(aisw.Create()); ScopedAudioInputStream ais(aisw.Create());
EXPECT_TRUE(ais->Open()); EXPECT_TRUE(ais->Open());
...@@ -441,7 +449,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { ...@@ -441,7 +449,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) {
} }
// Test that we can capture a stream in loopback. // Test that we can capture a stream in loopback.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { TEST_P(WinAudioInputTest, WASAPIAudioInputStreamLoopback) {
AudioDeviceInfoAccessorForTests device_info_accessor(audio_manager_.get()); AudioDeviceInfoAccessorForTests device_info_accessor(audio_manager_.get());
ABORT_AUDIO_TEST_IF_NOT(device_info_accessor.HasAudioOutputDevices() && ABORT_AUDIO_TEST_IF_NOT(device_info_accessor.HasAudioOutputDevices() &&
CoreAudioUtil::IsSupported()); CoreAudioUtil::IsSupported());
...@@ -475,7 +483,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { ...@@ -475,7 +483,7 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamLoopback) {
// To include disabled tests in test execution, just invoke the test program // To include disabled tests in test execution, just invoke the test program
// with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS
// environment variable to a value greater than 0. // environment variable to a value greater than 0.
TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { TEST_P(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
// Name of the output PCM file containing captured data. The output file // Name of the output PCM file containing captured data. The output file
...@@ -483,7 +491,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { ...@@ -483,7 +491,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
// Example of full name: \src\build\Debug\out_stereo_10sec.pcm. // Example of full name: \src\build\Debug\out_stereo_10sec.pcm.
const char* file_name = "out_10sec.pcm"; const char* file_name = "out_10sec.pcm";
AudioInputStreamWrapper aisw(audio_manager_.get()); AudioInputStreamWrapper aisw(audio_manager_.get(), GetParam());
ScopedAudioInputStream ais(aisw.Create()); ScopedAudioInputStream ais(aisw.Create());
ASSERT_TRUE(ais->Open()); ASSERT_TRUE(ais->Open());
...@@ -497,7 +505,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { ...@@ -497,7 +505,7 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) {
ais.Close(); ais.Close();
} }
TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { TEST_P(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
// This is basically the same test as WASAPIAudioInputStreamRecordToFile // This is basically the same test as WASAPIAudioInputStreamRecordToFile
...@@ -532,6 +540,8 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { ...@@ -532,6 +540,8 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) {
// Otherwise (e.g. 44.1kHz, 22.05kHz etc) we convert to 48kHz. // Otherwise (e.g. 44.1kHz, 22.05kHz etc) we convert to 48kHz.
const int hw_sample_rate = params.sample_rate(); const int hw_sample_rate = params.sample_rate();
params.Reset(params.format(), test.layout, test.rate, test.frames); params.Reset(params.format(), test.layout, test.rate, test.frames);
if (GetParam())
params.set_effects(params.effects() | AudioParameters::ECHO_CANCELLER);
std::string file_name(base::StringPrintf( std::string file_name(base::StringPrintf(
"resampled_10sec_%i_to_%i_%s.pcm", hw_sample_rate, params.sample_rate(), "resampled_10sec_%i_to_%i_%s.pcm", hw_sample_rate, params.sample_rate(),
...@@ -555,4 +565,8 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { ...@@ -555,4 +565,8 @@ TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) {
} }
} }
INSTANTIATE_TEST_CASE_P(/* Intentially left empty */,
WinAudioInputTest,
::testing::Bool());
} // namespace media } // namespace media
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
#include "media/audio/audio_features.h"
#include "media/audio/audio_io.h" #include "media/audio/audio_io.h"
#include "media/audio/win/audio_device_listener_win.h" #include "media/audio/win/audio_device_listener_win.h"
#include "media/audio/win/audio_low_latency_input_win.h" #include "media/audio/win/audio_low_latency_input_win.h"
...@@ -178,6 +179,9 @@ AudioParameters AudioManagerWin::GetInputStreamParameters( ...@@ -178,6 +179,9 @@ AudioParameters AudioManagerWin::GetInputStreamParameters(
if (user_buffer_size) if (user_buffer_size)
parameters.set_frames_per_buffer(user_buffer_size); parameters.set_frames_per_buffer(user_buffer_size);
parameters.set_effects(parameters.effects() |
AudioParameters::EXPERIMENTAL_ECHO_CANCELLER);
return parameters; return parameters;
} }
...@@ -248,7 +252,14 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( ...@@ -248,7 +252,14 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
const LogCallback& log_callback) { const LogCallback& log_callback) {
// Used for both AUDIO_PCM_LOW_LATENCY and AUDIO_PCM_LINEAR. // Used for both AUDIO_PCM_LOW_LATENCY and AUDIO_PCM_LINEAR.
DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; DVLOG(1) << "MakeLowLatencyInputStream: " << device_id;
return new WASAPIAudioInputStream(this, params, device_id, log_callback);
VoiceProcessingMode voice_processing_mode =
params.effects() & AudioParameters::ECHO_CANCELLER
? VoiceProcessingMode::kEnabled
: VoiceProcessingMode::kDisabled;
return new WASAPIAudioInputStream(this, params, device_id, log_callback,
voice_processing_mode);
} }
std::string AudioManagerWin::GetDefaultInputDeviceID() { std::string AudioManagerWin::GetDefaultInputDeviceID() {
......
...@@ -976,4 +976,71 @@ bool CoreAudioUtil::GetDxDiagDetails(std::string* driver_name, ...@@ -976,4 +976,71 @@ bool CoreAudioUtil::GetDxDiagDetails(std::string* driver_name,
return true; return true;
} }
HRESULT CoreAudioUtil::GetDeviceCollectionIndex(const std::string& device_id,
EDataFlow data_flow,
WORD* index) {
ComPtr<IMMDeviceEnumerator> enumerator = CreateDeviceEnumerator();
if (!enumerator.Get()) {
DLOG(ERROR) << "Failed to create device enumerator.";
return E_FAIL;
}
ComPtr<IMMDeviceCollection> device_collection;
HRESULT hr = enumerator->EnumAudioEndpoints(data_flow, DEVICE_STATE_ACTIVE,
&device_collection);
if (FAILED(hr)) {
DLOG(ERROR) << "Failed to get device collection.";
return hr;
}
UINT number_of_devices = 0;
hr = device_collection->GetCount(&number_of_devices);
if (FAILED(hr)) {
DLOG(ERROR) << "Failed to get device collection count.";
return hr;
}
ComPtr<IMMDevice> device;
for (WORD i = 0; i < number_of_devices; ++i) {
hr = device_collection->Item(i, &device);
if (FAILED(hr)) {
DLOG(WARNING) << "Failed to get device.";
continue;
}
ScopedCoMem<WCHAR> current_device_id;
hr = device->GetId(&current_device_id);
if (FAILED(hr)) {
DLOG(WARNING) << "Failed to get device id.";
continue;
}
if (base::UTF16ToUTF8(current_device_id.get()) == device_id) {
*index = i;
return S_OK;
}
}
DVLOG(1) << "No matching device found.";
return S_FALSE;
}
HRESULT CoreAudioUtil::SetBoolProperty(IPropertyStore* property_store,
REFPROPERTYKEY key,
VARIANT_BOOL value) {
base::win::ScopedPropVariant pv;
PROPVARIANT* pv_ptr = pv.Receive();
pv_ptr->vt = VT_BOOL;
pv_ptr->boolVal = value;
return property_store->SetValue(key, pv.get());
}
HRESULT CoreAudioUtil::SetVtI4Property(IPropertyStore* property_store,
REFPROPERTYKEY key,
LONG value) {
base::win::ScopedPropVariant pv;
PROPVARIANT* pv_ptr = pv.Receive();
pv_ptr->vt = VT_I4;
pv_ptr->lVal = value;
return property_store->SetValue(key, pv.get());
}
} // namespace media } // namespace media
...@@ -212,6 +212,23 @@ class MEDIA_EXPORT CoreAudioUtil { ...@@ -212,6 +212,23 @@ class MEDIA_EXPORT CoreAudioUtil {
static bool GetDxDiagDetails(std::string* driver_name, static bool GetDxDiagDetails(std::string* driver_name,
std::string* driver_version); std::string* driver_version);
// Gets the device collection index for the device specified by |device_id|.
// If the device is found in the device collection, the index is written to
// |*index| and S_OK is returned. If the device is not found, S_FALSE is
// returned and |*index| is left unchanged. In case of an error, the error
// result is returned and |*index| is left unchanged.
static HRESULT GetDeviceCollectionIndex(const std::string& device_id,
EDataFlow data_flow,
WORD* index);
// Sets the property identified by |key| to |value| in |*property_store|.
static HRESULT SetBoolProperty(IPropertyStore* property_store,
REFPROPERTYKEY key,
VARIANT_BOOL value);
static HRESULT SetVtI4Property(IPropertyStore* property_store,
REFPROPERTYKEY key,
LONG value);
private: private:
CoreAudioUtil() {} CoreAudioUtil() {}
~CoreAudioUtil() {} ~CoreAudioUtil() {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment