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
11 #include <memory>
12
13 #include "modules/audio_processing/audio_buffer.h"
14 #include "modules/audio_processing/gain_control_impl.h"
15 #include "modules/audio_processing/include/audio_processing.h"
16 #include "rtc_base/numerics/safe_minmax.h"
17 #include "rtc_base/thread_annotations.h"
18 #include "test/fuzzers/fuzz_data_helper.h"
19
20 namespace webrtc {
21 namespace {
22
FillAudioBuffer(size_t sample_rate_hz,test::FuzzDataHelper * fuzz_data,AudioBuffer * buffer)23 void FillAudioBuffer(size_t sample_rate_hz,
24 test::FuzzDataHelper* fuzz_data,
25 AudioBuffer* buffer) {
26 float* const* channels = buffer->channels_f();
27 for (size_t i = 0; i < buffer->num_channels(); ++i) {
28 for (size_t j = 0; j < buffer->num_frames(); ++j) {
29 channels[i][j] =
30 static_cast<float>(fuzz_data->ReadOrDefaultValue<int16_t>(0));
31 }
32 }
33
34 if (sample_rate_hz != 16000) {
35 buffer->SplitIntoFrequencyBands();
36 }
37 }
38
39 // This function calls the GainControl functions that are overriden as private
40 // in GainControlInterface.
FuzzGainControllerConfig(test::FuzzDataHelper * fuzz_data,GainControl * gc)41 void FuzzGainControllerConfig(test::FuzzDataHelper* fuzz_data,
42 GainControl* gc) {
43 GainControl::Mode modes[] = {GainControl::Mode::kAdaptiveAnalog,
44 GainControl::Mode::kAdaptiveDigital,
45 GainControl::Mode::kFixedDigital};
46 GainControl::Mode mode = fuzz_data->SelectOneOf(modes);
47 const bool enable_limiter = fuzz_data->ReadOrDefaultValue(true);
48 // The values are capped to comply with the API of webrtc::GainControl.
49 const int analog_level_min =
50 rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<uint16_t>(0), 0, 65534);
51 const int analog_level_max =
52 rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<uint16_t>(65535),
53 analog_level_min + 1, 65535);
54 const int stream_analog_level =
55 rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<uint16_t>(30000),
56 analog_level_min, analog_level_max);
57 const int gain =
58 rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(30), -1, 100);
59 const int target_level_dbfs =
60 rtc::SafeClamp<int>(fuzz_data->ReadOrDefaultValue<int8_t>(15), -1, 35);
61
62 gc->set_mode(mode);
63 gc->enable_limiter(enable_limiter);
64 if (mode == GainControl::Mode::kAdaptiveAnalog) {
65 gc->set_analog_level_limits(analog_level_min, analog_level_max);
66 gc->set_stream_analog_level(stream_analog_level);
67 }
68 gc->set_compression_gain_db(gain);
69 gc->set_target_level_dbfs(target_level_dbfs);
70
71 static_cast<void>(gc->mode());
72 static_cast<void>(gc->analog_level_minimum());
73 static_cast<void>(gc->analog_level_maximum());
74 static_cast<void>(gc->stream_analog_level());
75 static_cast<void>(gc->compression_gain_db());
76 static_cast<void>(gc->stream_is_saturated());
77 static_cast<void>(gc->target_level_dbfs());
78 static_cast<void>(gc->is_limiter_enabled());
79 }
80
FuzzGainController(test::FuzzDataHelper * fuzz_data,GainControlImpl * gci)81 void FuzzGainController(test::FuzzDataHelper* fuzz_data, GainControlImpl* gci) {
82 using Rate = ::webrtc::AudioProcessing::NativeRate;
83 const Rate rate_kinds[] = {Rate::kSampleRate16kHz, Rate::kSampleRate32kHz,
84 Rate::kSampleRate48kHz};
85
86 const auto sample_rate_hz =
87 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
88 const size_t samples_per_frame = sample_rate_hz / 100;
89 const size_t num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1;
90
91 gci->Initialize(num_channels, sample_rate_hz);
92 FuzzGainControllerConfig(fuzz_data, gci);
93
94 // The audio buffer is used for both capture and render.
95 AudioBuffer audio(sample_rate_hz, num_channels, sample_rate_hz,
96 num_channels, sample_rate_hz, num_channels);
97
98 std::vector<int16_t> packed_render_audio(samples_per_frame);
99
100 while (fuzz_data->CanReadBytes(1)) {
101 FillAudioBuffer(sample_rate_hz, fuzz_data, &audio);
102
103 const bool stream_has_echo = fuzz_data->ReadOrDefaultValue(true);
104 gci->AnalyzeCaptureAudio(audio);
105 gci->ProcessCaptureAudio(&audio, stream_has_echo);
106
107 FillAudioBuffer(sample_rate_hz, fuzz_data, &audio);
108
109 gci->PackRenderAudioBuffer(audio, &packed_render_audio);
110 gci->ProcessRenderAudio(packed_render_audio);
111 }
112 }
113
114 } // namespace
115
FuzzOneInput(const uint8_t * data,size_t size)116 void FuzzOneInput(const uint8_t* data, size_t size) {
117 if (size > 200000) {
118 return;
119 }
120 test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size));
121 auto gci = std::make_unique<GainControlImpl>();
122 FuzzGainController(&fuzz_data, gci.get());
123 }
124 } // namespace webrtc
125