Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 11 | #include <bitset> |
| 12 | #include <string> |
| 13 | |
Karl Wiberg | 918f50c | 2018-07-05 09:40:33 | [diff] [blame^] | 14 | #include "absl/memory/memory.h" |
Gustaf Ullberg | 0efa941 | 2018-02-27 12:58:45 | [diff] [blame] | 15 | #include "api/audio/echo_canceller3_factory.h" |
Alex Loiko | f344dbb | 2018-06-19 10:33:20 | [diff] [blame] | 16 | #include "modules/audio_processing/aec_dump/mock_aec_dump.h" |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 17 | #include "modules/audio_processing/include/audio_processing.h" |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 18 | #include "rtc_base/arraysize.h" |
Alex Loiko | a05ee82 | 2018-02-20 14:58:36 | [diff] [blame] | 19 | #include "rtc_base/numerics/safe_minmax.h" |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 20 | #include "system_wrappers/include/field_trial_default.h" |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 21 | #include "test/fuzzers/audio_processing_fuzzer_helper.h" |
| 22 | #include "test/fuzzers/fuzz_data_helper.h" |
| 23 | |
| 24 | namespace webrtc { |
| 25 | namespace { |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 26 | |
| 27 | const std::string kFieldTrialNames[] = { |
| 28 | "WebRTC-Aec3TransparentModeKillSwitch", |
| 29 | "WebRTC-Aec3StationaryRenderImprovementsKillSwitch", |
| 30 | "WebRTC-Aec3EnforceDelayAfterRealignmentKillSwitch", |
| 31 | "WebRTC-Aec3UseShortDelayEstimatorWindow", |
| 32 | "WebRTC-Aec3ReverbBasedOnRenderKillSwitch", |
| 33 | "WebRTC-Aec3ReverbModellingKillSwitch", |
| 34 | "WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch", |
| 35 | "WebRTC-Aec3TransparencyImprovementsKillSwitch", |
| 36 | "WebRTC-Aec3SoftTransparentModeKillSwitch", |
| 37 | "WebRTC-Aec3OverrideEchoPathGainKillSwitch", |
| 38 | "WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch", |
| 39 | "WebRTC-Aec3DownSamplingFactor8KillSwitch", |
| 40 | "WebRTC-Aec3EnforceSkewHysteresis1", |
| 41 | "WebRTC-Aec3EnforceSkewHysteresis2"}; |
| 42 | |
| 43 | std::unique_ptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data, |
| 44 | std::string* field_trial_string) { |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 45 | // Parse boolean values for optionally enabling different |
| 46 | // configurable public components of APM. |
| 47 | bool exp_agc = fuzz_data->ReadOrDefaultValue(true); |
| 48 | bool exp_ns = fuzz_data->ReadOrDefaultValue(true); |
Sam Zackrisson | 44b98f9 | 2018-06-25 12:21:53 | [diff] [blame] | 49 | static_cast<void>(fuzz_data->ReadOrDefaultValue(true)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 50 | bool ef = fuzz_data->ReadOrDefaultValue(true); |
| 51 | bool raf = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | 8a5edb2 | 2018-06-18 15:25:32 | [diff] [blame] | 52 | static_cast<void>(fuzz_data->ReadOrDefaultValue(true)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 53 | bool ie = fuzz_data->ReadOrDefaultValue(true); |
| 54 | bool red = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 55 | bool hpf = fuzz_data->ReadOrDefaultValue(true); |
| 56 | bool aec3 = fuzz_data->ReadOrDefaultValue(true); |
| 57 | |
| 58 | bool use_aec = fuzz_data->ReadOrDefaultValue(true); |
| 59 | bool use_aecm = fuzz_data->ReadOrDefaultValue(true); |
| 60 | bool use_agc = fuzz_data->ReadOrDefaultValue(true); |
| 61 | bool use_ns = fuzz_data->ReadOrDefaultValue(true); |
| 62 | bool use_le = fuzz_data->ReadOrDefaultValue(true); |
| 63 | bool use_vad = fuzz_data->ReadOrDefaultValue(true); |
| 64 | bool use_agc_limiter = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | a05ee82 | 2018-02-20 14:58:36 | [diff] [blame] | 65 | bool use_agc2_limiter = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 66 | |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 67 | // Read an int8 value, but don't let it be too large or small. |
| 68 | const float gain_controller2_gain_db = |
| 69 | rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(0), -50, 50); |
| 70 | |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 71 | constexpr size_t kNumFieldTrials = arraysize(kFieldTrialNames); |
| 72 | // This check ensures the uint16_t that is read has enough bits to cover all |
| 73 | // the field trials. |
| 74 | RTC_DCHECK_LE(kNumFieldTrials, 16); |
| 75 | std::bitset<kNumFieldTrials> field_trial_bitmask( |
| 76 | fuzz_data->ReadOrDefaultValue<uint16_t>(0)); |
| 77 | for (size_t i = 0; i < kNumFieldTrials; ++i) { |
| 78 | if (field_trial_bitmask[i]) { |
| 79 | *field_trial_string += kFieldTrialNames[i] + "/Enabled/"; |
| 80 | } |
| 81 | } |
| 82 | field_trial::InitFieldTrialsFromString(field_trial_string->c_str()); |
| 83 | |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 84 | // Ignore a few bytes. Bytes from this segment will be used for |
| 85 | // future config flag changes. We assume 40 bytes is enough for |
| 86 | // configuring the APM. |
| 87 | constexpr size_t kSizeOfConfigSegment = 40; |
| 88 | RTC_DCHECK(kSizeOfConfigSegment >= fuzz_data->BytesRead()); |
| 89 | static_cast<void>( |
| 90 | fuzz_data->ReadByteArray(kSizeOfConfigSegment - fuzz_data->BytesRead())); |
| 91 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 92 | // Filter out incompatible settings that lead to CHECK failures. |
| 93 | if (use_aecm && use_aec) { |
| 94 | return nullptr; |
| 95 | } |
| 96 | |
| 97 | // Components can be enabled through webrtc::Config and |
| 98 | // webrtc::AudioProcessingConfig. |
| 99 | Config config; |
| 100 | |
| 101 | std::unique_ptr<EchoControlFactory> echo_control_factory; |
| 102 | if (aec3) { |
| 103 | echo_control_factory.reset(new EchoCanceller3Factory()); |
| 104 | } |
| 105 | |
| 106 | config.Set<ExperimentalAgc>(new ExperimentalAgc(exp_agc)); |
| 107 | config.Set<ExperimentalNs>(new ExperimentalNs(exp_ns)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 108 | config.Set<ExtendedFilter>(new ExtendedFilter(ef)); |
| 109 | config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(raf)); |
Alex Loiko | 8a5edb2 | 2018-06-18 15:25:32 | [diff] [blame] | 110 | config.Set<DelayAgnostic>(new DelayAgnostic(true)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 111 | config.Set<Intelligibility>(new Intelligibility(ie)); |
| 112 | |
| 113 | std::unique_ptr<AudioProcessing> apm( |
| 114 | AudioProcessingBuilder() |
| 115 | .SetEchoControlFactory(std::move(echo_control_factory)) |
| 116 | .Create(config)); |
| 117 | |
Alex Loiko | f344dbb | 2018-06-19 10:33:20 | [diff] [blame] | 118 | apm->AttachAecDump( |
Karl Wiberg | 918f50c | 2018-07-05 09:40:33 | [diff] [blame^] | 119 | absl::make_unique<testing::NiceMock<webrtc::test::MockAecDump>>()); |
Alex Loiko | f344dbb | 2018-06-19 10:33:20 | [diff] [blame] | 120 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 121 | webrtc::AudioProcessing::Config apm_config; |
| 122 | apm_config.residual_echo_detector.enabled = red; |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 123 | apm_config.high_pass_filter.enabled = hpf; |
Alex Loiko | a05ee82 | 2018-02-20 14:58:36 | [diff] [blame] | 124 | apm_config.gain_controller2.enabled = use_agc2_limiter; |
| 125 | |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 126 | apm_config.gain_controller2.fixed_gain_db = gain_controller2_gain_db; |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 127 | |
| 128 | apm->ApplyConfig(apm_config); |
| 129 | |
| 130 | apm->echo_cancellation()->Enable(use_aec); |
| 131 | apm->echo_control_mobile()->Enable(use_aecm); |
| 132 | apm->gain_control()->Enable(use_agc); |
| 133 | apm->noise_suppression()->Enable(use_ns); |
| 134 | apm->level_estimator()->Enable(use_le); |
| 135 | apm->voice_detection()->Enable(use_vad); |
| 136 | apm->gain_control()->enable_limiter(use_agc_limiter); |
| 137 | |
| 138 | return apm; |
| 139 | } |
| 140 | } // namespace |
| 141 | |
| 142 | void FuzzOneInput(const uint8_t* data, size_t size) { |
| 143 | test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size)); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 144 | // This string must be in scope during execution, according to documentation |
| 145 | // for field_trial_default.h. Hence it's created here and not in CreateApm. |
| 146 | std::string field_trial_string = ""; |
| 147 | auto apm = CreateApm(&fuzz_data, &field_trial_string); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 148 | |
| 149 | if (apm) { |
| 150 | FuzzAudioProcessing(&fuzz_data, std::move(apm)); |
| 151 | } |
| 152 | } |
| 153 | } // namespace webrtc |