blob: eb2e0e89608dd9ec16343193b0d81f1d65a25318 [file] [log] [blame]
Alex Loikoab20a602018-01-16 11:50:341/*
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 20:44:0918#include "api/audio/audio_frame.h"
Alex Loikoab20a602018-01-16 11:50:3419#include "modules/audio_processing/include/audio_processing.h"
Alex Loikoab20a602018-01-16 11:50:3420#include "rtc_base/checks.h"
21
22namespace webrtc {
23namespace {
Alex Loikof5c3ba12018-06-25 13:31:3724bool ValidForApm(float x) {
25 return std::isfinite(x) && -1.0f <= x && x <= 1.0f;
26}
27
Alex Loikoab20a602018-01-16 11:50:3428void 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 17:38:1333 rtc::CheckedDivExact(input_rate, static_cast<size_t>(100));
Alex Loikoab20a602018-01-16 11:50:3434 RTC_DCHECK_LE(samples_per_input_channel, 480);
35 for (size_t i = 0; i < num_channels; ++i) {
Alex Loikof5c3ba12018-06-25 13:31:3736 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 11:50:3445 for (size_t j = 0; j < samples_per_input_channel; ++j) {
Alex Loikof5c3ba12018-06-25 13:31:3746 if (!ValidForApm(float_frames[i][j])) {
47 float_frames[i][j] = 0.f;
48 }
Alex Loikoab20a602018-01-16 11:50:3449 }
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 17:38:1358 rtc::CheckedDivExact(input_rate, static_cast<size_t>(100));
Alex Loikoab20a602018-01-16 11:50:3459 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 12:53:0966 fixed_frame->mutable_data()[i] = fuzz_data->ReadOrDefaultValue<int16_t>(0);
Alex Loikoab20a602018-01-16 11:50:3467 }
68}
69} // namespace
70
71void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
72 std::unique_ptr<AudioProcessing> apm) {
73 AudioFrame fixed_frame;
Sam Zackrisson31b01c02019-11-25 07:48:2674 // Normal usage is up to 8 channels. Allowing to fuzz one beyond this allows
75 // us to catch implicit assumptions about normal usage.
76 constexpr int kMaxNumChannels = 9;
77 std::array<std::array<float, 480>, kMaxNumChannels> float_frames;
78 std::array<float*, kMaxNumChannels> float_frame_ptrs;
79 for (int i = 0; i < kMaxNumChannels; ++i) {
80 float_frame_ptrs[i] = float_frames[i].data();
81 }
Alex Loikoab20a602018-01-16 11:50:3482 float* const* ptr_to_float_frames = &float_frame_ptrs[0];
83
84 using Rate = AudioProcessing::NativeRate;
85 const Rate rate_kinds[] = {Rate::kSampleRate8kHz, Rate::kSampleRate16kHz,
86 Rate::kSampleRate32kHz, Rate::kSampleRate48kHz};
87
88 // We may run out of fuzz data in the middle of a loop iteration. In
89 // that case, default values will be used for the rest of that
90 // iteration.
91 while (fuzz_data->CanReadBytes(1)) {
92 const bool is_float = fuzz_data->ReadOrDefaultValue(true);
93 // Decide input/output rate for this iteration.
94 const auto input_rate =
95 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
96 const auto output_rate =
97 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
98
Alex Loiko38c15d32018-03-02 12:53:0999 const uint8_t stream_delay = fuzz_data->ReadOrDefaultValue<uint8_t>(0);
Alex Loikoab20a602018-01-16 11:50:34100
101 // API call needed for AEC-2 and AEC-m to run.
102 apm->set_stream_delay_ms(stream_delay);
103
Sam Zackrisson1f5de532018-07-04 09:40:15104 const bool key_pressed = fuzz_data->ReadOrDefaultValue(true);
105 apm->set_stream_key_pressed(key_pressed);
106
Alex Loikoab20a602018-01-16 11:50:34107 // Make the APM call depending on capture/render mode and float /
108 // fix interface.
109 const bool is_capture = fuzz_data->ReadOrDefaultValue(true);
110
111 // Fill the arrays with audio samples from the data.
112 int apm_return_code = AudioProcessing::Error::kNoError;
113 if (is_float) {
Sam Zackrisson31b01c02019-11-25 07:48:26114 const int num_channels =
115 fuzz_data->ReadOrDefaultValue<uint8_t>(1) % kMaxNumChannels;
116
Alex Loikoab20a602018-01-16 11:50:34117 GenerateFloatFrame(fuzz_data, input_rate, num_channels,
118 ptr_to_float_frames);
119 if (is_capture) {
120 apm_return_code = apm->ProcessStream(
121 ptr_to_float_frames, StreamConfig(input_rate, num_channels),
122 StreamConfig(output_rate, num_channels), ptr_to_float_frames);
123 } else {
124 apm_return_code = apm->ProcessReverseStream(
125 ptr_to_float_frames, StreamConfig(input_rate, 1),
126 StreamConfig(output_rate, 1), ptr_to_float_frames);
127 }
128 } else {
Sam Zackrisson31b01c02019-11-25 07:48:26129 const int num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1;
Alex Loikoab20a602018-01-16 11:50:34130 GenerateFixedFrame(fuzz_data, input_rate, num_channels, &fixed_frame);
131
132 if (is_capture) {
133 apm_return_code = apm->ProcessStream(&fixed_frame);
134 } else {
135 apm_return_code = apm->ProcessReverseStream(&fixed_frame);
136 }
137 }
138
Sam Zackrisson28127632018-11-01 10:37:15139 // Cover stats gathering code paths.
140 static_cast<void>(apm->GetStatistics(true /*has_remote_tracks*/));
Alex Loiko9df3cf32018-04-10 10:18:02141
Alex Loikoab20a602018-01-16 11:50:34142 RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
143 }
144}
145} // namespace webrtc