Commit 473d43b3 authored by henrika's avatar henrika Committed by Commit Bot

Adds support for audio capture-effect enumeration on Windows

Initial work in this area landed in https://chromium-review.googlesource.com/c/chromium/src/+/2440055

This CL adds two new UMA histograms:

1) Media.Audio.Capture.Win.DefaultEffectType
2) Media.Audio.Capture.Win.RawEffectType

Each histogram can contain 17 different values and they indicate support
of different audio effect components such as AEC, NS, AGC etc. The idea
is to monitor how common each of these audio effects are.

There is one histogram for each audio processing mode: Default and Raw.

The CL changes no real-time functionality but it uses Windows UWP APIs
to enumerate the supported and active capture effects when opening
audio input streams on Windows.

Bug: 1133643
Change-Id: I3d866b96a5d240cf8fcbaa299f8f318615f6be0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2450195Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Reviewed-by: default avatarWeilun Shi <sweilun@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Commit-Queue: Henrik Andreasson <henrika@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821175}
parent 457ff60a
...@@ -61,10 +61,12 @@ ...@@ -61,10 +61,12 @@
#include <endpointvolume.h> #include <endpointvolume.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <windows.media.effects.h>
#include <wrl/client.h> #include <wrl/client.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
...@@ -157,6 +159,18 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -157,6 +159,18 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// Returns whether raw audio processing is supported or not for the selected // Returns whether raw audio processing is supported or not for the selected
// capture device. // capture device.
bool RawProcessingSupported(); bool RawProcessingSupported();
// The Windows.Media.Effects.AudioEffectsManager UWP API contains a method
// called CreateAudioCaptureEffectsManagerWithMode() which is needed to
// enumerate active audio effects on the capture stream. This UWP method
// needs a device ID which differs from what can be derived from the default
// Win32 API in CoreAudio. The GetUWPDeviceId() method builds up the required
// device ID that the audio effects manager needs. Note that it is also
// possible to get the ID directly from the Windows.Devices.Enumeration UWP
// API but that is rather complex and requires use of asynchronous methods.
std::string GetUWPDeviceId();
// For the selected |uwp_device_id|, generate two lists of enabled audio
// effects and store them in |default_effect_types_| and |raw_effect_types_|.
HRESULT GetAudioCaptureEffects(const std::string& uwp_device_id);
HRESULT SetCommunicationsCategoryAndRawCaptureMode(); HRESULT SetCommunicationsCategoryAndRawCaptureMode();
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
...@@ -306,6 +320,14 @@ class MEDIA_EXPORT WASAPIAudioInputStream ...@@ -306,6 +320,14 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// Also added to a UMS histogram. // Also added to a UMS histogram.
bool raw_processing_supported_ = false; bool raw_processing_supported_ = false;
// List of supported and active capture effects for the selected device in
// default (normal) audio processing mode.
std::vector<ABI::Windows::Media::Effects::AudioEffectType>
default_effect_types_;
// List of supported and active capture effects for the selected device in
// raw (minimal) audio processing mode. Will be empty in most cases.
std::vector<ABI::Windows::Media::Effects::AudioEffectType> raw_effect_types_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream); DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream);
......
...@@ -175,7 +175,7 @@ class AudioInputStreamWrapper { ...@@ -175,7 +175,7 @@ class AudioInputStreamWrapper {
explicit AudioInputStreamWrapper(AudioManager* audio_manager) explicit AudioInputStreamWrapper(AudioManager* audio_manager)
: audio_man_(audio_manager) { : audio_man_(audio_manager) {
EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
AudioDeviceDescription::kDefaultDeviceId, false, &default_params_))); device_id_, false, &default_params_)));
EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
frames_per_buffer_ = default_params_.frames_per_buffer(); frames_per_buffer_ = default_params_.frames_per_buffer();
} }
...@@ -187,6 +187,15 @@ class AudioInputStreamWrapper { ...@@ -187,6 +187,15 @@ class AudioInputStreamWrapper {
frames_per_buffer_ = default_params_.frames_per_buffer(); frames_per_buffer_ = default_params_.frames_per_buffer();
} }
AudioInputStreamWrapper(AudioManager* audio_manager,
const std::string& device_id)
: audio_man_(audio_manager), device_id_(device_id) {
EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
device_id_, false, &default_params_)));
EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
frames_per_buffer_ = default_params_.frames_per_buffer();
}
~AudioInputStreamWrapper() {} ~AudioInputStreamWrapper() {}
// Creates AudioInputStream object using default parameters. // Creates AudioInputStream object using default parameters.
...@@ -205,20 +214,21 @@ class AudioInputStreamWrapper { ...@@ -205,20 +214,21 @@ class AudioInputStreamWrapper {
} }
int sample_rate() const { return default_params_.sample_rate(); } int sample_rate() const { return default_params_.sample_rate(); }
int frames_per_buffer() const { return frames_per_buffer_; } int frames_per_buffer() const { return frames_per_buffer_; }
std::string device_id() const { return device_id_; }
private: private:
AudioInputStream* CreateInputStream() { AudioInputStream* CreateInputStream() {
AudioParameters params = default_params_; AudioParameters params = default_params_;
params.set_frames_per_buffer(frames_per_buffer_); params.set_frames_per_buffer(frames_per_buffer_);
AudioInputStream* ais = audio_man_->MakeAudioInputStream( AudioInputStream* ais = audio_man_->MakeAudioInputStream(
params, AudioDeviceDescription::kDefaultDeviceId, params, device_id_, base::BindRepeating(&LogCallbackDummy));
base::BindRepeating(&LogCallbackDummy));
EXPECT_TRUE(ais); EXPECT_TRUE(ais);
return ais; return ais;
} }
AudioManager* audio_man_; AudioManager* audio_man_;
AudioParameters default_params_; AudioParameters default_params_;
std::string device_id_ = AudioDeviceDescription::kDefaultDeviceId;
int frames_per_buffer_; int frames_per_buffer_;
}; };
...@@ -341,6 +351,26 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { ...@@ -341,6 +351,26 @@ TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) {
ais.Close(); ais.Close();
} }
// Test Open(), Close() calling sequences for all available devices.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndCloseForAllDevices) {
AudioDeviceInfoAccessorForTests device_info_accessor(audio_manager_.get());
ABORT_AUDIO_TEST_IF_NOT(device_info_accessor.HasAudioInputDevices() &&
CoreAudioUtil::IsSupported());
// Retrieve a list of all available input devices.
media::AudioDeviceDescriptions device_descriptions;
device_info_accessor.GetAudioInputDeviceDescriptions(&device_descriptions);
// Open and close an audio input stream for all available devices.
for (const auto& device : device_descriptions) {
AudioInputStreamWrapper aisw(audio_manager_.get(), device.unique_id);
{
ScopedAudioInputStream ais(aisw.Create());
EXPECT_TRUE(ais->Open());
}
}
}
// Test Open(), Start(), Close() calling sequence. // Test Open(), Start(), Close() calling sequence.
TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) {
ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get()));
...@@ -362,6 +392,7 @@ TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { ...@@ -362,6 +392,7 @@ TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) {
: feature_list.InitAndDisableFeature(media::kWasapiRawAudioCapture); : feature_list.InitAndDisableFeature(media::kWasapiRawAudioCapture);
ScopedAudioInputStream ais( ScopedAudioInputStream ais(
CreateDefaultAudioInputStream(audio_manager_.get())); CreateDefaultAudioInputStream(audio_manager_.get()));
EXPECT_TRUE(ais->SetAutomaticGainControl(true));
EXPECT_TRUE(ais->Open()); EXPECT_TRUE(ais->Open());
MockAudioInputCallback sink; MockAudioInputCallback sink;
ais->Start(&sink); ais->Start(&sink);
......
...@@ -4028,6 +4028,27 @@ Unknown properties are collapsed to zero. --> ...@@ -4028,6 +4028,27 @@ Unknown properties are collapsed to zero. -->
<int value="54" label="Sub mute"/> <int value="54" label="Sub mute"/>
</enum> </enum>
<enum name="AudioEffectType">
<int value="0" label="Other/None"/>
<int value="1" label="AcousticEchoCancellation"/>
<int value="2" label="NoiseSuppression"/>
<int value="3" label="AutomaticGainControl"/>
<int value="4" label="BeamForming"/>
<int value="5" label="ConstantToneRemoval"/>
<int value="6" label="Equalizer"/>
<int value="7" label="LoudnessEqualizer"/>
<int value="8" label="BassBoost"/>
<int value="9" label="VirtualSurround"/>
<int value="10" label="VirtualHeadphones"/>
<int value="11" label="SpeakerFill"/>
<int value="12" label="RoomCorrection"/>
<int value="13" label="BassManagement"/>
<int value="14" label="EnvironmentalEffects"/>
<int value="15" label="SpeakerProtection"/>
<int value="16" label="SpeakerCompensation"/>
<int value="17" label="DynamicRangeCompression"/>
</enum>
<enum name="AudioFocusAbandonSource"> <enum name="AudioFocusAbandonSource">
<int value="0" label="Unknown"/> <int value="0" label="Unknown"/>
<int value="1" label="API"/> <int value="1" label="API"/>
...@@ -347,6 +347,22 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -347,6 +347,22 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary> </summary>
</histogram> </histogram>
<histogram name="Media.Audio.Capture.Win.{AudioProcessingMode}EffectType"
enum="AudioEffectType" expires_after="2021-10-22">
<owner>henrika@chromium.org</owner>
<owner>media-dev@chromium.org</owner>
<summary>
Audio effect types detected on audio input streams using the
{AudioProcessingMode} audio processing mode. Emitted when the audio input
stream is closed but only on Windows platforms. Only uploaded for the case
when analog AGC is enabled, i.e., for WebRTC-based audio input streams.
</summary>
<token key="AudioProcessingMode">
<variant name="Default"/>
<variant name="Raw"/>
</token>
</histogram>
<histogram name="Media.Audio.CoreAudioDispatchOverrideInitResult" <histogram name="Media.Audio.CoreAudioDispatchOverrideInitResult"
enum="CoreAudioDispatchOverrideInitResult" expires_after="2021-04-01"> enum="CoreAudioDispatchOverrideInitResult" expires_after="2021-04-01">
<owner>guidou@chromium.org</owner> <owner>guidou@chromium.org</owner>
......
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