blob: 073ab17bd931c4bbec133d0e90ad5c1b3cbaf4c3 [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 = {
77 &float_frame1[0], &float_frame2[0],
78 };
79 float* const* ptr_to_float_frames = &float_frame_ptrs[0];
80
81 using Rate = AudioProcessing::NativeRate;
82 const Rate rate_kinds[] = {Rate::kSampleRate8kHz, Rate::kSampleRate16kHz,
83 Rate::kSampleRate32kHz, Rate::kSampleRate48kHz};
84
85 // We may run out of fuzz data in the middle of a loop iteration. In
86 // that case, default values will be used for the rest of that
87 // iteration.
88 while (fuzz_data->CanReadBytes(1)) {
89 const bool is_float = fuzz_data->ReadOrDefaultValue(true);
90 // Decide input/output rate for this iteration.
91 const auto input_rate =
92 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
93 const auto output_rate =
94 static_cast<size_t>(fuzz_data->SelectOneOf(rate_kinds));
95
Alex Loikoc480e9d2018-07-05 11:14:28 +020096 const int num_channels = fuzz_data->ReadOrDefaultValue(true) ? 2 : 1;
Alex Loiko38c15d32018-03-02 13:53:09 +010097 const uint8_t stream_delay = fuzz_data->ReadOrDefaultValue<uint8_t>(0);
Alex Loikoab20a602018-01-16 12:50:34 +010098
99 // API call needed for AEC-2 and AEC-m to run.
100 apm->set_stream_delay_ms(stream_delay);
101
Sam Zackrisson1f5de532018-07-04 11:40:15 +0200102 const bool key_pressed = fuzz_data->ReadOrDefaultValue(true);
103 apm->set_stream_key_pressed(key_pressed);
104
Alex Loikoab20a602018-01-16 12:50:34 +0100105 // 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) {
112 GenerateFloatFrame(fuzz_data, input_rate, num_channels,
113 ptr_to_float_frames);
114 if (is_capture) {
115 apm_return_code = apm->ProcessStream(
116 ptr_to_float_frames, StreamConfig(input_rate, num_channels),
117 StreamConfig(output_rate, num_channels), ptr_to_float_frames);
118 } else {
119 apm_return_code = apm->ProcessReverseStream(
120 ptr_to_float_frames, StreamConfig(input_rate, 1),
121 StreamConfig(output_rate, 1), ptr_to_float_frames);
122 }
123 } else {
124 GenerateFixedFrame(fuzz_data, input_rate, num_channels, &fixed_frame);
125
126 if (is_capture) {
127 apm_return_code = apm->ProcessStream(&fixed_frame);
128 } else {
129 apm_return_code = apm->ProcessReverseStream(&fixed_frame);
130 }
131 }
132
Alex Loiko9df3cf32018-04-10 12:18:02 +0200133 // Make calls to stats gathering functions to cover these
134 // codeways.
135 static_cast<void>(apm->GetStatistics());
136 static_cast<void>(apm->GetStatistics(true));
Alex Loikoc480e9d2018-07-05 11:14:28 +0200137 static_cast<void>(apm->UpdateHistogramsOnCallEnd());
Alex Loiko9df3cf32018-04-10 12:18:02 +0200138
Alex Loikoab20a602018-01-16 12:50:34 +0100139 RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError);
140 }
141}
142} // namespace webrtc