| /* |
| * 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 "absl/memory/memory.h" |
| #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/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<float>(fuzz_data->ReadOrDefaultValue<int16_t>(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<int>(fuzz_data->ReadOrDefaultValue<uint16_t>(0), 0, 65534); |
| const int analog_level_max = |
| rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<uint16_t>(65535), |
| analog_level_min + 1, 65535); |
| const int stream_analog_level = |
| rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<uint16_t>(30000), |
| analog_level_min, analog_level_max); |
| const int gain = |
| rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(30), -1, 100); |
| const int target_level_dbfs = |
| rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(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<void>(gc->is_enabled()); |
| static_cast<void>(gc->mode()); |
| static_cast<void>(gc->analog_level_minimum()); |
| static_cast<void>(gc->analog_level_maximum()); |
| static_cast<void>(gc->stream_analog_level()); |
| static_cast<void>(gc->compression_gain_db()); |
| static_cast<void>(gc->stream_is_saturated()); |
| static_cast<void>(gc->target_level_dbfs()); |
| static_cast<void>(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<size_t>(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<int16_t> 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) { |
| if (size > 200000) { |
| return; |
| } |
| test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size)); |
| rtc::CriticalSection crit_capture; |
| rtc::CriticalSection crit_render; |
| auto gci = absl::make_unique<GainControlImpl>(&crit_render, &crit_capture); |
| FuzzGainController(&fuzz_data, gci.get()); |
| } |
| } // namespace webrtc |