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" |
Danil Chapovalov | 32b1834 | 2019-07-11 11:58:14 | [diff] [blame] | 16 | #include "api/task_queue/default_task_queue_factory.h" |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 17 | #include "modules/audio_processing/aec_dump/aec_dump_factory.h" |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 18 | #include "modules/audio_processing/include/audio_processing.h" |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 19 | #include "rtc_base/arraysize.h" |
Alex Loiko | a05ee82 | 2018-02-20 14:58:36 | [diff] [blame] | 20 | #include "rtc_base/numerics/safe_minmax.h" |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 21 | #include "rtc_base/task_queue.h" |
Mirko Bonadei | 17f4878 | 2018-09-28 06:51:10 | [diff] [blame] | 22 | #include "system_wrappers/include/field_trial.h" |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 23 | #include "test/fuzzers/audio_processing_fuzzer_helper.h" |
| 24 | #include "test/fuzzers/fuzz_data_helper.h" |
| 25 | |
| 26 | namespace webrtc { |
| 27 | namespace { |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 28 | |
| 29 | const std::string kFieldTrialNames[] = { |
Gustaf Ullberg | 68d6d44 | 2019-01-29 09:08:15 | [diff] [blame] | 30 | "WebRTC-Audio-Agc2ForceExtraSaturationMargin", |
| 31 | "WebRTC-Audio-Agc2ForceInitialSaturationMargin", |
Gustaf Ullberg | aa1a43e | 2019-02-21 12:09:50 | [diff] [blame] | 32 | "WebRTC-Aec3MinErleDuringOnsetsKillSwitch", |
Gustaf Ullberg | 9249fbf | 2019-03-14 10:24:54 | [diff] [blame] | 33 | "WebRTC-Aec3ShortHeadroomKillSwitch", |
Gustaf Ullberg | 53e2211 | 2018-10-11 13:27:26 | [diff] [blame] | 34 | }; |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 35 | |
| 36 | std::unique_ptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data, |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 37 | std::string* field_trial_string, |
| 38 | rtc::TaskQueue* worker_queue) { |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 39 | // Parse boolean values for optionally enabling different |
| 40 | // configurable public components of APM. |
| 41 | bool exp_agc = fuzz_data->ReadOrDefaultValue(true); |
| 42 | bool exp_ns = fuzz_data->ReadOrDefaultValue(true); |
Sam Zackrisson | 44b98f9 | 2018-06-25 12:21:53 | [diff] [blame] | 43 | static_cast<void>(fuzz_data->ReadOrDefaultValue(true)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 44 | bool ef = fuzz_data->ReadOrDefaultValue(true); |
| 45 | bool raf = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | 8a5edb2 | 2018-06-18 15:25:32 | [diff] [blame] | 46 | static_cast<void>(fuzz_data->ReadOrDefaultValue(true)); |
Alessio Bazzica | cc22f51 | 2018-08-30 11:01:34 | [diff] [blame] | 47 | static_cast<void>(fuzz_data->ReadOrDefaultValue(true)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 48 | bool red = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 49 | bool hpf = fuzz_data->ReadOrDefaultValue(true); |
| 50 | bool aec3 = fuzz_data->ReadOrDefaultValue(true); |
| 51 | |
| 52 | bool use_aec = fuzz_data->ReadOrDefaultValue(true); |
| 53 | bool use_aecm = fuzz_data->ReadOrDefaultValue(true); |
| 54 | bool use_agc = fuzz_data->ReadOrDefaultValue(true); |
| 55 | bool use_ns = fuzz_data->ReadOrDefaultValue(true); |
| 56 | bool use_le = fuzz_data->ReadOrDefaultValue(true); |
| 57 | bool use_vad = fuzz_data->ReadOrDefaultValue(true); |
| 58 | bool use_agc_limiter = fuzz_data->ReadOrDefaultValue(true); |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 59 | bool use_agc2 = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 60 | |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 61 | // Read an int8 value, but don't let it be too large or small. |
| 62 | const float gain_controller2_gain_db = |
Alex Loiko | 20f60f0 | 2018-11-12 11:09:57 | [diff] [blame] | 63 | rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(0), -40, 40); |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 64 | |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 65 | constexpr size_t kNumFieldTrials = arraysize(kFieldTrialNames); |
Sam Zackrisson | b5d3802 | 2018-07-13 08:20:30 | [diff] [blame] | 66 | // Verify that the read data type has enough bits to fuzz the field trials. |
Jonas Olsson | e068ad6 | 2018-10-24 08:33:08 | [diff] [blame] | 67 | using FieldTrialBitmaskType = uint64_t; |
Yves Gerey | 9516c38 | 2018-10-25 12:26:07 | [diff] [blame] | 68 | static_assert(kNumFieldTrials <= sizeof(FieldTrialBitmaskType) * 8, |
| 69 | "FieldTrialBitmaskType is not large enough."); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 70 | std::bitset<kNumFieldTrials> field_trial_bitmask( |
Sam Zackrisson | b5d3802 | 2018-07-13 08:20:30 | [diff] [blame] | 71 | fuzz_data->ReadOrDefaultValue<FieldTrialBitmaskType>(0)); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 72 | for (size_t i = 0; i < kNumFieldTrials; ++i) { |
| 73 | if (field_trial_bitmask[i]) { |
| 74 | *field_trial_string += kFieldTrialNames[i] + "/Enabled/"; |
| 75 | } |
| 76 | } |
| 77 | field_trial::InitFieldTrialsFromString(field_trial_string->c_str()); |
| 78 | |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 79 | bool use_agc2_adaptive_digital = fuzz_data->ReadOrDefaultValue(true); |
| 80 | bool use_agc2_adaptive_digital_rms_estimator = |
| 81 | fuzz_data->ReadOrDefaultValue(true); |
| 82 | bool use_agc2_adaptive_digital_saturation_protector = |
| 83 | fuzz_data->ReadOrDefaultValue(true); |
| 84 | |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 85 | // Ignore a few bytes. Bytes from this segment will be used for |
| 86 | // future config flag changes. We assume 40 bytes is enough for |
| 87 | // configuring the APM. |
| 88 | constexpr size_t kSizeOfConfigSegment = 40; |
| 89 | RTC_DCHECK(kSizeOfConfigSegment >= fuzz_data->BytesRead()); |
| 90 | static_cast<void>( |
| 91 | fuzz_data->ReadByteArray(kSizeOfConfigSegment - fuzz_data->BytesRead())); |
| 92 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 93 | // Filter out incompatible settings that lead to CHECK failures. |
Alex Loiko | c480e9d | 2018-07-05 09:14:28 | [diff] [blame] | 94 | if ((use_aecm && use_aec) || // These settings cause CHECK failure. |
| 95 | (use_aecm && aec3 && use_ns) // These settings trigger webrtc:9489. |
Jonas Olsson | a4d8737 | 2019-07-05 17:08:33 | [diff] [blame] | 96 | ) { |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 97 | return nullptr; |
| 98 | } |
| 99 | |
| 100 | // Components can be enabled through webrtc::Config and |
| 101 | // webrtc::AudioProcessingConfig. |
| 102 | Config config; |
| 103 | |
| 104 | std::unique_ptr<EchoControlFactory> echo_control_factory; |
| 105 | if (aec3) { |
| 106 | echo_control_factory.reset(new EchoCanceller3Factory()); |
| 107 | } |
| 108 | |
| 109 | config.Set<ExperimentalAgc>(new ExperimentalAgc(exp_agc)); |
| 110 | config.Set<ExperimentalNs>(new ExperimentalNs(exp_ns)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 111 | config.Set<ExtendedFilter>(new ExtendedFilter(ef)); |
| 112 | config.Set<RefinedAdaptiveFilter>(new RefinedAdaptiveFilter(raf)); |
Alex Loiko | 8a5edb2 | 2018-06-18 15:25:32 | [diff] [blame] | 113 | config.Set<DelayAgnostic>(new DelayAgnostic(true)); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 114 | |
| 115 | std::unique_ptr<AudioProcessing> apm( |
| 116 | AudioProcessingBuilder() |
| 117 | .SetEchoControlFactory(std::move(echo_control_factory)) |
| 118 | .Create(config)); |
| 119 | |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 120 | #ifdef WEBRTC_LINUX |
| 121 | apm->AttachAecDump(AecDumpFactory::Create("/dev/null", -1, worker_queue)); |
| 122 | #endif |
Alex Loiko | f344dbb | 2018-06-19 10:33:20 | [diff] [blame] | 123 | |
Sam Zackrisson | 2a959d9 | 2018-07-23 14:48:07 | [diff] [blame] | 124 | webrtc::AudioProcessing::Config apm_config; |
Per Ã…hgren | e14cb99 | 2019-11-27 08:34:22 | [diff] [blame^] | 125 | apm_config.pipeline.multi_channel_render = true; |
| 126 | apm_config.pipeline.multi_channel_capture = true; |
Sam Zackrisson | 1c718f9 | 2018-09-26 08:07:48 | [diff] [blame] | 127 | apm_config.echo_canceller.enabled = use_aec || use_aecm; |
| 128 | apm_config.echo_canceller.mobile_mode = use_aecm; |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 129 | apm_config.residual_echo_detector.enabled = red; |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 130 | apm_config.high_pass_filter.enabled = hpf; |
Sam Zackrisson | f0d1c03 | 2019-03-27 12:28:08 | [diff] [blame] | 131 | apm_config.gain_controller1.enabled = use_agc; |
| 132 | apm_config.gain_controller1.enable_limiter = use_agc_limiter; |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 133 | apm_config.gain_controller2.enabled = use_agc2; |
Alessio Bazzica | 1e2542f | 2018-11-13 13:44:15 | [diff] [blame] | 134 | apm_config.gain_controller2.fixed_digital.gain_db = gain_controller2_gain_db; |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 135 | apm_config.gain_controller2.adaptive_digital.enabled = |
| 136 | use_agc2_adaptive_digital; |
| 137 | apm_config.gain_controller2.adaptive_digital.level_estimator = |
| 138 | use_agc2_adaptive_digital_rms_estimator |
| 139 | ? webrtc::AudioProcessing::Config::GainController2::LevelEstimator:: |
| 140 | kRms |
| 141 | : webrtc::AudioProcessing::Config::GainController2::LevelEstimator:: |
| 142 | kPeak; |
| 143 | apm_config.gain_controller2.adaptive_digital.use_saturation_protector = |
| 144 | use_agc2_adaptive_digital_saturation_protector; |
Sam Zackrisson | 2351313 | 2019-01-11 14:10:32 | [diff] [blame] | 145 | apm_config.noise_suppression.enabled = use_ns; |
Sam Zackrisson | 6c330ab | 2019-01-04 09:35:53 | [diff] [blame] | 146 | apm_config.voice_detection.enabled = use_vad; |
saza | 6787f23 | 2019-10-11 17:31:07 | [diff] [blame] | 147 | apm_config.level_estimation.enabled = use_le; |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 148 | apm->ApplyConfig(apm_config); |
| 149 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 150 | return apm; |
| 151 | } |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 152 | |
| 153 | TaskQueueFactory* GetTaskQueueFactory() { |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 154 | static TaskQueueFactory* const factory = |
Danil Chapovalov | 32b1834 | 2019-07-11 11:58:14 | [diff] [blame] | 155 | CreateDefaultTaskQueueFactory().release(); |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 156 | return factory; |
| 157 | } |
| 158 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 159 | } // namespace |
| 160 | |
| 161 | void FuzzOneInput(const uint8_t* data, size_t size) { |
Sam Zackrisson | d71edac | 2019-03-11 12:47:54 | [diff] [blame] | 162 | if (size > 400000) { |
| 163 | return; |
| 164 | } |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 165 | test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size)); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 166 | // This string must be in scope during execution, according to documentation |
Mirko Bonadei | 17f4878 | 2018-09-28 06:51:10 | [diff] [blame] | 167 | // for field_trial.h. Hence it's created here and not in CreateApm. |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 168 | std::string field_trial_string = ""; |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 169 | |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 170 | rtc::TaskQueue worker_queue(GetTaskQueueFactory()->CreateTaskQueue( |
| 171 | "rtc-low-prio", rtc::TaskQueue::Priority::LOW)); |
| 172 | auto apm = CreateApm(&fuzz_data, &field_trial_string, &worker_queue); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 173 | |
| 174 | if (apm) { |
| 175 | FuzzAudioProcessing(&fuzz_data, std::move(apm)); |
| 176 | } |
| 177 | } |
| 178 | } // namespace webrtc |