diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 3efa065639..b43a98b167 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -34,14 +34,6 @@ rtc_static_library("audio_processing") { "aec/aec_resampler.h", "aec/echo_cancellation.cc", "aec/echo_cancellation.h", - "agc/agc.cc", - "agc/agc.h", - "agc/agc_manager_direct.cc", - "agc/agc_manager_direct.h", - "agc/loudness_histogram.cc", - "agc/loudness_histogram.h", - "agc/utility.cc", - "agc/utility.h", "audio_buffer.cc", "audio_buffer.h", "audio_processing_impl.cc", @@ -108,12 +100,12 @@ rtc_static_library("audio_processing") { defines = [] deps = [ ":aec_core", - ":agc_gain_map_internal", ":apm_logging", ":audio_frame_view", ":audio_generator_interface", ":audio_processing_c", ":audio_processing_statistics", + ":gain_control_interface", "../..:typedefs", "../..:webrtc_common", "../../api:array_view", @@ -131,6 +123,8 @@ rtc_static_library("audio_processing") { "../../system_wrappers:cpu_features_api", "../../system_wrappers:field_trial_api", "../../system_wrappers:metrics_api", + "agc", + "agc:agc_legacy_c", "agc2:adaptive_digital", "agc2:fixed_digital", "agc2:gain_applier", @@ -169,6 +163,12 @@ rtc_static_library("audio_processing") { ] } +rtc_source_set("gain_control_interface") { + sources = [ + "include/gain_control.h", + ] +} + rtc_source_set("audio_processing_statistics") { visibility = [ "*" ] sources = [ @@ -232,13 +232,7 @@ rtc_source_set("file_audio_generator") { rtc_source_set("audio_processing_c") { visibility = [ ":*" ] # Only targets in this file can depend on this. - sources = [ - "agc/legacy/analog_agc.c", - "agc/legacy/analog_agc.h", - "agc/legacy/digital_agc.c", - "agc/legacy/digital_agc.h", - "agc/legacy/gain_control.h", - ] + sources = [] if (rtc_prefer_fixed_point) { sources += [ @@ -273,6 +267,7 @@ rtc_source_set("audio_processing_c") { "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../system_wrappers:cpu_features_api", + "agc:agc_legacy_c", ] if (rtc_build_with_neon) { @@ -397,12 +392,6 @@ rtc_source_set("aec_core") { } } -rtc_source_set("agc_gain_map_internal") { - sources = [ - "agc/gain_map_internal.h", - ] -} - if (rtc_include_tests) { rtc_source_set("mocks") { testonly = true @@ -446,9 +435,6 @@ if (rtc_include_tests) { sources = [ "aec/echo_cancellation_unittest.cc", "aec/system_delay_unittest.cc", - "agc/agc_manager_direct_unittest.cc", - "agc/loudness_histogram_unittest.cc", - "agc/mock_agc.h", "audio_buffer_unittest.cc", "audio_frame_view_unittest.cc", "config_unittest.cc", @@ -496,6 +482,7 @@ if (rtc_include_tests) { "../../test:test_support", "../audio_coding:neteq_input_audio_tools", "aec_dump:mock_aec_dump_unittests", + "agc:agc_unittests", "agc2:adaptive_digital_unittests", "agc2:biquad_filter_unittests", "agc2:fixed_digital_unittests", @@ -620,13 +607,13 @@ if (rtc_include_tests) { "test/fake_recording_device.h", ] deps = [ - ":agc_gain_map_internal", "../../api:array_view", "../../api/audio:audio_frame_api", "../../common_audio:common_audio", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", "../../rtc_base:safe_minmax", + "agc:gain_map", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", ] @@ -734,6 +721,7 @@ if (rtc_include_tests) { "../../system_wrappers:metrics_default", "../../test:fileutils", "../../test:test_support", + "agc:level_estimation", "//testing/gtest", ] } diff --git a/modules/audio_processing/agc/BUILD.gn b/modules/audio_processing/agc/BUILD.gn new file mode 100644 index 0000000000..c5d4fbaa61 --- /dev/null +++ b/modules/audio_processing/agc/BUILD.gn @@ -0,0 +1,129 @@ +# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import("../../../webrtc.gni") + +rtc_source_set("agc") { + sources = [ + "agc_manager_direct.cc", + "agc_manager_direct.h", + ] + configs += [ "..:apm_debug_dump" ] + deps = [ + ":gain_map", + ":level_estimation", + "..:apm_logging", + "..:gain_control_interface", + "../../..:typedefs", + "../../..:webrtc_common", + "../../../rtc_base:checks", + "../../../rtc_base:logging", + "../../../rtc_base:macromagic", + "../../../rtc_base:safe_minmax", + "../../../system_wrappers:metrics_api", + "../vad", + ] +} + +rtc_source_set("level_estimation") { + sources = [ + "agc.cc", + "agc.h", + "loudness_histogram.cc", + "loudness_histogram.h", + "utility.cc", + "utility.h", + ] + deps = [ + "../../..:typedefs", + "../../..:webrtc_common", + "../../../rtc_base:checks", + "../../../rtc_base:macromagic", + "../vad", + ] +} + +rtc_source_set("agc_legacy_c") { + visibility = [ + ":*", + "..:*", + ] # Only targets in this file and in + # audio_processing can depend on + # this. + + sources = [ + "legacy/analog_agc.c", + "legacy/analog_agc.h", + "legacy/digital_agc.c", + "legacy/digital_agc.h", + "legacy/gain_control.h", + ] + + deps = [ + "../../..:typedefs", + "../../..:webrtc_common", + "../../../common_audio", + "../../../common_audio:common_audio_c", + "../../../common_audio:fft4g", + "../../../rtc_base:checks", + "../../../rtc_base:rtc_base_approved", + "../../../system_wrappers:cpu_features_api", + ] + + if (rtc_build_with_neon) { + if (current_cpu != "arm64") { + # Enable compilation for the NEON instruction set. This is needed + # since //build/config/arm.gni only enables NEON for iOS, not Android. + # This provides the same functionality as webrtc/build/arm_neon.gypi. + suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] + cflags = [ "-mfpu=neon" ] + } + + # Disable LTO on NEON targets due to compiler bug. + # TODO(fdegans): Enable this. See crbug.com/408997. + if (rtc_use_lto) { + cflags -= [ + "-flto", + "-ffat-lto-objects", + ] + } + } +} + +rtc_source_set("gain_map") { + sources = [ + "gain_map_internal.h", + ] +} + +if (rtc_include_tests) { + rtc_source_set("agc_unittests") { + testonly = true + sources = [ + "agc_manager_direct_unittest.cc", + "loudness_histogram_unittest.cc", + "mock_agc.h", + ] + configs += [ "..:apm_debug_dump" ] + + if ((!build_with_chromium || is_win) && is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] + } + + deps = [ + ":agc", + ":level_estimation", + "..:mocks", + "../../..:webrtc_common", + "../../../test:fileutils", + "../../../test:test_support", + "//testing/gtest", + ] + } +} diff --git a/modules/audio_processing/agc/agc_manager_direct.cc b/modules/audio_processing/agc/agc_manager_direct.cc index a0ae0c0727..64fa2a6c31 100644 --- a/modules/audio_processing/agc/agc_manager_direct.cc +++ b/modules/audio_processing/agc/agc_manager_direct.cc @@ -17,7 +17,7 @@ #endif #include "modules/audio_processing/agc/gain_map_internal.h" -#include "modules/audio_processing/gain_control_impl.h" +#include "modules/audio_processing/include/gain_control.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h index 0882d3378c..9d27f1627d 100644 --- a/modules/audio_processing/include/audio_processing.h +++ b/modules/audio_processing/include/audio_processing.h @@ -28,6 +28,7 @@ #include "modules/audio_processing/include/audio_generator.h" #include "modules/audio_processing/include/audio_processing_statistics.h" #include "modules/audio_processing/include/config.h" +#include "modules/audio_processing/include/gain_control.h" #include "rtc_base/arraysize.h" #include "rtc_base/deprecation.h" #include "rtc_base/platform_file.h" @@ -948,96 +949,6 @@ class EchoControlMobile { virtual ~EchoControlMobile() {} }; -// The automatic gain control (AGC) component brings the signal to an -// appropriate range. This is done by applying a digital gain directly and, in -// the analog mode, prescribing an analog gain to be applied at the audio HAL. -// -// Recommended to be enabled on the client-side. -class GainControl { - public: - virtual int Enable(bool enable) = 0; - virtual bool is_enabled() const = 0; - - // When an analog mode is set, this must be called prior to |ProcessStream()| - // to pass the current analog level from the audio HAL. Must be within the - // range provided to |set_analog_level_limits()|. - virtual int set_stream_analog_level(int level) = 0; - - // When an analog mode is set, this should be called after |ProcessStream()| - // to obtain the recommended new analog level for the audio HAL. It is the - // users responsibility to apply this level. - virtual int stream_analog_level() = 0; - - enum Mode { - // Adaptive mode intended for use if an analog volume control is available - // on the capture device. It will require the user to provide coupling - // between the OS mixer controls and AGC through the |stream_analog_level()| - // functions. - // - // It consists of an analog gain prescription for the audio device and a - // digital compression stage. - kAdaptiveAnalog, - - // Adaptive mode intended for situations in which an analog volume control - // is unavailable. It operates in a similar fashion to the adaptive analog - // mode, but with scaling instead applied in the digital domain. As with - // the analog mode, it additionally uses a digital compression stage. - kAdaptiveDigital, - - // Fixed mode which enables only the digital compression stage also used by - // the two adaptive modes. - // - // It is distinguished from the adaptive modes by considering only a - // short time-window of the input signal. It applies a fixed gain through - // most of the input level range, and compresses (gradually reduces gain - // with increasing level) the input signal at higher levels. This mode is - // preferred on embedded devices where the capture signal level is - // predictable, so that a known gain can be applied. - kFixedDigital - }; - - virtual int set_mode(Mode mode) = 0; - virtual Mode mode() const = 0; - - // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels - // from digital full-scale). The convention is to use positive values. For - // instance, passing in a value of 3 corresponds to -3 dBFs, or a target - // level 3 dB below full-scale. Limited to [0, 31]. - // - // TODO(ajm): use a negative value here instead, if/when VoE will similarly - // update its interface. - virtual int set_target_level_dbfs(int level) = 0; - virtual int target_level_dbfs() const = 0; - - // Sets the maximum |gain| the digital compression stage may apply, in dB. A - // higher number corresponds to greater compression, while a value of 0 will - // leave the signal uncompressed. Limited to [0, 90]. - virtual int set_compression_gain_db(int gain) = 0; - virtual int compression_gain_db() const = 0; - - // When enabled, the compression stage will hard limit the signal to the - // target level. Otherwise, the signal will be compressed but not limited - // above the target level. - virtual int enable_limiter(bool enable) = 0; - virtual bool is_limiter_enabled() const = 0; - - // Sets the |minimum| and |maximum| analog levels of the audio capture device. - // Must be set if and only if an analog mode is used. Limited to [0, 65535]. - virtual int set_analog_level_limits(int minimum, int maximum) = 0; - virtual int analog_level_minimum() const = 0; - virtual int analog_level_maximum() const = 0; - - // Returns true if the AGC has detected a saturation event (period where the - // signal reaches digital full-scale) in the current frame and the analog - // level cannot be reduced. - // - // This could be used as an indicator to reduce or disable analog mic gain at - // the audio HAL. - virtual bool stream_is_saturated() const = 0; - - protected: - virtual ~GainControl() {} -}; // TODO(peah): Remove this interface. // A filtering component which removes DC offset and low-frequency noise. // Recommended to be enabled on the client-side. diff --git a/modules/audio_processing/include/gain_control.h b/modules/audio_processing/include/gain_control.h new file mode 100644 index 0000000000..420b1c6e38 --- /dev/null +++ b/modules/audio_processing/include/gain_control.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_PROCESSING_INCLUDE_GAIN_CONTROL_H_ +#define MODULES_AUDIO_PROCESSING_INCLUDE_GAIN_CONTROL_H_ + +namespace webrtc { + +// The automatic gain control (AGC) component brings the signal to an +// appropriate range. This is done by applying a digital gain directly and, in +// the analog mode, prescribing an analog gain to be applied at the audio HAL. +// +// Recommended to be enabled on the client-side. +class GainControl { + public: + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // When an analog mode is set, this must be called prior to |ProcessStream()| + // to pass the current analog level from the audio HAL. Must be within the + // range provided to |set_analog_level_limits()|. + virtual int set_stream_analog_level(int level) = 0; + + // When an analog mode is set, this should be called after |ProcessStream()| + // to obtain the recommended new analog level for the audio HAL. It is the + // users responsibility to apply this level. + virtual int stream_analog_level() = 0; + + enum Mode { + // Adaptive mode intended for use if an analog volume control is available + // on the capture device. It will require the user to provide coupling + // between the OS mixer controls and AGC through the |stream_analog_level()| + // functions. + // + // It consists of an analog gain prescription for the audio device and a + // digital compression stage. + kAdaptiveAnalog, + + // Adaptive mode intended for situations in which an analog volume control + // is unavailable. It operates in a similar fashion to the adaptive analog + // mode, but with scaling instead applied in the digital domain. As with + // the analog mode, it additionally uses a digital compression stage. + kAdaptiveDigital, + + // Fixed mode which enables only the digital compression stage also used by + // the two adaptive modes. + // + // It is distinguished from the adaptive modes by considering only a + // short time-window of the input signal. It applies a fixed gain through + // most of the input level range, and compresses (gradually reduces gain + // with increasing level) the input signal at higher levels. This mode is + // preferred on embedded devices where the capture signal level is + // predictable, so that a known gain can be applied. + kFixedDigital + }; + + virtual int set_mode(Mode mode) = 0; + virtual Mode mode() const = 0; + + // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels + // from digital full-scale). The convention is to use positive values. For + // instance, passing in a value of 3 corresponds to -3 dBFs, or a target + // level 3 dB below full-scale. Limited to [0, 31]. + // + // TODO(ajm): use a negative value here instead, if/when VoE will similarly + // update its interface. + virtual int set_target_level_dbfs(int level) = 0; + virtual int target_level_dbfs() const = 0; + + // Sets the maximum |gain| the digital compression stage may apply, in dB. A + // higher number corresponds to greater compression, while a value of 0 will + // leave the signal uncompressed. Limited to [0, 90]. + virtual int set_compression_gain_db(int gain) = 0; + virtual int compression_gain_db() const = 0; + + // When enabled, the compression stage will hard limit the signal to the + // target level. Otherwise, the signal will be compressed but not limited + // above the target level. + virtual int enable_limiter(bool enable) = 0; + virtual bool is_limiter_enabled() const = 0; + + // Sets the |minimum| and |maximum| analog levels of the audio capture device. + // Must be set if and only if an analog mode is used. Limited to [0, 65535]. + virtual int set_analog_level_limits(int minimum, int maximum) = 0; + virtual int analog_level_minimum() const = 0; + virtual int analog_level_maximum() const = 0; + + // Returns true if the AGC has detected a saturation event (period where the + // signal reaches digital full-scale) in the current frame and the analog + // level cannot be reduced. + // + // This could be used as an indicator to reduce or disable analog mic gain at + // the audio HAL. + virtual bool stream_is_saturated() const = 0; + + protected: + virtual ~GainControl() {} +}; +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_INCLUDE_GAIN_CONTROL_H_ diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn index d31ffc95ef..dc5f193232 100644 --- a/rtc_tools/BUILD.gn +++ b/rtc_tools/BUILD.gn @@ -290,7 +290,7 @@ if (rtc_include_tests) { deps = [ "../api/audio:audio_frame_api", - "../modules/audio_processing", + "../modules/audio_processing/agc:level_estimation", "../modules/audio_processing/vad", "../rtc_base:rtc_base_approved", "../rtc_base:safe_minmax",