Index: webrtc/test/fuzzers/audio_processing_fuzzer.cc |
diff --git a/webrtc/test/fuzzers/audio_processing_fuzzer.cc b/webrtc/test/fuzzers/audio_processing_fuzzer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d5a3bea0a1f56ddaf45daf233fc801aa9ac9628f |
--- /dev/null |
+++ b/webrtc/test/fuzzers/audio_processing_fuzzer.cc |
@@ -0,0 +1,157 @@ |
+/* |
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/test/fuzzers/audio_processing_fuzzer.h" |
+ |
+#include <algorithm> |
+#include <array> |
+#include <cmath> |
+ |
+#include "webrtc/base/checks.h" |
+#include "webrtc/modules/audio_processing/include/audio_processing.h" |
+#include "webrtc/modules/include/module_common_types.h" |
+ |
+namespace webrtc { |
+namespace { |
+size_t ByteToNativeRate(uint8_t data) { |
+ using Rate = AudioProcessing::NativeRate; |
+ switch (data % 4) { |
+ case 0: |
+ // Breaks AEC3. |
+ // return static_cast<size_t>(Rate::kSampleRate8kHz); |
+ case 1: |
+ return static_cast<size_t>(Rate::kSampleRate16kHz); |
+ case 2: |
+ return static_cast<size_t>(Rate::kSampleRate32kHz); |
+ default: |
+ return static_cast<size_t>(Rate::kSampleRate48kHz); |
+ } |
+} |
+ |
+template <class T> |
+bool ParseSequence(size_t size, |
+ const uint8_t** data, |
+ size_t* remaining_size, |
+ T* result_data) { |
+ const size_t data_size_bytes = sizeof(T) * size; |
+ if (data_size_bytes > *remaining_size) { |
+ return false; |
+ } |
+ |
+ std::copy(*data, *data + data_size_bytes, |
+ reinterpret_cast<uint8_t*>(result_data)); |
+ |
+ *data += data_size_bytes; |
+ *remaining_size -= data_size_bytes; |
+ return true; |
+} |
+ |
+void FuzzAudioProcessing(const uint8_t* data, |
+ size_t size, |
+ bool is_float, |
+ AudioProcessing* apm) { |
+ AudioFrame fixed_frame; |
+ std::array<float, 480> float_frame; |
+ float* const first_channel = &float_frame[0]; |
+ |
+ while (size > 0) { |
+ // Decide input/output rate for this iteration. |
+ const auto input_rate_byte = ParseByte(&data, &size); |
+ const auto output_rate_byte = ParseByte(&data, &size); |
+ if (!input_rate_byte || !output_rate_byte) { |
+ return; |
+ } |
+ const auto input_rate_hz = ByteToNativeRate(*input_rate_byte); |
+ const auto output_rate_hz = ByteToNativeRate(*output_rate_byte); |
+ |
+ const size_t samples_per_input_channel = |
+ rtc::CheckedDivExact(input_rate_hz, 100ul); |
+ fixed_frame.samples_per_channel_ = samples_per_input_channel; |
+ fixed_frame.sample_rate_hz_ = input_rate_hz; |
+ |
+ // Two channels breaks AEC3. |
+ fixed_frame.num_channels_ = 1; |
+ |
+ // Fill the arrays with audio samples from the data. |
+ if (is_float) { |
+ if (!ParseSequence(samples_per_input_channel, &data, &size, |
+ &float_frame[0])) { |
+ return; |
+ } |
+ } else if (!ParseSequence(samples_per_input_channel, &data, &size, |
+ fixed_frame.mutable_data())) { |
+ return; |
+ } |
+ |
+ // Filter obviously wrong values like inf/nan and values that will |
+ // lead to inf/nan in calculations. 1e6 leads to DCHECKS failing. |
+ for (auto& x : float_frame) { |
+ if (!std::isnormal(x) || std::abs(x) > 1e5) { |
+ x = 0; |
+ } |
+ } |
+ |
+ // Make the APM call depending on capture/render mode and float / |
+ // fix interface. |
+ const auto is_capture = ParseBool(&data, &size); |
+ if (!is_capture) { |
+ return; |
+ } |
+ if (*is_capture) { |
+ auto apm_return_code = |
+ is_float ? (apm->ProcessStream( |
+ &first_channel, StreamConfig(input_rate_hz, 1), |
+ StreamConfig(output_rate_hz, 1), &first_channel)) |
+ : (apm->ProcessStream(&fixed_frame)); |
+ RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError); |
+ } else { |
+ auto apm_return_code = |
+ is_float ? (apm->ProcessReverseStream( |
+ &first_channel, StreamConfig(input_rate_hz, 1), |
+ StreamConfig(output_rate_hz, 1), &first_channel)) |
+ : (apm->ProcessReverseStream(&fixed_frame)); |
+ RTC_DCHECK_NE(apm_return_code, AudioProcessing::kBadDataLengthError); |
+ } |
+ } |
+} |
+ |
+} // namespace |
+ |
+rtc::Optional<bool> ParseBool(const uint8_t** data, size_t* remaining_size) { |
+ if (1 > *remaining_size) { |
+ return rtc::Optional<bool>(); |
+ } |
+ auto res = rtc::Optional<bool>((**data) % 2); |
+ *data += 1; |
+ *remaining_size -= 1; |
+ return res; |
+} |
+ |
+rtc::Optional<uint8_t> ParseByte(const uint8_t** data, size_t* remaining_size) { |
+ if (1 > *remaining_size) { |
+ return rtc::Optional<uint8_t>(); |
+ } |
+ auto res = rtc::Optional<uint8_t>((**data)); |
+ *data += 1; |
+ *remaining_size -= 1; |
+ return res; |
+} |
+ |
+void FuzzAudioProcessing(const uint8_t* data, |
+ size_t size, |
+ std::unique_ptr<AudioProcessing> apm) { |
+ const auto is_float = ParseBool(&data, &size); |
+ if (!is_float) { |
+ return; |
+ } |
+ |
+ FuzzAudioProcessing(data, size, *is_float, apm.get()); |
+} |
+} // namespace webrtc |