diff --git a/test/fuzzers/BUILD.gn b/test/fuzzers/BUILD.gn index 4ac5e14875..c923b54bc3 100644 --- a/test/fuzzers/BUILD.gn +++ b/test/fuzzers/BUILD.gn @@ -480,6 +480,21 @@ webrtc_fuzzer_test("audio_processing_fuzzer") { seed_corpus = "corpora/audio_processing-corpus" } +webrtc_fuzzer_test("agc_fuzzer") { + sources = [ + "agc_fuzzer.cc", + ] + deps = [ + ":fuzz_data_helper", + "../../modules/audio_processing", + "../../rtc_base:rtc_base_approved", + "../../rtc_base:safe_minmax", + ] + + seed_corpus = "corpora/agc-corpus" + libfuzzer_options = [ "max_len=200000" ] +} + webrtc_fuzzer_test("comfort_noise_decoder_fuzzer") { sources = [ "comfort_noise_decoder_fuzzer.cc", diff --git a/test/fuzzers/agc_fuzzer.cc b/test/fuzzers/agc_fuzzer.cc new file mode 100644 index 0000000000..7253802d6b --- /dev/null +++ b/test/fuzzers/agc_fuzzer.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 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. + */ + +#include "modules/audio_processing/audio_buffer.h" +#include "modules/audio_processing/gain_control_impl.h" +#include "modules/audio_processing/include/audio_processing.h" +#include "rtc_base/numerics/safe_minmax.h" +#include "rtc_base/ptr_util.h" +#include "rtc_base/thread_annotations.h" +#include "test/fuzzers/fuzz_data_helper.h" + +namespace webrtc { +namespace { + +void FillAudioBuffer(test::FuzzDataHelper* fuzz_data, AudioBuffer* buffer) { + float* const* channels = buffer->channels_f(); + for (size_t i = 0; i < buffer->num_channels(); ++i) { + for (size_t j = 0; j < buffer->num_frames(); ++j) { + channels[i][j] = + static_cast(fuzz_data->ReadOrDefaultValue(0)); + } + } +} + +// This function calls the GainControl functions that are overriden as private +// in GainControlInterface. +void FuzzGainControllerConfig(test::FuzzDataHelper* fuzz_data, + GainControl* gc) { + GainControl::Mode modes[] = {GainControl::Mode::kAdaptiveAnalog, + GainControl::Mode::kAdaptiveDigital, + GainControl::Mode::kFixedDigital}; + GainControl::Mode mode = fuzz_data->SelectOneOf(modes); + const bool enable_limiter = fuzz_data->ReadOrDefaultValue(true); + // The values are capped to comply with the API of webrtc::GainControl. + const int analog_level_min = + rtc::SafeClamp(fuzz_data->ReadOrDefaultValue(0), 0, 65534); + const int analog_level_max = + rtc::SafeClamp(fuzz_data->ReadOrDefaultValue(65535), + analog_level_min + 1, 65535); + const int stream_analog_level = + rtc::SafeClamp(fuzz_data->ReadOrDefaultValue(30000), + analog_level_min, analog_level_max); + const int gain = + rtc::SafeClamp(fuzz_data->ReadOrDefaultValue(30), -1, 100); + const int target_level_dbfs = + rtc::SafeClamp(fuzz_data->ReadOrDefaultValue(15), -1, 35); + + gc->set_mode(mode); + gc->enable_limiter(enable_limiter); + if (mode == GainControl::Mode::kAdaptiveAnalog) { + gc->set_analog_level_limits(analog_level_min, analog_level_max); + gc->set_stream_analog_level(stream_analog_level); + } + gc->set_compression_gain_db(gain); + gc->set_target_level_dbfs(target_level_dbfs); + gc->Enable(true); + + static_cast(gc->is_enabled()); + static_cast(gc->mode()); + static_cast(gc->analog_level_minimum()); + static_cast(gc->analog_level_maximum()); + static_cast(gc->stream_analog_level()); + static_cast(gc->compression_gain_db()); + static_cast(gc->stream_is_saturated()); + static_cast(gc->target_level_dbfs()); + static_cast(gc->is_limiter_enabled()); +} + +void FuzzGainController(test::FuzzDataHelper* fuzz_data, GainControlImpl* gci) { + using Rate = ::webrtc::AudioProcessing::NativeRate; + const Rate rate_kinds[] = {Rate::kSampleRate8kHz, Rate::kSampleRate16kHz, + Rate::kSampleRate32kHz, Rate::kSampleRate48kHz}; + + const auto sample_rate_hz = + static_cast(fuzz_data->SelectOneOf(rate_kinds)); + const size_t samples_per_frame = sample_rate_hz / 100; + const bool num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1; + + gci->Initialize(num_channels, sample_rate_hz); + FuzzGainControllerConfig(fuzz_data, gci); + + // The audio buffer is used for both capture and render. + AudioBuffer audio(samples_per_frame, num_channels, samples_per_frame, + num_channels, samples_per_frame); + + std::vector packed_render_audio(samples_per_frame); + + while (fuzz_data->CanReadBytes(1)) { + FillAudioBuffer(fuzz_data, &audio); + + const bool stream_has_echo = fuzz_data->ReadOrDefaultValue(true); + gci->AnalyzeCaptureAudio(&audio); + gci->ProcessCaptureAudio(&audio, stream_has_echo); + + FillAudioBuffer(fuzz_data, &audio); + + gci->PackRenderAudioBuffer(&audio, &packed_render_audio); + gci->ProcessRenderAudio(packed_render_audio); + } +} + +} // namespace + +void FuzzOneInput(const uint8_t* data, size_t size) { + test::FuzzDataHelper fuzz_data(rtc::ArrayView(data, size)); + rtc::CriticalSection crit_capture; + rtc::CriticalSection crit_render; + auto gci = rtc::MakeUnique(&crit_render, &crit_capture); + FuzzGainController(&fuzz_data, gci.get()); +} +} // namespace webrtc diff --git a/test/fuzzers/corpora/agc-corpus/agc-1 b/test/fuzzers/corpora/agc-corpus/agc-1 new file mode 100644 index 0000000000..cda107c534 Binary files /dev/null and b/test/fuzzers/corpora/agc-corpus/agc-1 differ diff --git a/test/fuzzers/corpora/agc-corpus/agc-2 b/test/fuzzers/corpora/agc-corpus/agc-2 new file mode 100644 index 0000000000..bf1a98dccd Binary files /dev/null and b/test/fuzzers/corpora/agc-corpus/agc-2 differ diff --git a/test/fuzzers/corpora/agc-corpus/agc-3 b/test/fuzzers/corpora/agc-corpus/agc-3 new file mode 100644 index 0000000000..f28283502a Binary files /dev/null and b/test/fuzzers/corpora/agc-corpus/agc-3 differ diff --git a/test/fuzzers/corpora/agc-corpus/agc-4 b/test/fuzzers/corpora/agc-corpus/agc-4 new file mode 100644 index 0000000000..7b5d1cd790 Binary files /dev/null and b/test/fuzzers/corpora/agc-corpus/agc-4 differ