blob: 5252918d77ea78f02a0142d6d59a1ee6f69b7866 [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"
Per Åhgrenfea8b942020-04-07 09:33:1619#include "modules/audio_processing/include/audio_frame_proxies.h"
Alex Loikoab20a602018-01-16 11:50:3420#include "modules/audio_processing/include/audio_processing.h"
Alex Loikoab20a602018-01-16 11:50:3421#include "rtc_base/checks.h"
22
23namespace webrtc {
24namespace {
Alex Loikof5c3ba12018-06-25 13:31:3725bool ValidForApm(float x) {
26 return std::isfinite(x) && -1.0f <= x && x <= 1.0f;
27}
28
Alex Loikoab20a602018-01-16 11:50:3429void GenerateFloatFrame(test::FuzzDataHelper* fuzz_data,
Sam Zackrisson306eee32022-05-31 13:03:2830 int input_rate,
31 int num_channels,
Alex Loikoab20a602018-01-16 11:50:3432 float* const* float_frames) {
Sam Zackrisson3bd444f2022-08-03 12:37:0033 const int samples_per_input_channel =
34 AudioProcessing::GetFrameSize(input_rate);
Alex Loikoab20a602018-01-16 11:50:3435 RTC_DCHECK_LE(samples_per_input_channel, 480);
Sam Zackrisson306eee32022-05-31 13:03:2836 for (int i = 0; i < num_channels; ++i) {
Alex Loikof5c3ba12018-06-25 13:31:3737 std::fill(float_frames[i], float_frames[i] + samples_per_input_channel, 0);
38 const size_t read_bytes = sizeof(float) * samples_per_input_channel;
39 if (fuzz_data->CanReadBytes(read_bytes)) {
40 rtc::ArrayView<const uint8_t> byte_array =
41 fuzz_data->ReadByteArray(read_bytes);
42 memmove(float_frames[i], byte_array.begin(), read_bytes);
43 }
44
45 // Sanitize input.
Sam Zackrisson306eee32022-05-31 13:03:2846 for (int j = 0; j < samples_per_input_channel; ++j) {
Alex Loikof5c3ba12018-06-25 13:31:3747 if (!ValidForApm(float_frames[i][j])) {
48 float_frames[i][j] = 0.f;
49 }
Alex Loikoab20a602018-01-16 11:50:3450 }
51 }
52}
53
54void GenerateFixedFrame(test::FuzzDataHelper* fuzz_data,
Sam Zackrisson306eee32022-05-31 13:03:2855 int input_rate,
56 int num_channels,
Alex Loikoab20a602018-01-16 11:50:3457 AudioFrame* fixed_frame) {
Sam Zackrisson3bd444f2022-08-03 12:37:0058 const int samples_per_input_channel =
59 AudioProcessing::GetFrameSize(input_rate);
60
Alex Loikoab20a602018-01-16 11:50:3461 fixed_frame->samples_per_channel_ = samples_per_input_channel;
62 fixed_frame->sample_rate_hz_ = input_rate;
63 fixed_frame->num_channels_ = num_channels;
64
65 RTC_DCHECK_LE(samples_per_input_channel * num_channels,
66 AudioFrame::kMaxDataSizeSamples);
Sam Zackrisson306eee32022-05-31 13:03:2867 for (int i = 0; i < samples_per_input_channel * num_channels; ++i) {
Alex Loiko38c15d32018-03-02 12:53:0968 fixed_frame->mutable_data()[i] = fuzz_data->ReadOrDefaultValue<int16_t>(0);
Alex Loikoab20a602018-01-16 11:50:3469 }
70}
71} // namespace
72
73void FuzzAudioProcessing(test::FuzzDataHelper* fuzz_data,
Niels Möller4f776ac2021-07-02 09:30:5474 rtc::scoped_refptr<AudioProcessing> apm) {
Alex Loikoab20a602018-01-16 11:50:3475 AudioFrame fixed_frame;
Sam Zackrisson31b01c02019-11-25 07:48:2676 // Normal usage is up to 8 channels. Allowing to fuzz one beyond this allows
77 // us to catch implicit assumptions about normal usage.
78 constexpr int kMaxNumChannels = 9;
79 std::array<std::array<float, 480>, kMaxNumChannels> float_frames;
80 std::array<float*, kMaxNumChannels> float_frame_ptrs;
81 for (int i = 0; i < kMaxNumChannels; ++i) {
82 float_frame_ptrs[i] = float_frames[i].data();
83 }
Alex Loikoab20a602018-01-16 11:50:3484 float* const* ptr_to_float_frames = &float_frame_ptrs[0];
85
Sam Zackrisson306eee32022-05-31 13:03:2886 constexpr int kSampleRatesHz[] = {8000, 11025, 16000, 22050,
87 32000, 44100, 48000};
Alex Loikoab20a602018-01-16 11:50:3488
89 // We may run out of fuzz data in the middle of a loop iteration. In
90 // that case, default values will be used for the rest of that
91 // iteration.
92 while (fuzz_data->CanReadBytes(1)) {
93 const bool is_float = fuzz_data->ReadOrDefaultValue(true);
94 // Decide input/output rate for this iteration.
Sam Zackrisson306eee32022-05-31 13:03:2895 const int input_rate = fuzz_data->SelectOneOf(kSampleRatesHz);
96 const int output_rate = fuzz_data->SelectOneOf(kSampleRatesHz);
Alex Loikoab20a602018-01-16 11:50:3497
Alex Loiko38c15d32018-03-02 12:53:0998 const uint8_t stream_delay = fuzz_data->ReadOrDefaultValue<uint8_t>(0);
Sam Zackrisson306eee32022-05-31 13:03:2899 // API call needed for AECM to run.
Alex Loikoab20a602018-01-16 11:50:34100 apm->set_stream_delay_ms(stream_delay);
101
Sam Zackrisson1f5de532018-07-04 09:40:15102 const bool key_pressed = fuzz_data->ReadOrDefaultValue(true);
103 apm->set_stream_key_pressed(key_pressed);
104
Alex Loikoab20a602018-01-16 11:50:34105 // Make the APM call depending on capture/render mode and float /
106 // fix interface.
107 const bool is_capture = fuzz_data->ReadOrDefaultValue(true);
108
109 // Fill the arrays with audio samples from the data.
110 int apm_return_code = AudioProcessing::Error::kNoError;
111 if (is_float) {
Sam Zackrisson31b01c02019-11-25 07:48:26112 const int num_channels =
113 fuzz_data->ReadOrDefaultValue<uint8_t>(1) % kMaxNumChannels;
114
Alex Loikoab20a602018-01-16 11:50:34115 GenerateFloatFrame(fuzz_data, input_rate, num_channels,
116 ptr_to_float_frames);
117 if (is_capture) {
118 apm_return_code = apm->ProcessStream(
119 ptr_to_float_frames, StreamConfig(input_rate, num_channels),
120 StreamConfig(output_rate, num_channels), ptr_to_float_frames);
121 } else {
122 apm_return_code = apm->ProcessReverseStream(
Sam Zackrisson2b4bd972019-11-26 17:52:00123 ptr_to_float_frames, StreamConfig(input_rate, num_channels),
124 StreamConfig(output_rate, num_channels), ptr_to_float_frames);
Alex Loikoab20a602018-01-16 11:50:34125 }
126 } else {
Sam Zackrisson31b01c02019-11-25 07:48:26127 const int num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1;
Alex Loikoab20a602018-01-16 11:50:34128 GenerateFixedFrame(fuzz_data, input_rate, num_channels, &fixed_frame);
129
130 if (is_capture) {
Per Åhgrenfea8b942020-04-07 09:33:16131 apm_return_code = ProcessAudioFrame(apm.get(), &fixed_frame);
Alex Loikoab20a602018-01-16 11:50:34132 } else {
Per Åhgrenfea8b942020-04-07 09:33:16133 apm_return_code = ProcessReverseAudioFrame(apm.get(), &fixed_frame);
Alex Loikoab20a602018-01-16 11:50:34134 }
135 }
136
Sam Zackrisson28127632018-11-01 10:37:15137 // Cover stats gathering code paths.
138 static_cast<void>(apm->GetStatistics(true /*has_remote_tracks*/));
Alex Loiko9df3cf32018-04-10 10:18:02139
Alex Loikoab20a602018-01-16 11:50:34140 RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
141 }
142}
143} // namespace webrtc