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 | |
Danil Chapovalov | b64eef1 | 2024-01-04 13:45:23 | [diff] [blame] | 14 | #include "absl/base/nullability.h" |
Karl Wiberg | 918f50c | 2018-07-05 09:40:33 | [diff] [blame] | 15 | #include "absl/memory/memory.h" |
Florent Castelli | 0afde76 | 2024-04-19 15:07:08 | [diff] [blame] | 16 | #include "api/audio/audio_processing.h" |
Gustaf Ullberg | 0efa941 | 2018-02-27 12:58:45 | [diff] [blame] | 17 | #include "api/audio/echo_canceller3_factory.h" |
Sam Zackrisson | 03cb7e5 | 2021-12-06 14:40:04 | [diff] [blame] | 18 | #include "api/audio/echo_detector_creator.h" |
Danil Chapovalov | 32b1834 | 2019-07-11 11:58:14 | [diff] [blame] | 19 | #include "api/task_queue/default_task_queue_factory.h" |
Danil Chapovalov | b64eef1 | 2024-01-04 13:45:23 | [diff] [blame] | 20 | #include "api/task_queue/task_queue_base.h" |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 21 | #include "modules/audio_processing/aec_dump/aec_dump_factory.h" |
Per Åhgren | cc73ed3 | 2020-04-26 21:56:17 | [diff] [blame] | 22 | #include "modules/audio_processing/test/audio_processing_builder_for_testing.h" |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 23 | #include "rtc_base/arraysize.h" |
Alex Loiko | a05ee82 | 2018-02-20 14:58:36 | [diff] [blame] | 24 | #include "rtc_base/numerics/safe_minmax.h" |
Mirko Bonadei | 17f4878 | 2018-09-28 06:51:10 | [diff] [blame] | 25 | #include "system_wrappers/include/field_trial.h" |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 26 | #include "test/fuzzers/audio_processing_fuzzer_helper.h" |
| 27 | #include "test/fuzzers/fuzz_data_helper.h" |
| 28 | |
| 29 | namespace webrtc { |
| 30 | namespace { |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 31 | |
| 32 | const std::string kFieldTrialNames[] = { |
Gustaf Ullberg | aa1a43e | 2019-02-21 12:09:50 | [diff] [blame] | 33 | "WebRTC-Aec3MinErleDuringOnsetsKillSwitch", |
Gustaf Ullberg | 9249fbf | 2019-03-14 10:24:54 | [diff] [blame] | 34 | "WebRTC-Aec3ShortHeadroomKillSwitch", |
Gustaf Ullberg | 53e2211 | 2018-10-11 13:27:26 | [diff] [blame] | 35 | }; |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 36 | |
Danil Chapovalov | b64eef1 | 2024-01-04 13:45:23 | [diff] [blame] | 37 | rtc::scoped_refptr<AudioProcessing> CreateApm( |
| 38 | test::FuzzDataHelper* fuzz_data, |
| 39 | std::string* field_trial_string, |
| 40 | absl::Nonnull<TaskQueueBase*> worker_queue) { |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 41 | // Parse boolean values for optionally enabling different |
| 42 | // configurable public components of APM. |
Alessio Bazzica | be1b898 | 2021-09-17 06:26:10 | [diff] [blame] | 43 | bool use_ts = fuzz_data->ReadOrDefaultValue(true); |
Sam Zackrisson | 03cb7e5 | 2021-12-06 14:40:04 | [diff] [blame] | 44 | bool use_red = fuzz_data->ReadOrDefaultValue(true); |
| 45 | bool use_hpf = fuzz_data->ReadOrDefaultValue(true); |
| 46 | bool use_aec3 = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 47 | bool use_aec = fuzz_data->ReadOrDefaultValue(true); |
| 48 | bool use_aecm = fuzz_data->ReadOrDefaultValue(true); |
| 49 | bool use_agc = fuzz_data->ReadOrDefaultValue(true); |
| 50 | bool use_ns = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 51 | bool use_agc_limiter = fuzz_data->ReadOrDefaultValue(true); |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 52 | bool use_agc2 = fuzz_data->ReadOrDefaultValue(true); |
Sam Zackrisson | 306eee3 | 2022-05-31 13:03:28 | [diff] [blame] | 53 | bool use_agc2_adaptive_digital = fuzz_data->ReadOrDefaultValue(true); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 54 | |
Sam Zackrisson | 306eee3 | 2022-05-31 13:03:28 | [diff] [blame] | 55 | // Read a gain value supported by GainController2::Validate(). |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 56 | const float gain_controller2_gain_db = |
Sam Zackrisson | 306eee3 | 2022-05-31 13:03:28 | [diff] [blame] | 57 | fuzz_data->ReadOrDefaultValue<uint8_t>(0) % 50; |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 58 | |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 59 | constexpr size_t kNumFieldTrials = arraysize(kFieldTrialNames); |
Sam Zackrisson | b5d3802 | 2018-07-13 08:20:30 | [diff] [blame] | 60 | // 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] | 61 | using FieldTrialBitmaskType = uint64_t; |
Yves Gerey | 9516c38 | 2018-10-25 12:26:07 | [diff] [blame] | 62 | static_assert(kNumFieldTrials <= sizeof(FieldTrialBitmaskType) * 8, |
| 63 | "FieldTrialBitmaskType is not large enough."); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 64 | std::bitset<kNumFieldTrials> field_trial_bitmask( |
Sam Zackrisson | b5d3802 | 2018-07-13 08:20:30 | [diff] [blame] | 65 | fuzz_data->ReadOrDefaultValue<FieldTrialBitmaskType>(0)); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 66 | for (size_t i = 0; i < kNumFieldTrials; ++i) { |
| 67 | if (field_trial_bitmask[i]) { |
| 68 | *field_trial_string += kFieldTrialNames[i] + "/Enabled/"; |
| 69 | } |
| 70 | } |
| 71 | field_trial::InitFieldTrialsFromString(field_trial_string->c_str()); |
| 72 | |
Alex Loiko | 38c15d3 | 2018-03-02 12:53:09 | [diff] [blame] | 73 | // Ignore a few bytes. Bytes from this segment will be used for |
| 74 | // future config flag changes. We assume 40 bytes is enough for |
| 75 | // configuring the APM. |
| 76 | constexpr size_t kSizeOfConfigSegment = 40; |
| 77 | RTC_DCHECK(kSizeOfConfigSegment >= fuzz_data->BytesRead()); |
| 78 | static_cast<void>( |
| 79 | fuzz_data->ReadByteArray(kSizeOfConfigSegment - fuzz_data->BytesRead())); |
| 80 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 81 | // Filter out incompatible settings that lead to CHECK failures. |
Sam Zackrisson | 03cb7e5 | 2021-12-06 14:40:04 | [diff] [blame] | 82 | if ((use_aecm && use_aec) || // These settings cause CHECK failure. |
| 83 | (use_aecm && use_aec3 && use_ns) // These settings trigger webrtc:9489. |
Jonas Olsson | a4d8737 | 2019-07-05 17:08:33 | [diff] [blame] | 84 | ) { |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 85 | return nullptr; |
| 86 | } |
| 87 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 88 | std::unique_ptr<EchoControlFactory> echo_control_factory; |
Sam Zackrisson | 03cb7e5 | 2021-12-06 14:40:04 | [diff] [blame] | 89 | if (use_aec3) { |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 90 | echo_control_factory.reset(new EchoCanceller3Factory()); |
| 91 | } |
| 92 | |
Sam Zackrisson | 2a959d9 | 2018-07-23 14:48:07 | [diff] [blame] | 93 | webrtc::AudioProcessing::Config apm_config; |
Per Åhgren | e14cb99 | 2019-11-27 08:34:22 | [diff] [blame] | 94 | apm_config.pipeline.multi_channel_render = true; |
| 95 | apm_config.pipeline.multi_channel_capture = true; |
Sam Zackrisson | 1c718f9 | 2018-09-26 08:07:48 | [diff] [blame] | 96 | apm_config.echo_canceller.enabled = use_aec || use_aecm; |
| 97 | apm_config.echo_canceller.mobile_mode = use_aecm; |
Sam Zackrisson | 03cb7e5 | 2021-12-06 14:40:04 | [diff] [blame] | 98 | apm_config.high_pass_filter.enabled = use_hpf; |
Sam Zackrisson | f0d1c03 | 2019-03-27 12:28:08 | [diff] [blame] | 99 | apm_config.gain_controller1.enabled = use_agc; |
| 100 | apm_config.gain_controller1.enable_limiter = use_agc_limiter; |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 101 | apm_config.gain_controller2.enabled = use_agc2; |
Alessio Bazzica | 1e2542f | 2018-11-13 13:44:15 | [diff] [blame] | 102 | apm_config.gain_controller2.fixed_digital.gain_db = gain_controller2_gain_db; |
Alessio Bazzica | dc10796 | 2018-12-03 17:22:34 | [diff] [blame] | 103 | apm_config.gain_controller2.adaptive_digital.enabled = |
| 104 | use_agc2_adaptive_digital; |
Sam Zackrisson | 2351313 | 2019-01-11 14:10:32 | [diff] [blame] | 105 | apm_config.noise_suppression.enabled = use_ns; |
Alessio Bazzica | be1b898 | 2021-09-17 06:26:10 | [diff] [blame] | 106 | apm_config.transient_suppression.enabled = use_ts; |
Alessio Bazzica | 0b45462 | 2021-10-18 09:09:48 | [diff] [blame] | 107 | |
| 108 | rtc::scoped_refptr<AudioProcessing> apm = |
| 109 | AudioProcessingBuilderForTesting() |
| 110 | .SetEchoControlFactory(std::move(echo_control_factory)) |
Sam Zackrisson | 03cb7e5 | 2021-12-06 14:40:04 | [diff] [blame] | 111 | .SetEchoDetector(use_red ? CreateEchoDetector() : nullptr) |
Alessio Bazzica | 0b45462 | 2021-10-18 09:09:48 | [diff] [blame] | 112 | .SetConfig(apm_config) |
| 113 | .Create(); |
| 114 | |
| 115 | #ifdef WEBRTC_LINUX |
| 116 | apm->AttachAecDump(AecDumpFactory::Create("/dev/null", -1, worker_queue)); |
| 117 | #endif |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 118 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 119 | return apm; |
| 120 | } |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 121 | |
| 122 | TaskQueueFactory* GetTaskQueueFactory() { |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 123 | static TaskQueueFactory* const factory = |
Danil Chapovalov | 32b1834 | 2019-07-11 11:58:14 | [diff] [blame] | 124 | CreateDefaultTaskQueueFactory().release(); |
Danil Chapovalov | cb2a4ff | 2019-04-10 07:47:00 | [diff] [blame] | 125 | return factory; |
| 126 | } |
| 127 | |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 128 | } // namespace |
| 129 | |
| 130 | void FuzzOneInput(const uint8_t* data, size_t size) { |
Sam Zackrisson | d71edac | 2019-03-11 12:47:54 | [diff] [blame] | 131 | if (size > 400000) { |
| 132 | return; |
| 133 | } |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 134 | test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size)); |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 135 | // This string must be in scope during execution, according to documentation |
Mirko Bonadei | 17f4878 | 2018-09-28 06:51:10 | [diff] [blame] | 136 | // for field_trial.h. Hence it's created here and not in CreateApm. |
Sam Zackrisson | 790da37 | 2018-06-19 08:46:04 | [diff] [blame] | 137 | std::string field_trial_string = ""; |
Alex Loiko | 4842c78 | 2018-10-23 11:43:28 | [diff] [blame] | 138 | |
Danil Chapovalov | b64eef1 | 2024-01-04 13:45:23 | [diff] [blame] | 139 | std::unique_ptr<TaskQueueBase, TaskQueueDeleter> worker_queue = |
| 140 | GetTaskQueueFactory()->CreateTaskQueue("rtc-low-prio", |
| 141 | TaskQueueFactory::Priority::LOW); |
| 142 | auto apm = CreateApm(&fuzz_data, &field_trial_string, worker_queue.get()); |
Alex Loiko | ab20a60 | 2018-01-16 11:50:34 | [diff] [blame] | 143 | |
| 144 | if (apm) { |
| 145 | FuzzAudioProcessing(&fuzz_data, std::move(apm)); |
| 146 | } |
| 147 | } |
| 148 | } // namespace webrtc |