blob: 5d7ea4c80760d9667146ac75227ad53852eeb3e1 [file] [log] [blame]
Alex Loikoab20a602018-01-16 12:50:34 +01001/*
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 "test/fuzzers/audio_processing_fuzzer_helper.h"
12
13#include <algorithm>
14#include <array>
15#include <cmath>
16#include <limits>
17
Fredrik Solenbergbbf21a32018-04-12 22:44:09 +020018#include "api/audio/audio_frame.h"
Alex Loikoab20a602018-01-16 12:50:34 +010019#include "modules/audio_processing/include/audio_processing.h"
Alex Loikoab20a602018-01-16 12:50:34 +010020#include "rtc_base/checks.h"
21
22namespace webrtc {
23namespace {
Alex Loikof5c3ba12018-06-25 15:31:37 +020024bool ValidForApm(float x) {
25 return std::isfinite(x) && -1.0f <= x && x <= 1.0f;
26}
27
Alex Loikoab20a602018-01-16 12:50:34 +010028void GenerateFloatFrame(test::FuzzDataHelper* fuzz_data,
29 size_t input_rate,
30 size_t num_channels,
31 float* const* float_frames) {
32 const size_t samples_per_input_channel =
Jonathan Metzman9f80b972018-10-05 10:38:13 -070033 rtc::CheckedDivExact(input_rate, static_cast<size_t>(100));
Alex Loikoab20a602018-01-16 12:50:34 +010034 RTC_DCHECK_LE(samples_per_input_channel, 480);
35 for (size_t i = 0; i < num_channels; ++i) {
Alex Loikof5c3ba12018-06-25 15:31:37 +020036 std::fill(float_frames[i], float_frames[i] + samples_per_input_channel, 0);
37 const size_t read_bytes = sizeof(float) * samples_per_input_channel;
38 if (fuzz_data->CanReadBytes(read_bytes)) {
39 rtc::ArrayView<const uint8_t> byte_array =
40 fuzz_data->ReadByteArray(read_bytes);
41 memmove(float_frames[i], byte_array.begin(), read_bytes);
42 }
43
44 // Sanitize input.
Alex Loikoab20a602018-01-16 12:50:34 +010045 for (size_t j = 0; j < samples_per_input_channel; ++j) {
Alex Loikof5c3ba12018-06-25 15:31:37 +020046 if (!ValidForApm(float_frames[i][j])) {
47 float_frames[i][j] = 0.f;
48 }
Alex Loikoab20a602018-01-16 12:50:34 +010049 }
50 }
51}
52
53void GenerateFixedFrame(test::FuzzDataHelper* fuzz_data,
54 size_t input_rate,
55 size_t num_channels,
56 AudioFrame* fixed_frame) {
57 const size_t samples_per_input_channel =
Jonathan Metzman9f80b972018-10-05 10:38:13 -070058 rtc::CheckedDivExact(input_rate, static_cast<size_t>(100));
Alex Loikoab20a602018-01-16 12:50:34 +010059 fixed_frame->samples_per_channel_ = samples_per_input_channel;
60 fixed_frame->sample_rate_hz_ = input_rate;
61 fixed_frame->num_channels_ = num_channels;
62
63 RTC_DCHECK_LE(samples_per_input_channel * num_channels,
64 AudioFrame::kMaxDataSizeSamples);
65 for (size_t i = 0; i < samples_per_input_channel * num_channels; ++i) {
Alex Loiko38c15d32018-03-02 13:53:09 +010066 fixed_frame->mutable_data()[i] = fuzz_data->ReadOrDefaultValue<int16_t>(0);
Alex Loikoab20a602018-01-16 12:50:34 +010067 }
68}
69} // namespace
70
71void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
72 std::unique_ptr<AudioProcessing> apm) {
73 AudioFrame fixed_frame;
74 std::array<float, 480> float_frame1;
75 std::array<float, 480> float_frame2;
76 std::array<float* const, 2> float_frame_ptrs = {
Jonas Olssona4d87372019-07-05 19:08:33 +020077 &float_frame1[0],
78 &float_frame2[0],
Alex Loikoab20a602018-01-16 12:50:34 +010079 };
80 float* const* ptr_to_float_frames = &float_frame_ptrs[0];
81
82 using Rate = AudioProcessing::NativeRate;
83 const Rate rate_kinds[] = {Rate::kSampleRate8kHz, Rate::kSampleRate16kHz,
84 Rate::kSampleRate32kHz, Rate::kSampleRate48kHz};
85
86 // We may run out of fuzz data in the middle of a loop iteration. In
87 // that case, default values will be used for the rest of that
88 // iteration.
89 while (fuzz_data->CanReadBytes(1)) {
90 const bool is_float = fuzz_data->ReadOrDefaultValue(true);
91 // Decide input/output rate for this iteration.
92 const auto input_rate =
93 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
94 const auto output_rate =
95 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
96
Alex Loikoc480e9d2018-07-05 11:14:28 +020097 const int num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1;
Alex Loiko38c15d32018-03-02 13:53:09 +010098 const uint8_t stream_delay = fuzz_data->ReadOrDefaultValue<uint8_t>(0);
Alex Loikoab20a602018-01-16 12:50:34 +010099
100 // API call needed for AEC-2 and AEC-m to run.
101 apm->set_stream_delay_ms(stream_delay);
102
Sam Zackrisson1f5de532018-07-04 11:40:15 +0200103 const bool key_pressed = fuzz_data->ReadOrDefaultValue(true);
104 apm->set_stream_key_pressed(key_pressed);
105
Alex Loikoab20a602018-01-16 12:50:34 +0100106 // Make the APM call depending on capture/render mode and float /
107 // fix interface.
108 const bool is_capture = fuzz_data->ReadOrDefaultValue(true);
109
110 // Fill the arrays with audio samples from the data.
111 int apm_return_code = AudioProcessing::Error::kNoError;
112 if (is_float) {
113 GenerateFloatFrame(fuzz_data, input_rate, num_channels,
114 ptr_to_float_frames);
115 if (is_capture) {
116 apm_return_code = apm->ProcessStream(
117 ptr_to_float_frames, StreamConfig(input_rate, num_channels),
118 StreamConfig(output_rate, num_channels), ptr_to_float_frames);
119 } else {
120 apm_return_code = apm->ProcessReverseStream(
121 ptr_to_float_frames, StreamConfig(input_rate, 1),
122 StreamConfig(output_rate, 1), ptr_to_float_frames);
123 }
124 } else {
125 GenerateFixedFrame(fuzz_data, input_rate, num_channels, &fixed_frame);
126
127 if (is_capture) {
128 apm_return_code = apm->ProcessStream(&fixed_frame);
129 } else {
130 apm_return_code = apm->ProcessReverseStream(&fixed_frame);
131 }
132 }
133
Sam Zackrisson28127632018-11-01 11:37:15 +0100134 // Cover stats gathering code paths.
135 static_cast<void>(apm->GetStatistics(true /*has_remote_tracks*/));
Alex Loiko9df3cf32018-04-10 12:18:02 +0200136
Alex Loikoab20a602018-01-16 12:50:34 +0100137 RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
138 }
139}
140} // namespace webrtc