add libaudioprocessing_resampler_fuzzer
This is based on the code from test-resampler.cpp. I simplify out some
bits and use the data from LibFuzzer as the input audio.
Test: ran fuzzer locally on-device
Change-Id: I1ed732698feccd4a644a1a8eea4e3862a025e11a
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..1df47b7
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -0,0 +1,10 @@
+cc_fuzz {
+ name: "libaudioprocessing_resampler_fuzzer",
+ srcs: [
+ "libaudioprocessing_resampler_fuzzer.cpp",
+ ],
+ defaults: ["libaudioprocessing_test_defaults"],
+ static_libs: [
+ "libsndfile",
+ ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
new file mode 100644
index 0000000..938c610
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/macros.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/sndfile.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Vector.h>
+
+#include <memory>
+
+using namespace android;
+
+const int MAX_FRAMES = 10;
+const int MIN_FREQ = 1e3;
+const int MAX_FREQ = 100e3;
+
+const AudioResampler::src_quality qualities[] = {
+ AudioResampler::DEFAULT_QUALITY,
+ AudioResampler::LOW_QUALITY,
+ AudioResampler::MED_QUALITY,
+ AudioResampler::HIGH_QUALITY,
+ AudioResampler::VERY_HIGH_QUALITY,
+ AudioResampler::DYN_LOW_QUALITY,
+ AudioResampler::DYN_MED_QUALITY,
+ AudioResampler::DYN_HIGH_QUALITY,
+};
+
+class Provider : public AudioBufferProvider {
+ const void* mAddr; // base address
+ const size_t mNumFrames; // total frames
+ const size_t mFrameSize; // size of each frame in bytes
+ size_t mNextFrame; // index of next frame to provide
+ size_t mUnrel; // number of frames not yet released
+ public:
+ Provider(const void* addr, size_t frames, size_t frameSize)
+ : mAddr(addr),
+ mNumFrames(frames),
+ mFrameSize(frameSize),
+ mNextFrame(0),
+ mUnrel(0) {}
+ status_t getNextBuffer(Buffer* buffer) override {
+ if (buffer->frameCount > mNumFrames - mNextFrame) {
+ buffer->frameCount = mNumFrames - mNextFrame;
+ }
+ mUnrel = buffer->frameCount;
+ if (buffer->frameCount > 0) {
+ buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+ return NO_ERROR;
+ } else {
+ buffer->raw = nullptr;
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ virtual void releaseBuffer(Buffer* buffer) {
+ if (buffer->frameCount > mUnrel) {
+ mNextFrame += mUnrel;
+ mUnrel = 0;
+ } else {
+ mNextFrame += buffer->frameCount;
+ mUnrel -= buffer->frameCount;
+ }
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+ }
+ void reset() { mNextFrame = 0; }
+};
+
+audio_format_t chooseFormat(AudioResampler::src_quality quality,
+ uint8_t input_byte) {
+ switch (quality) {
+ case AudioResampler::DYN_LOW_QUALITY:
+ case AudioResampler::DYN_MED_QUALITY:
+ case AudioResampler::DYN_HIGH_QUALITY:
+ if (input_byte % 2) {
+ return AUDIO_FORMAT_PCM_FLOAT;
+ }
+ FALLTHROUGH_INTENDED;
+ default:
+ return AUDIO_FORMAT_PCM_16_BIT;
+ }
+}
+
+int parseValue(const uint8_t* src, int index, void* dst, size_t size) {
+ memcpy(dst, &src[index], size);
+ return size;
+}
+
+bool validFreq(int freq) { return freq > MIN_FREQ && freq < MAX_FREQ; }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ int input_freq = 0;
+ int output_freq = 0;
+ int input_channels = 0;
+
+ float left_volume = 0;
+ float right_volume = 0;
+
+ size_t metadata_size = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+ if (size < metadata_size) {
+ // not enough data to set options
+ return 0;
+ }
+
+ AudioResampler::src_quality quality = qualities[data[0] % 8];
+ audio_format_t format = chooseFormat(quality, data[1]);
+
+ int index = 2;
+
+ index += parseValue(data, index, &input_freq, sizeof(int));
+ index += parseValue(data, index, &output_freq, sizeof(int));
+ index += parseValue(data, index, &input_channels, sizeof(int));
+
+ index += parseValue(data, index, &left_volume, sizeof(float));
+ index += parseValue(data, index, &right_volume, sizeof(float));
+
+ if (!validFreq(input_freq) || !validFreq(output_freq)) {
+ // sampling frequencies must be reasonable
+ return 0;
+ }
+
+ if (input_channels < 1 ||
+ input_channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) {
+ // invalid number of input channels
+ return 0;
+ }
+
+ size_t single_channel_size =
+ format == AUDIO_FORMAT_PCM_FLOAT ? sizeof(float) : sizeof(int16_t);
+ size_t input_frame_size = single_channel_size * input_channels;
+ size_t input_size = size - metadata_size;
+ uint8_t input_data[input_size];
+ memcpy(input_data, &data[metadata_size], input_size);
+
+ size_t input_frames = input_size / input_frame_size;
+ if (input_frames > MAX_FRAMES) {
+ return 0;
+ }
+
+ Provider provider(input_data, input_frames, input_frame_size);
+
+ std::unique_ptr<AudioResampler> resampler(
+ AudioResampler::create(format, input_channels, output_freq, quality));
+
+ resampler->setSampleRate(input_freq);
+ resampler->setVolume(left_volume, right_volume);
+
+ // output is at least stereo samples
+ int output_channels = input_channels > 2 ? input_channels : 2;
+ size_t output_frame_size = output_channels * sizeof(int32_t);
+ size_t output_frames = (input_frames * output_freq) / input_freq;
+ size_t output_size = output_frames * output_frame_size;
+
+ uint8_t output_data[output_size];
+ for (size_t i = 0; i < output_frames; i++) {
+ memset(output_data, 0, output_size);
+ resampler->resample((int*)output_data, i, &provider);
+ }
+
+ return 0;
+}