Merge "Updating typeconverter_tests audio_policy_configuration import"
diff --git a/drm/libmediadrm/protos/Android.bp b/drm/libmediadrm/protos/Android.bp
new file mode 100644
index 0000000..b26cda4
--- /dev/null
+++ b/drm/libmediadrm/protos/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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.
+
+// This is the version of the drm metrics configured for protobuf full on host.
+// It is used by the metrics_dump tool.
+
+cc_library_host_shared {
+ name: "libdrm_metrics_protos_full_host",
+ vendor_available: true,
+
+ include_dirs: ["external/protobuf/src"],
+
+ srcs: [
+ "metrics.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+
+ cflags: [
+ // Suppress unused parameter error. This error occurs
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
index 2dcd00f..051a968 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -15,7 +15,7 @@
namespace clearkey {
std::string MemoryFileSystem::GetFileName(const std::string& path) {
- size_t index = path.find_last_of("/");
+ size_t index = path.find_last_of('/');
if (index != std::string::npos) {
return path.substr(index+1);
} else {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 97145c3..6e0c295 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -625,21 +625,19 @@
Mutexed<Output>::Locked output(mOutput);
if (!output->buffers ||
output->buffers->hasPending() ||
- output->buffers->numClientBuffers() >= output->numSlots) {
+ output->buffers->numActiveSlots() >= output->numSlots) {
return;
}
}
- size_t numInputSlots = mInput.lock()->numSlots;
- for (size_t i = 0; i < numInputSlots; ++i) {
- if (mPipelineWatcher.lock()->pipelineFull()) {
- return;
- }
+ size_t numActiveSlots = 0;
+ while (!mPipelineWatcher.lock()->pipelineFull()) {
sp<MediaCodecBuffer> inBuffer;
size_t index;
{
Mutexed<Input>::Locked input(mInput);
- if (input->buffers->numClientBuffers() >= input->numSlots) {
- return;
+ numActiveSlots = input->buffers->numActiveSlots();
+ if (numActiveSlots >= input->numSlots) {
+ break;
}
if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
ALOGV("[%s] no new buffer available", mName);
@@ -649,6 +647,7 @@
ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
mCallback->onInputBufferAvailable(index, inBuffer);
}
+ ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots);
}
status_t CCodecBufferChannel::renderOutputBuffer(
@@ -817,6 +816,9 @@
status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
if (result != OK) {
ALOGI("[%s] queueBuffer failed: %d", mName, result);
+ if (result == NO_INIT) {
+ mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
+ }
return result;
}
ALOGV("[%s] queue buffer successful", mName);
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 3c99bf6..692da58 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -495,11 +495,12 @@
mBuffers.clear();
}
-size_t FlexBuffersImpl::numClientBuffers() const {
+size_t FlexBuffersImpl::numActiveSlots() const {
return std::count_if(
mBuffers.begin(), mBuffers.end(),
[](const Entry &entry) {
- return (entry.clientBuffer != nullptr);
+ return (entry.clientBuffer != nullptr
+ || !entry.compBuffer.expired());
});
}
@@ -645,11 +646,11 @@
}
}
-size_t BuffersArrayImpl::numClientBuffers() const {
+size_t BuffersArrayImpl::numActiveSlots() const {
return std::count_if(
mBuffers.begin(), mBuffers.end(),
[](const Entry &entry) {
- return entry.ownedByClient;
+ return entry.ownedByClient || !entry.compBuffer.expired();
});
}
@@ -699,8 +700,8 @@
mImpl.flush();
}
-size_t InputBuffersArray::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t InputBuffersArray::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
@@ -737,8 +738,8 @@
return nullptr;
}
-size_t SlotInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t SlotInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
@@ -789,8 +790,8 @@
return std::move(array);
}
-size_t LinearInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t LinearInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
// static
@@ -966,8 +967,8 @@
return std::move(array);
}
-size_t GraphicMetadataInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t GraphicMetadataInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
@@ -1031,8 +1032,8 @@
return std::move(array);
}
-size_t GraphicInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t GraphicInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
@@ -1121,8 +1122,8 @@
mImpl.getArray(array);
}
-size_t OutputBuffersArray::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t OutputBuffersArray::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
@@ -1232,8 +1233,8 @@
return array;
}
-size_t FlexOutputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t FlexOutputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
// LinearOutputBuffers
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index 0d4fa81..c383a7c 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -33,8 +33,8 @@
class SkipCutBuffer;
constexpr size_t kLinearBufferSize = 1048576;
-// This can fit 4K RGBA frame, and most likely client won't need more than this.
-constexpr size_t kMaxLinearBufferSize = 4096 * 2304 * 4;
+// This can fit an 8K frame.
+constexpr size_t kMaxLinearBufferSize = 7680 * 4320 * 2;
/**
* Base class for representation of buffers at one port.
@@ -72,7 +72,7 @@
/**
* Return number of buffers the client owns.
*/
- virtual size_t numClientBuffers() const = 0;
+ virtual size_t numActiveSlots() const = 0;
/**
* Examine image data from the buffer and update the format if necessary.
@@ -584,7 +584,7 @@
* Return the number of buffers that are sent to the client but not released
* yet.
*/
- size_t numClientBuffers() const;
+ size_t numActiveSlots() const;
/**
* Return the number of buffers that are sent to the component but not
@@ -705,7 +705,7 @@
* Return the number of buffers that are sent to the client but not released
* yet.
*/
- size_t numClientBuffers() const;
+ size_t numActiveSlots() const;
/**
* Return the size of the array.
@@ -765,7 +765,7 @@
void flush() override;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -796,7 +796,7 @@
std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() final;
@@ -826,7 +826,7 @@
std::unique_ptr<InputBuffers> toArrayMode(size_t size) override;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -894,7 +894,7 @@
std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -924,7 +924,7 @@
std::unique_ptr<InputBuffers> toArrayMode(
size_t size) final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -965,7 +965,7 @@
array->clear();
}
- size_t numClientBuffers() const final {
+ size_t numActiveSlots() const final {
return 0u;
}
@@ -1019,7 +1019,7 @@
void getArray(Vector<sp<MediaCodecBuffer>> *array) const final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
/**
* Reallocate the array, filled with buffers with the same size as given
@@ -1073,7 +1073,7 @@
std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) override;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
/**
* Return an appropriate Codec2Buffer object for the type of buffers.
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 0b1cfa0..ded3d1a 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -1582,15 +1582,24 @@
ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(image->thumbnails[0]);
if (thumbItemIndex >= 0) {
const ImageItem &thumbnail = mItemIdToItemMap[thumbItemIndex];
- // TODO(vigneshv): Handle thumbnail for AVIF.
- if (thumbnail.hvcc != NULL) {
+ if (thumbnail.hvcc != NULL || thumbnail.av1c != NULL) {
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH, thumbnail.width);
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT, thumbnail.height);
- AMediaFormat_setBuffer(meta,
- AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC,
- thumbnail.hvcc->data(), thumbnail.hvcc->size());
+ if (thumbnail.hvcc != NULL) {
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC,
+ thumbnail.hvcc->data(), thumbnail.hvcc->size());
+ } else {
+ // We use a hard-coded string here instead of
+ // AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C. The key is available only from SDK 31.
+ // The mp4 extractor is part of mainline and builds against SDK 29 as of
+ // writing. This hard-coded string can be replaced with the named constant once
+ // the mp4 extractor is built against SDK >= 31.
+ AMediaFormat_setBuffer(meta,
+ "thumbnail-csd-av1c", thumbnail.av1c->data(), thumbnail.av1c->size());
+ }
ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
} else {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index cd70869..7989d4b 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -203,8 +203,8 @@
uint32_t duration;
int32_t compositionOffset;
uint8_t iv[16];
- Vector<size_t> clearsizes;
- Vector<size_t> encryptedsizes;
+ Vector<uint32_t> clearsizes;
+ Vector<uint32_t> encryptedsizes;
};
Vector<Sample> mCurrentSamples;
std::map<off64_t, uint32_t> mDrmOffsets;
@@ -6556,9 +6556,9 @@
if (smpl->encryptedsizes.size()) {
// store clear/encrypted lengths in metadata
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES,
- smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
+ smpl->clearsizes.array(), smpl->clearsizes.size() * sizeof(uint32_t));
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_SIZES,
- smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
+ smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * sizeof(uint32_t));
AMediaFormat_setInt32(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE, mDefaultIVSize);
AMediaFormat_setInt32(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_MODE, mCryptoMode);
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_KEY, mCryptoKey, 16);
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 81f9dff..cd098b5 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -1614,6 +1614,7 @@
// case SET_FORCE_USE:
case INIT_STREAM_VOLUME:
case SET_STREAM_VOLUME:
+ case SET_VOLUME_ATTRIBUTES:
case REGISTER_POLICY_MIXES:
case SET_MASTER_MONO:
case GET_SURROUND_FORMATS:
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
index 1df47b7..2a0dec4 100644
--- a/media/libaudioprocessing/tests/fuzzer/Android.bp
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -8,3 +8,14 @@
"libsndfile",
],
}
+
+cc_fuzz {
+ name: "libaudioprocessing_record_buffer_converter_fuzzer",
+ srcs: [
+ "libaudioprocessing_record_buffer_converter_fuzzer.cpp",
+ ],
+ defaults: ["libaudioprocessing_test_defaults"],
+ static_libs: [
+ "libsndfile",
+ ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h
new file mode 100644
index 0000000..5165925
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#ifndef ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
+#define ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
+
+#include <media/AudioBufferProvider.h>
+#include <system/audio.h>
+
+namespace android {
+
+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;
+ }
+ }
+ void releaseBuffer(Buffer* buffer) override {
+ 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; }
+};
+
+} // namespace android
+
+#endif // ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp
new file mode 100644
index 0000000..017598c
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 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 "libaudioprocessing_fuzz_utils.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include <media/AudioResampler.h>
+#include <media/RecordBufferConverter.h>
+#include <stddef.h>
+#include <stdint.h>
+
+using namespace android;
+
+constexpr int MAX_FRAMES = 1024;
+
+#define AUDIO_FORMAT_PCM_MAIN 0
+
+// Copied and simplified from audio-hal-enums.h?l=571
+constexpr uint32_t FUZZ_AUDIO_FORMATS[] = {
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_16_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_8_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_32_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_8_24_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_FLOAT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED,
+ 0x01000000u,
+ 0x02000000u,
+ 0x03000000u,
+ 0x04000000u,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_MAIN,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LC,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_SSR,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LTP,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_HE_V1,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_SCALABLE,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ERLC,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LD,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_HE_V2,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ELD,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_XHE,
+ 0x05000000u,
+ 0x06000000u,
+ 0x07000000u,
+ 0x08000000u,
+ 0x09000000u,
+ 0x0A000000u,
+ AUDIO_FORMAT_E_AC3 | AUDIO_FORMAT_E_AC3_SUB_JOC,
+ 0x0B000000u,
+ 0x0C000000u,
+ 0x0D000000u,
+ 0x0E000000u,
+ 0x10000000u,
+ 0x11000000u,
+ 0x12000000u,
+ 0x13000000u,
+ 0x14000000u,
+ 0x15000000u,
+ 0x16000000u,
+ 0x17000000u,
+ 0x18000000u,
+ 0x19000000u,
+ 0x1A000000u,
+ 0x1B000000u,
+ 0x1C000000u,
+ 0x1D000000u,
+ 0x1E000000u,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_MAIN,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LC,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_SSR,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LTP,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_HE_V1,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_SCALABLE,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_ERLC,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LD,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_HE_V2,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_ELD,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_XHE,
+ 0x1F000000u,
+ 0x20000000u,
+ 0x21000000u,
+ 0x22000000u,
+ 0x23000000u,
+ 0x24000000u,
+ AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_1_0,
+ AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_2_0,
+ AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_2_1,
+ 0x25000000u,
+ AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_LC,
+ AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_HE_V1,
+ AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_HE_V2,
+ 0x26000000u,
+ 0x27000000u,
+ 0x28000000u,
+ 0x29000000u,
+ 0x2A000000u,
+ 0x2B000000u,
+ 0xFFFFFFFFu,
+ AUDIO_FORMAT_PCM_MAIN,
+ AUDIO_FORMAT_PCM,
+};
+constexpr size_t NUM_AUDIO_FORMATS = std::size(FUZZ_AUDIO_FORMATS);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ fdp.ConsumeIntegral<int>();
+
+ const audio_channel_mask_t srcChannelMask = (audio_channel_mask_t)fdp.ConsumeIntegral<int>();
+ const audio_format_t srcFormat =
+ (audio_format_t)FUZZ_AUDIO_FORMATS[fdp.ConsumeIntegralInRange<int>(0, NUM_AUDIO_FORMATS - 1)];
+ const uint32_t srcSampleRate = fdp.ConsumeIntegralInRange<int>(1, 0x7fffffff);
+ const audio_channel_mask_t dstChannelMask = (audio_channel_mask_t)fdp.ConsumeIntegral<int>();
+ const audio_format_t dstFormat =
+ (audio_format_t)FUZZ_AUDIO_FORMATS[fdp.ConsumeIntegralInRange<int>(0, NUM_AUDIO_FORMATS - 1)];
+ const uint32_t dstSampleRate = fdp.ConsumeIntegralInRange<int>(1, 0x7fffffff);
+
+ // Certain formats will result in LOG_ALWAYS_FATAL errors that aren't interesting crashes
+ // for fuzzing. Don't use those ones.
+ const uint32_t dstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
+ constexpr android::AudioResampler::src_quality quality =
+ android::AudioResampler::DEFAULT_QUALITY;
+ const int maxChannels =
+ quality < android::AudioResampler::DYN_LOW_QUALITY ? 2 : 8;
+ if (dstChannelCount < 1 || dstChannelCount > maxChannels) {
+ return 0;
+ }
+
+ const uint32_t srcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
+ if (srcChannelCount < 1 || srcChannelCount > maxChannels) {
+ return 0;
+ }
+
+ RecordBufferConverter converter(srcChannelMask, srcFormat, srcSampleRate,
+ dstChannelMask, dstFormat, dstSampleRate);
+ if (converter.initCheck() != NO_ERROR) {
+ return 0;
+ }
+
+ const uint32_t srcFrameSize = srcChannelCount * audio_bytes_per_sample(srcFormat);
+ const int srcNumFrames = fdp.ConsumeIntegralInRange<int>(0, MAX_FRAMES);
+ constexpr size_t metadataSize = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+ std::vector<uint8_t> inputData = fdp.ConsumeBytes<uint8_t>(
+ metadataSize + (srcFrameSize * srcNumFrames));
+ Provider provider(inputData.data(), srcNumFrames, srcFrameSize);
+
+ const uint32_t dstFrameSize = dstChannelCount * audio_bytes_per_sample(dstFormat);
+ const size_t frames = fdp.ConsumeIntegralInRange<size_t>(0, MAX_FRAMES + 1);
+ int8_t dst[dstFrameSize * frames];
+ memset(dst, 0, sizeof(int8_t) * dstFrameSize * frames);
+
+ // Add a small number of loops to see if repeated calls to convert cause
+ // any change in behavior.
+ const int numLoops = fdp.ConsumeIntegralInRange<int>(1, 3);
+ for (int loop = 0; loop < numLoops; ++loop) {
+ switch (fdp.ConsumeIntegralInRange<int>(0, 1)) {
+ case 0:
+ converter.reset();
+ FALLTHROUGH_INTENDED;
+ case 1:
+ converter.convert(dst, &provider, frames);
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
index 938c610..65c9a3c 100644
--- a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -34,6 +34,8 @@
#include <unistd.h>
#include <utils/Vector.h>
+#include "libaudioprocessing_fuzz_utils.h"
+
#include <memory>
using namespace android;
@@ -53,46 +55,6 @@
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) {
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index 16cd0ad..5217cf9 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -1,6 +1,6 @@
// audio preprocessing wrapper
cc_library_shared {
- name: "libaudiopreprocessing",
+ name: "libaudiopreprocessing_legacy",
vendor: true,
@@ -17,6 +17,7 @@
cflags: [
"-DWEBRTC_POSIX",
+ "-DWEBRTC_LEGACY",
"-fvisibility=hidden",
"-Wall",
"-Werror",
@@ -27,3 +28,34 @@
"libhardware_headers",
],
}
+
+cc_library_shared {
+ name: "libaudiopreprocessing",
+ vendor: true,
+ relative_install_path: "soundfx",
+ srcs: ["PreProcessing.cpp"],
+ local_include_dirs: [
+ ".",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "webrtc_audio_processing",
+ ],
+
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ "libwebrtc_absl_headers",
+ ],
+}
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index c7afe2f..f2f74a5 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -23,10 +23,15 @@
#include <hardware/audio_effect.h>
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_agc.h>
+#ifndef WEBRTC_LEGACY
+#include <audio_effects/effect_agc2.h>
+#endif
#include <audio_effects/effect_ns.h>
#include <module_common_types.h>
#include <audio_processing.h>
+#ifdef WEBRTC_LEGACY
#include "speex/speex_resampler.h"
+#endif
// undefine to perform multi channels API functional tests
//#define DUAL_MIC_TEST
@@ -42,6 +47,9 @@
enum preproc_id
{
PREPROC_AGC, // Automatic Gain Control
+#ifndef WEBRTC_LEGACY
+ PREPROC_AGC2, // Automatic Gain Control 2
+#endif
PREPROC_AEC, // Acoustic Echo Canceler
PREPROC_NS, // Noise Suppressor
PREPROC_NUM_EFFECTS
@@ -103,6 +111,10 @@
int id; // audio session ID
int io; // handle of input stream this session is on
webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
+#ifndef WEBRTC_LEGACY
+ // Audio Processing module builder
+ webrtc::AudioProcessingBuilder ap_builder;
+#endif
size_t apmFrameCount; // buffer size for webRTC process (10 ms)
uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
@@ -113,25 +125,42 @@
uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
uint32_t processedMsk; // bit field containing IDs of pre processors already
// processed in current round
+#ifdef WEBRTC_LEGACY
webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
+#else
+ // audio config strucutre
+ webrtc::AudioProcessing::Config config;
+ webrtc::StreamConfig inputConfig; // input stream configuration
+ webrtc::StreamConfig outputConfig; // output stream configuration
+#endif
int16_t *inBuf; // input buffer used when resampling
size_t inBufSize; // input buffer size in frames
size_t framesIn; // number of frames in input buffer
+#ifdef WEBRTC_LEGACY
SpeexResamplerState *inResampler; // handle on input speex resampler
+#endif
int16_t *outBuf; // output buffer used when resampling
size_t outBufSize; // output buffer size in frames
size_t framesOut; // number of frames in output buffer
+#ifdef WEBRTC_LEGACY
SpeexResamplerState *outResampler; // handle on output speex resampler
+#endif
uint32_t revChannelCount; // number of channels on reverse stream
uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
// with reverse channel
uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
// channel already processed in current round
+#ifdef WEBRTC_LEGACY
webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
+#else
+ webrtc::StreamConfig revConfig; // reverse stream configuration.
+#endif
int16_t *revBuf; // reverse channel input buffer
size_t revBufSize; // reverse channel input buffer size
size_t framesRev; // number of frames in reverse channel input buffer
+#ifdef WEBRTC_LEGACY
SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
+#endif
};
#ifdef DUAL_MIC_TEST
@@ -188,6 +217,20 @@
"The Android Open Source Project"
};
+#ifndef WEBRTC_LEGACY
+// Automatic Gain Control 2
+static const effect_descriptor_t sAgc2Descriptor = {
+ { 0xae3c653b, 0xbe18, 0x4ab8, 0x8938, { 0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac } }, // type
+ { 0x89f38e65, 0xd4d2, 0x4d64, 0xad0e, { 0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Automatic Gain Control 2",
+ "The Android Open Source Project"
+};
+#endif
+
// Acoustic Echo Cancellation
static const effect_descriptor_t sAecDescriptor = {
{ 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
@@ -215,6 +258,9 @@
static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
&sAgcDescriptor,
+#ifndef WEBRTC_LEGACY
+ &sAgc2Descriptor,
+#endif
&sAecDescriptor,
&sNsDescriptor
};
@@ -225,6 +271,9 @@
const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
FX_IID_AGC,
+#ifndef WEBRTC_LEGACY
+ FX_IID_AGC2,
+#endif
FX_IID_AEC,
FX_IID_NS
};
@@ -266,19 +315,50 @@
static const int kAgcDefaultCompGain = 9;
static const bool kAgcDefaultLimiter = true;
+#ifndef WEBRTC_LEGACY
+int Agc2Init (preproc_effect_t *effect)
+{
+ ALOGV("Agc2Init");
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller2.fixed_digital.gain_db = 0.f;
+ effect->session->config.gain_controller2.adaptive_digital.level_estimator =
+ effect->session->config.gain_controller2.kRms;
+ effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db = 2.f;
+ effect->session->apm->ApplyConfig(effect->session->config);
+ return 0;
+}
+#endif
+
int AgcInit (preproc_effect_t *effect)
{
ALOGV("AgcInit");
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
agc->set_mode(webrtc::GainControl::kFixedDigital);
agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
agc->set_compression_gain_db(kAgcDefaultCompGain);
agc->enable_limiter(kAgcDefaultLimiter);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller1.target_level_dbfs = kAgcDefaultTargetLevel;
+ effect->session->config.gain_controller1.compression_gain_db = kAgcDefaultCompGain;
+ effect->session->config.gain_controller1.enable_limiter = kAgcDefaultLimiter;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
return 0;
}
+#ifndef WEBRTC_LEGACY
+int Agc2Create(preproc_effect_t *effect)
+{
+ Agc2Init(effect);
+ return 0;
+}
+#endif
+
int AgcCreate(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = effect->session->apm->gain_control();
ALOGV("AgcCreate got agc %p", agc);
if (agc == NULL) {
@@ -286,10 +366,93 @@
return -ENOMEM;
}
effect->engine = static_cast<preproc_fx_handle_t>(agc);
+#endif
AgcInit(effect);
return 0;
}
+#ifndef WEBRTC_LEGACY
+int Agc2GetParameter(preproc_effect_t *effect,
+ void *pParam,
+ uint32_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ agc2_settings_t *pProperties = (agc2_settings_t *)pValue;
+
+ switch (param) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN:
+ if (*pValueSize < sizeof(float)) {
+ *pValueSize = 0.f;
+ return -EINVAL;
+ }
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
+ if (*pValueSize < sizeof(int32_t)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
+ if (*pValueSize < sizeof(float)) {
+ *pValueSize = 0.f;
+ return -EINVAL;
+ }
+ break;
+ case AGC2_PARAM_PROPERTIES:
+ if (*pValueSize < sizeof(agc2_settings_t)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ ALOGW("Agc2GetParameter() unknown param %08x", param);
+ status = -EINVAL;
+ break;
+ }
+
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN:
+ *(float *) pValue =
+ (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
+ ALOGV("Agc2GetParameter() target level %f dB", *(float *) pValue);
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
+ *(uint32_t *) pValue =
+ (uint32_t)(effect->session->config.gain_controller2.adaptive_digital.
+ level_estimator);
+ ALOGV("Agc2GetParameter() level estimator %d",
+ *(webrtc::AudioProcessing::Config::GainController2::LevelEstimator *) pValue);
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
+ *(float *) pValue =
+ (float)(effect->session->config.gain_controller2.adaptive_digital.
+ extra_saturation_margin_db);
+ ALOGV("Agc2GetParameter() extra saturation margin %f dB", *(float *) pValue);
+ break;
+ case AGC2_PARAM_PROPERTIES:
+ pProperties->fixedDigitalGain =
+ (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
+ pProperties->level_estimator =
+ (uint32_t)(effect->session->config.gain_controller2.adaptive_digital.
+ level_estimator);
+ pProperties->extraSaturationMargin =
+ (float)(effect->session->config.gain_controller2.adaptive_digital.
+ extra_saturation_margin_db);
+ break;
+ default:
+ ALOGW("Agc2GetParameter() unknown param %d", param);
+ status = -EINVAL;
+ break;
+ }
+
+ return status;
+}
+#endif
+
int AgcGetParameter(preproc_effect_t *effect,
void *pParam,
uint32_t *pValueSize,
@@ -298,7 +461,9 @@
int status = 0;
uint32_t param = *(uint32_t *)pParam;
t_agc_settings *pProperties = (t_agc_settings *)pValue;
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+#endif
switch (param) {
case AGC_PARAM_TARGET_LEVEL:
@@ -327,6 +492,7 @@
break;
}
+#ifdef WEBRTC_LEGACY
switch (param) {
case AGC_PARAM_TARGET_LEVEL:
*(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
@@ -351,12 +517,98 @@
status = -EINVAL;
break;
}
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ *(int16_t *) pValue =
+ (int16_t)(effect->session->config.gain_controller1.target_level_dbfs * -100);
+ ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ *(int16_t *) pValue =
+ (int16_t)(effect->session->config.gain_controller1.compression_gain_db * -100);
+ ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ *(bool *) pValue =
+ (bool)(effect->session->config.gain_controller1.enable_limiter);
+ ALOGV("AgcGetParameter() limiter enabled %s",
+ (*(int16_t *) pValue != 0) ? "true" : "false");
+ break;
+ case AGC_PARAM_PROPERTIES:
+ pProperties->targetLevel =
+ (int16_t)(effect->session->config.gain_controller1.target_level_dbfs * -100);
+ pProperties->compGain =
+ (int16_t)(effect->session->config.gain_controller1.compression_gain_db * -100);
+ pProperties->limiterEnabled =
+ (bool)(effect->session->config.gain_controller1.enable_limiter);
+ break;
+ default:
+ ALOGW("AgcGetParameter() unknown param %d", param);
+ status = -EINVAL;
+ break;
+ }
+#endif
return status;
}
+#ifndef WEBRTC_LEGACY
+int Agc2SetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ float valueFloat = 0.f;
+ agc2_settings_t *pProperties = (agc2_settings_t *)pValue;
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN:
+ valueFloat = (float)(*(int32_t *) pValue);
+ ALOGV("Agc2SetParameter() fixed digital gain %f dB", valueFloat);
+ effect->session->config.gain_controller2.fixed_digital.gain_db = valueFloat;
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
+ ALOGV("Agc2SetParameter() level estimator %d", *(webrtc::AudioProcessing::Config::
+ GainController2::LevelEstimator *) pValue);
+ effect->session->config.gain_controller2.adaptive_digital.level_estimator =
+ (*(webrtc::AudioProcessing::Config::GainController2::LevelEstimator *) pValue);
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
+ valueFloat = (float)(*(int32_t *) pValue);
+ ALOGV("Agc2SetParameter() extra saturation margin %f dB", valueFloat);
+ effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
+ valueFloat;
+ break;
+ case AGC2_PARAM_PROPERTIES:
+ ALOGV("Agc2SetParameter() properties gain %f, level %d margin %f",
+ pProperties->fixedDigitalGain,
+ pProperties->level_estimator,
+ pProperties->extraSaturationMargin);
+ effect->session->config.gain_controller2.fixed_digital.gain_db =
+ pProperties->fixedDigitalGain;
+ effect->session->config.gain_controller2.adaptive_digital.level_estimator =
+ (webrtc::AudioProcessing::Config::GainController2::LevelEstimator)pProperties->
+ level_estimator;
+ effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
+ pProperties->extraSaturationMargin;
+ break;
+ default:
+ ALOGW("Agc2SetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ effect->session->apm->ApplyConfig(effect->session->config);
+
+ ALOGV("Agc2SetParameter() done status %d", status);
+
+ return status;
+}
+#endif
+
int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
{
int status = 0;
+#ifdef WEBRTC_LEGACY
uint32_t param = *(uint32_t *)pParam;
t_agc_settings *pProperties = (t_agc_settings *)pValue;
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
@@ -390,27 +642,95 @@
status = -EINVAL;
break;
}
+#else
+ uint32_t param = *(uint32_t *)pParam;
+ t_agc_settings *pProperties = (t_agc_settings *)pValue;
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
+ effect->session->config.gain_controller1.target_level_dbfs =
+ (-(*(int16_t *)pValue / 100));
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
+ effect->session->config.gain_controller1.compression_gain_db =
+ (*(int16_t *)pValue / 100);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
+ effect->session->config.gain_controller1.enable_limiter =
+ (*(bool *)pValue);
+ break;
+ case AGC_PARAM_PROPERTIES:
+ ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
+ pProperties->targetLevel,
+ pProperties->compGain,
+ pProperties->limiterEnabled);
+ effect->session->config.gain_controller1.target_level_dbfs =
+ -(pProperties->targetLevel / 100);
+ effect->session->config.gain_controller1.compression_gain_db =
+ pProperties->compGain / 100;
+ effect->session->config.gain_controller1.enable_limiter =
+ pProperties->limiterEnabled;
+ break;
+ default:
+ ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
ALOGV("AgcSetParameter() done status %d", status);
return status;
}
+#ifndef WEBRTC_LEGACY
+void Agc2Enable(preproc_effect_t *effect)
+{
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller2.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+}
+#endif
+
void AgcEnable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
ALOGV("AgcEnable agc %p", agc);
agc->Enable(true);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller1.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
+#ifndef WEBRTC_LEGACY
+void Agc2Disable(preproc_effect_t *effect)
+{
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller2.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+}
+#endif
+
void AgcDisable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
ALOGV("AgcDisable");
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
agc->Enable(false);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller1.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
-
static const preproc_ops_t sAgcOps = {
AgcCreate,
AgcInit,
@@ -422,26 +742,48 @@
NULL
};
+#ifndef WEBRTC_LEGACY
+static const preproc_ops_t sAgc2Ops = {
+ Agc2Create,
+ Agc2Init,
+ NULL,
+ Agc2Enable,
+ Agc2Disable,
+ Agc2SetParameter,
+ Agc2GetParameter,
+ NULL
+};
+#endif
//------------------------------------------------------------------------------
// Acoustic Echo Canceler (AEC)
//------------------------------------------------------------------------------
+#ifdef WEBRTC_LEGACY
static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
webrtc::EchoControlMobile::kEarpiece;
static const bool kAecDefaultComfortNoise = true;
+#endif
int AecInit (preproc_effect_t *effect)
{
ALOGV("AecInit");
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
aec->set_routing_mode(kAecDefaultMode);
aec->enable_comfort_noise(kAecDefaultComfortNoise);
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ effect->session->config.echo_canceller.mobile_mode = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
return 0;
}
int AecCreate(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
ALOGV("AecCreate got aec %p", aec);
if (aec == NULL) {
@@ -449,6 +791,7 @@
return -ENOMEM;
}
effect->engine = static_cast<preproc_fx_handle_t>(aec);
+#endif
AecInit (effect);
return 0;
}
@@ -470,6 +813,14 @@
*(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
break;
+#ifndef WEBRTC_LEGACY
+ case AEC_PARAM_MOBILE_MODE:
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ *(uint32_t *)pValue = effect->session->config.echo_canceller.mobile_mode;
+ ALOGV("AecGetParameter() mobile mode %d us", *(uint32_t *)pValue);
+ break;
+#endif
default:
ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
status = -EINVAL;
@@ -490,6 +841,15 @@
status = effect->session->apm->set_stream_delay_ms(value/1000);
ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
break;
+#ifndef WEBRTC_LEGACY
+ case AEC_PARAM_MOBILE_MODE:
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ effect->session->config.echo_canceller.mobile_mode = value;
+ ALOGV("AecSetParameter() mobile mode %d us", value);
+ effect->session->apm->ApplyConfig(effect->session->config);
+ break;
+#endif
default:
ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
status = -EINVAL;
@@ -500,28 +860,43 @@
void AecEnable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
ALOGV("AecEnable aec %p", aec);
aec->Enable(true);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.echo_canceller.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
void AecDisable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
ALOGV("AecDisable");
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
aec->Enable(false);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.echo_canceller.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
int AecSetDevice(preproc_effect_t *effect, uint32_t device)
{
ALOGV("AecSetDevice %08x", device);
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
+#endif
if (audio_is_input_device(device)) {
return 0;
}
+#ifdef WEBRTC_LEGACY
switch(device) {
case AUDIO_DEVICE_OUT_EARPIECE:
mode = webrtc::EchoControlMobile::kEarpiece;
@@ -536,6 +911,7 @@
break;
}
aec->set_routing_mode(mode);
+#endif
return 0;
}
@@ -554,11 +930,17 @@
// Noise Suppression (NS)
//------------------------------------------------------------------------------
+#ifdef WEBRTC_LEGACY
static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
+#else
+static const webrtc::AudioProcessing::Config::NoiseSuppression::Level kNsDefaultLevel =
+ webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
+#endif
int NsInit (preproc_effect_t *effect)
{
ALOGV("NsInit");
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ns->set_level(kNsDefaultLevel);
webrtc::Config config;
@@ -575,12 +957,20 @@
config.Set<webrtc::Beamforming>(
new webrtc::Beamforming(false, geometry));
effect->session->apm->SetExtraOptions(config);
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ effect->session->config.noise_suppression.level =
+ kNsDefaultLevel;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
effect->type = NS_TYPE_SINGLE_CHANNEL;
return 0;
}
int NsCreate(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
ALOGV("NsCreate got ns %p", ns);
if (ns == NULL) {
@@ -588,6 +978,7 @@
return -ENOMEM;
}
effect->engine = static_cast<preproc_fx_handle_t>(ns);
+#endif
NsInit (effect);
return 0;
}
@@ -604,6 +995,7 @@
int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
{
int status = 0;
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
uint32_t param = *(uint32_t *)pParam;
uint32_t value = *(uint32_t *)pValue;
@@ -629,12 +1021,30 @@
ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
status = -EINVAL;
}
+#else
+ uint32_t param = *(uint32_t *)pParam;
+ uint32_t value = *(uint32_t *)pValue;
+ effect->session->config =
+ effect->session->apm->GetConfig();
+ switch (param) {
+ case NS_PARAM_LEVEL:
+ effect->session->config.noise_suppression.level =
+ (webrtc::AudioProcessing::Config::NoiseSuppression::Level)value;
+ ALOGV("NsSetParameter() level %d", value);
+ break;
+ default:
+ ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
+ status = -EINVAL;
+ }
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
return status;
}
void NsEnable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ALOGV("NsEnable ns %p", ns);
ns->Enable(true);
@@ -644,17 +1054,30 @@
config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
effect->session->apm->SetExtraOptions(config);
}
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig();
+ effect->session->config.noise_suppression.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
void NsDisable(preproc_effect_t *effect)
{
ALOGV("NsDisable");
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ns->Enable(false);
webrtc::Config config;
std::vector<webrtc::Point> geometry;
config.Set<webrtc::Beamforming>(new webrtc::Beamforming(false, geometry));
effect->session->apm->SetExtraOptions(config);
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig();
+ effect->session->config.noise_suppression.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
static const preproc_ops_t sNsOps = {
@@ -669,8 +1092,12 @@
};
+
static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
&sAgcOps,
+#ifndef WEBRTC_LEGACY
+ &sAgc2Ops,
+#endif
&sAecOps,
&sNsOps
};
@@ -812,7 +1239,9 @@
session->id = 0;
session->io = 0;
session->createdMsk = 0;
+#ifdef WEBRTC_LEGACY
session->apm = NULL;
+#endif
for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
status = Effect_Init(&session->effects[i], i);
}
@@ -829,6 +1258,7 @@
ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
if (session->createdMsk == 0) {
+#ifdef WEBRTC_LEGACY
session->apm = webrtc::AudioProcessing::Create();
if (session->apm == NULL) {
ALOGW("Session_CreateEffect could not get apm engine");
@@ -850,28 +1280,53 @@
ALOGW("Session_CreateEffect could not allocate reverse audio frame");
goto error;
}
+#else
+ session->apm = session->ap_builder.Create();
+ if (session->apm == NULL) {
+ ALOGW("Session_CreateEffect could not get apm engine");
+ goto error;
+ }
+#endif
session->apmSamplingRate = kPreprocDefaultSr;
session->apmFrameCount = (kPreprocDefaultSr) / 100;
session->frameCount = session->apmFrameCount;
session->samplingRate = kPreprocDefaultSr;
session->inChannelCount = kPreProcDefaultCnl;
session->outChannelCount = kPreProcDefaultCnl;
+#ifdef WEBRTC_LEGACY
session->procFrame->sample_rate_hz_ = kPreprocDefaultSr;
session->procFrame->num_channels_ = kPreProcDefaultCnl;
+#else
+ session->inputConfig.set_sample_rate_hz(kPreprocDefaultSr);
+ session->inputConfig.set_num_channels(kPreProcDefaultCnl);
+ session->outputConfig.set_sample_rate_hz(kPreprocDefaultSr);
+ session->outputConfig.set_num_channels(kPreProcDefaultCnl);
+#endif
session->revChannelCount = kPreProcDefaultCnl;
+#ifdef WEBRTC_LEGACY
session->revFrame->sample_rate_hz_ = kPreprocDefaultSr;
session->revFrame->num_channels_ = kPreProcDefaultCnl;
+#else
+ session->revConfig.set_sample_rate_hz(kPreprocDefaultSr);
+ session->revConfig.set_num_channels(kPreProcDefaultCnl);
+#endif
session->enabledMsk = 0;
session->processedMsk = 0;
session->revEnabledMsk = 0;
session->revProcessedMsk = 0;
+#ifdef WEBRTC_LEGACY
session->inResampler = NULL;
+#endif
session->inBuf = NULL;
session->inBufSize = 0;
+#ifdef WEBRTC_LEGACY
session->outResampler = NULL;
+#endif
session->outBuf = NULL;
session->outBufSize = 0;
+#ifdef WEBRTC_LEGACY
session->revResampler = NULL;
+#endif
session->revBuf = NULL;
session->revBufSize = 0;
}
@@ -885,12 +1340,17 @@
error:
if (session->createdMsk == 0) {
+#ifdef WEBRTC_LEGACY
delete session->revFrame;
session->revFrame = NULL;
delete session->procFrame;
session->procFrame = NULL;
delete session->apm;
session->apm = NULL; // NOLINT(clang-analyzer-cplusplus.NewDelete)
+#else
+ delete session->apm;
+ session->apm = NULL;
+#endif
}
return status;
}
@@ -901,6 +1361,7 @@
ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
session->createdMsk &= ~(1<<fx->procId);
if (session->createdMsk == 0) {
+#ifdef WEBRTC_LEGACY
delete session->apm;
session->apm = NULL;
delete session->procFrame;
@@ -919,6 +1380,10 @@
speex_resampler_destroy(session->revResampler);
session->revResampler = NULL;
}
+#else
+ delete session->apm;
+ session->apm = NULL;
+#endif
delete session->inBuf;
session->inBuf = NULL;
delete session->outBuf;
@@ -946,7 +1411,9 @@
ALOGV("Session_SetConfig sr %d cnl %08x",
config->inputCfg.samplingRate, config->inputCfg.channels);
+#ifdef WEBRTC_LEGACY
int status;
+#endif
// AEC implementation is limited to 16kHz
if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
@@ -958,6 +1425,7 @@
session->apmSamplingRate = 8000;
}
+#ifdef WEBRTC_LEGACY
const webrtc::ProcessingConfig processing_config = {
{{static_cast<int>(session->apmSamplingRate), inCnl},
{static_cast<int>(session->apmSamplingRate), outCnl},
@@ -967,23 +1435,41 @@
if (status < 0) {
return -EINVAL;
}
+#endif
session->samplingRate = config->inputCfg.samplingRate;
session->apmFrameCount = session->apmSamplingRate / 100;
if (session->samplingRate == session->apmSamplingRate) {
session->frameCount = session->apmFrameCount;
} else {
+#ifdef WEBRTC_LEGACY
session->frameCount = (session->apmFrameCount * session->samplingRate) /
session->apmSamplingRate + 1;
+#else
+ session->frameCount = (session->apmFrameCount * session->samplingRate) /
+ session->apmSamplingRate;
+#endif
}
session->inChannelCount = inCnl;
session->outChannelCount = outCnl;
+#ifdef WEBRTC_LEGACY
session->procFrame->num_channels_ = inCnl;
session->procFrame->sample_rate_hz_ = session->apmSamplingRate;
+#else
+ session->inputConfig.set_sample_rate_hz(session->samplingRate);
+ session->inputConfig.set_num_channels(inCnl);
+ session->outputConfig.set_sample_rate_hz(session->samplingRate);
+ session->outputConfig.set_num_channels(inCnl);
+#endif
session->revChannelCount = inCnl;
+#ifdef WEBRTC_LEGACY
session->revFrame->num_channels_ = inCnl;
session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
+#else
+ session->revConfig.set_sample_rate_hz(session->samplingRate);
+ session->revConfig.set_num_channels(inCnl);
+#endif
// force process buffer reallocation
session->inBufSize = 0;
@@ -992,6 +1478,7 @@
session->framesOut = 0;
+#ifdef WEBRTC_LEGACY
if (session->inResampler != NULL) {
speex_resampler_destroy(session->inResampler);
session->inResampler = NULL;
@@ -1043,6 +1530,7 @@
return -EINVAL;
}
}
+#endif
session->state = PREPROC_SESSION_STATE_CONFIG;
return 0;
@@ -1079,6 +1567,7 @@
return -EINVAL;
}
uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
+#ifdef WEBRTC_LEGACY
const webrtc::ProcessingConfig processing_config = {
{{static_cast<int>(session->apmSamplingRate), session->inChannelCount},
{static_cast<int>(session->apmSamplingRate), session->outChannelCount},
@@ -1088,9 +1577,12 @@
if (status < 0) {
return -EINVAL;
}
+#endif
session->revChannelCount = inCnl;
+#ifdef WEBRTC_LEGACY
session->revFrame->num_channels_ = inCnl;
session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
+#endif
// force process buffer reallocation
session->revBufSize = 0;
session->framesRev = 0;
@@ -1114,6 +1606,7 @@
if (enabled) {
if(session->enabledMsk == 0) {
session->framesIn = 0;
+#ifdef WEBRTC_LEGACY
if (session->inResampler != NULL) {
speex_resampler_reset_mem(session->inResampler);
}
@@ -1121,13 +1614,16 @@
if (session->outResampler != NULL) {
speex_resampler_reset_mem(session->outResampler);
}
+#endif
}
session->enabledMsk |= (1 << procId);
if (HasReverseStream(procId)) {
session->framesRev = 0;
+#ifdef WEBRTC_LEGACY
if (session->revResampler != NULL) {
speex_resampler_reset_mem(session->revResampler);
}
+#endif
session->revEnabledMsk |= (1 << procId);
}
} else {
@@ -1252,6 +1748,7 @@
return 0;
}
+#ifdef WEBRTC_LEGACY
if (session->inResampler != NULL) {
size_t fr = session->frameCount - session->framesIn;
if (inBuffer->frameCount < fr) {
@@ -1335,6 +1832,28 @@
session->procFrame->samples_per_channel_ = session->apmFrameCount;
effect->session->apm->ProcessStream(session->procFrame);
+#else
+ size_t fr = session->frameCount - session->framesIn;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ session->framesIn += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesIn < session->frameCount) {
+ return 0;
+ }
+ session->framesIn = 0;
+ if (int status = effect->session->apm->ProcessStream(
+ (const int16_t* const)inBuffer->s16,
+ (const webrtc::StreamConfig)effect->session->inputConfig,
+ (const webrtc::StreamConfig)effect->session->outputConfig,
+ (int16_t* const)outBuffer->s16);
+ status != 0) {
+ ALOGE("Process Stream failed with error %d\n", status);
+ return status;
+ }
+ outBuffer->frameCount = inBuffer->frameCount;
+#endif
if (session->outBufSize < session->framesOut + session->frameCount) {
int16_t *buf;
@@ -1350,6 +1869,7 @@
session->outBuf = buf;
}
+#ifdef WEBRTC_LEGACY
if (session->outResampler != NULL) {
spx_uint32_t frIn = session->apmFrameCount;
spx_uint32_t frOut = session->frameCount;
@@ -1375,6 +1895,9 @@
session->framesOut += session->frameCount;
}
size_t fr = session->framesOut;
+#else
+ fr = session->framesOut;
+#endif
if (framesRq - framesWr < fr) {
fr = framesRq - framesWr;
}
@@ -1794,6 +2317,7 @@
if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
effect->session->revProcessedMsk = 0;
+#ifdef WEBRTC_LEGACY
if (session->revResampler != NULL) {
size_t fr = session->frameCount - session->framesRev;
if (inBuffer->frameCount < fr) {
@@ -1858,6 +2382,27 @@
}
session->revFrame->samples_per_channel_ = session->apmFrameCount;
effect->session->apm->AnalyzeReverseStream(session->revFrame);
+#else
+ size_t fr = session->frameCount - session->framesRev;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ session->framesRev += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesRev < session->frameCount) {
+ return 0;
+ }
+ session->framesRev = 0;
+ if (int status = effect->session->apm->ProcessReverseStream(
+ (const int16_t* const)inBuffer->s16,
+ (const webrtc::StreamConfig)effect->session->revConfig,
+ (const webrtc::StreamConfig)effect->session->revConfig,
+ (int16_t* const)outBuffer->s16);
+ status != 0) {
+ ALOGE("Process Reverse Stream failed with error %d\n", status);
+ return status;
+ }
+#endif
return 0;
} else {
return -ENODATA;
diff --git a/media/libeffects/preprocessing/tests/Android.bp b/media/libeffects/preprocessing/tests/Android.bp
index 71f6e8f..045b0d3 100644
--- a/media/libeffects/preprocessing/tests/Android.bp
+++ b/media/libeffects/preprocessing/tests/Android.bp
@@ -1,5 +1,37 @@
// audio preprocessing unit test
cc_test {
+ name: "AudioPreProcessingLegacyTest",
+
+ vendor: true,
+
+ relative_install_path: "soundfx",
+
+ srcs: ["PreProcessingTest.cpp"],
+
+ shared_libs: [
+ "libaudiopreprocessing_legacy",
+ "libaudioutils",
+ "liblog",
+ "libutils",
+ "libwebrtc_audio_preprocessing",
+ ],
+
+ cflags: [
+ "-DWEBRTC_POSIX",
+ "-DWEBRTC_LEGACY",
+ "-fvisibility=default",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ ],
+}
+
+cc_test {
name: "AudioPreProcessingTest",
vendor: true,
@@ -13,16 +45,7 @@
"libaudioutils",
"liblog",
"libutils",
- "libwebrtc_audio_preprocessing",
],
-
- cflags: [
- "-DWEBRTC_POSIX",
- "-fvisibility=default",
- "-Wall",
- "-Werror",
- ],
-
header_libs: [
"libaudioeffects",
"libhardware_headers",
diff --git a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
index 5c81d78..3244c1f 100644
--- a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
@@ -14,23 +14,19 @@
* limitations under the License.
*/
+#include <getopt.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <vector>
+
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_agc.h>
+#ifndef WEBRTC_LEGACY
+#include <audio_effects/effect_agc2.h>
+#endif
#include <audio_effects/effect_ns.h>
-#include <audio_processing.h>
-#include <getopt.h>
-#include <hardware/audio_effect.h>
-#include <module_common_types.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#include <audio_utils/channels.h>
-#include <audio_utils/primitives.h>
#include <log/log.h>
-#include <system/audio.h>
// This is the only symbol that needs to be imported
extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
@@ -42,6 +38,9 @@
// types of pre processing modules
enum PreProcId {
PREPROC_AGC, // Automatic Gain Control
+#ifndef WEBRTC_LEGACY
+ PREPROC_AGC2, // Automatic Gain Control 2
+#endif
PREPROC_AEC, // Acoustic Echo Canceler
PREPROC_NS, // Noise Suppressor
PREPROC_NUM_EFFECTS
@@ -58,6 +57,12 @@
ARG_AGC_COMP_LVL,
ARG_AEC_DELAY,
ARG_NS_LVL,
+#ifndef WEBRTC_LEGACY
+ ARG_AEC_MOBILE,
+ ARG_AGC2_GAIN,
+ ARG_AGC2_LVL,
+ ARG_AGC2_SAT_MGN
+#endif
};
struct preProcConfigParams_t {
@@ -66,11 +71,19 @@
int nsLevel = 0; // a value between 0-3
int agcTargetLevel = 3; // in dB
int agcCompLevel = 9; // in dB
+#ifndef WEBRTC_LEGACY
+ float agc2Gain = 0.f; // in dB
+ float agc2SaturationMargin = 2.f; // in dB
+ int agc2Level = 0; // either kRms(0) or kPeak(1)
+#endif
int aecDelay = 0; // in ms
};
const effect_uuid_t kPreProcUuids[PREPROC_NUM_EFFECTS] = {
{0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // agc uuid
+#ifndef WEBRTC_LEGACY
+ {0x89f38e65, 0xd4d2, 0x4d64, 0xad0e, {0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}}, // agc2 uuid
+#endif
{0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // aec uuid
{0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // ns uuid
};
@@ -126,14 +139,30 @@
printf("\n Enable Noise Suppression, default disabled");
printf("\n --agc");
printf("\n Enable Gain Control, default disabled");
+#ifndef WEBRTC_LEGACY
+ printf("\n --agc2");
+ printf("\n Enable Gain Controller 2, default disabled");
+#endif
printf("\n --ns_lvl <ns_level>");
printf("\n Noise Suppression level in dB, default value 0dB");
printf("\n --agc_tgt_lvl <target_level>");
printf("\n AGC Target Level in dB, default value 3dB");
printf("\n --agc_comp_lvl <comp_level>");
printf("\n AGC Comp Level in dB, default value 9dB");
+#ifndef WEBRTC_LEGACY
+ printf("\n --agc2_gain <fixed_digital_gain>");
+ printf("\n AGC Fixed Digital Gain in dB, default value 0dB");
+ printf("\n --agc2_lvl <level_estimator>");
+ printf("\n AGC Adaptive Digital Level Estimator, default value kRms");
+ printf("\n --agc2_sat_mgn <saturation_margin>");
+ printf("\n AGC Adaptive Digital Saturation Margin in dB, default value 2dB");
+#endif
printf("\n --aec_delay <delay>");
printf("\n AEC delay value in ms, default value 0ms");
+#ifndef WEBRTC_LEGACY
+ printf("\n --aec_mobile");
+ printf("\n Enable mobile mode of echo canceller, default disabled");
+#endif
printf("\n");
}
@@ -184,6 +213,9 @@
const char *outputFile = nullptr;
const char *farFile = nullptr;
int effectEn[PREPROC_NUM_EFFECTS] = {0};
+#ifndef WEBRTC_LEGACY
+ int aecMobileMode = 0;
+#endif
const option long_opts[] = {
{"help", no_argument, nullptr, ARG_HELP},
@@ -194,11 +226,22 @@
{"ch_mask", required_argument, nullptr, ARG_CH_MASK},
{"agc_tgt_lvl", required_argument, nullptr, ARG_AGC_TGT_LVL},
{"agc_comp_lvl", required_argument, nullptr, ARG_AGC_COMP_LVL},
+#ifndef WEBRTC_LEGACY
+ {"agc2_gain", required_argument, nullptr, ARG_AGC2_GAIN},
+ {"agc2_lvl", required_argument, nullptr, ARG_AGC2_LVL},
+ {"agc2_sat_mgn", required_argument, nullptr, ARG_AGC2_SAT_MGN},
+#endif
{"aec_delay", required_argument, nullptr, ARG_AEC_DELAY},
{"ns_lvl", required_argument, nullptr, ARG_NS_LVL},
{"aec", no_argument, &effectEn[PREPROC_AEC], 1},
{"agc", no_argument, &effectEn[PREPROC_AGC], 1},
+#ifndef WEBRTC_LEGACY
+ {"agc2", no_argument, &effectEn[PREPROC_AGC2], 1},
+#endif
{"ns", no_argument, &effectEn[PREPROC_NS], 1},
+#ifndef WEBRTC_LEGACY
+ {"aec_mobile", no_argument, &aecMobileMode, 1},
+#endif
{nullptr, 0, nullptr, 0},
};
struct preProcConfigParams_t preProcCfgParams {};
@@ -246,6 +289,20 @@
preProcCfgParams.agcCompLevel = atoi(optarg);
break;
}
+#ifndef WEBRTC_LEGACY
+ case ARG_AGC2_GAIN: {
+ preProcCfgParams.agc2Gain = atof(optarg);
+ break;
+ }
+ case ARG_AGC2_LVL: {
+ preProcCfgParams.agc2Level = atoi(optarg);
+ break;
+ }
+ case ARG_AGC2_SAT_MGN: {
+ preProcCfgParams.agc2SaturationMargin = atof(optarg);
+ break;
+ }
+#endif
case ARG_AEC_DELAY: {
preProcCfgParams.aecDelay = atoi(optarg);
break;
@@ -342,6 +399,31 @@
return EXIT_FAILURE;
}
}
+#ifndef WEBRTC_LEGACY
+ if (effectEn[PREPROC_AGC2]) {
+ if (int status = preProcSetConfigParam(AGC2_PARAM_FIXED_DIGITAL_GAIN,
+ (float)preProcCfgParams.agc2Gain,
+ effectHandle[PREPROC_AGC2]);
+ status != 0) {
+ ALOGE("Invalid AGC2 Fixed Digital Gain. Error %d\n", status);
+ return EXIT_FAILURE;
+ }
+ if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
+ (uint32_t)preProcCfgParams.agc2Level,
+ effectHandle[PREPROC_AGC2]);
+ status != 0) {
+ ALOGE("Invalid AGC2 Level Estimator. Error %d\n", status);
+ return EXIT_FAILURE;
+ }
+ if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
+ (float)preProcCfgParams.agc2SaturationMargin,
+ effectHandle[PREPROC_AGC2]);
+ status != 0) {
+ ALOGE("Invalid AGC2 Saturation Margin. Error %d\n", status);
+ return EXIT_FAILURE;
+ }
+ }
+#endif
if (effectEn[PREPROC_NS]) {
if (int status = preProcSetConfigParam(NS_PARAM_LEVEL, (uint32_t)preProcCfgParams.nsLevel,
effectHandle[PREPROC_NS]);
@@ -350,6 +432,16 @@
return EXIT_FAILURE;
}
}
+#ifndef WEBRTC_LEGACY
+ if (effectEn[PREPROC_AEC]) {
+ if (int status = preProcSetConfigParam(AEC_PARAM_MOBILE_MODE, (uint32_t)aecMobileMode,
+ effectHandle[PREPROC_AEC]);
+ status != 0) {
+ ALOGE("Invalid AEC mobile mode value %d\n", status);
+ return EXIT_FAILURE;
+ }
+ }
+#endif
// Process Call
const int frameLength = (int)(preProcCfgParams.samplingFreq * kTenMilliSecVal);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 13e1933..6a8c708 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -922,6 +922,11 @@
firstEntry = false;
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
+ if (mediaTimeUs < 0) {
+ ALOGD("fillAudioBuffer: reset negative media time %.2f secs to zero",
+ mediaTimeUs / 1E6);
+ mediaTimeUs = 0;
+ }
ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b9f9173..44ee2ac 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5834,17 +5834,19 @@
case ACodec::kWhatSetSurface:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
sp<RefBase> obj;
CHECK(msg->findObject("surface", &obj));
status_t err = mCodec->handleSetSurface(static_cast<Surface *>(obj.get()));
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
+ sp<AReplyToken> replyID;
+ if (msg->senderAwaitsResponse(&replyID)) {
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ } else if (err != OK) {
+ mCodec->signalError(OMX_ErrorUndefined, err);
+ }
break;
}
@@ -8353,6 +8355,23 @@
break;
}
+ case kWhatSetSurface:
+ {
+ ALOGV("[%s] Deferring setSurface", mCodec->mComponentName.c_str());
+
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ mCodec->deferMessage(msg);
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", OK);
+ response->postReply(replyID);
+
+ handled = true;
+ break;
+ }
+
case kWhatCheckIfStuck:
{
int32_t generation = 0;
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 965b6dd..e783578 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -121,15 +121,23 @@
false /*allocRotated*/, true /*metaOnly*/);
}
+bool isAvif(const sp<MetaData> &trackMeta) {
+ const char *mime;
+ return trackMeta->findCString(kKeyMIMEType, &mime)
+ && (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF));
+}
+
bool findThumbnailInfo(
const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
uint32_t dummyType;
const void *dummyData;
size_t dummySize;
+ int codecConfigKey = isAvif(trackMeta) ? kKeyThumbnailAV1C : kKeyThumbnailHVCC;
return trackMeta->findInt32(kKeyThumbnailWidth, width)
&& trackMeta->findInt32(kKeyThumbnailHeight, height)
- && trackMeta->findData(kKeyThumbnailHVCC,
+ && trackMeta->findData(codecConfigKey,
type ?: &dummyType, data ?: &dummyData, size ?: &dummySize);
}
@@ -752,7 +760,10 @@
overrideMeta->remove(kKeyDisplayHeight);
overrideMeta->setInt32(kKeyWidth, mWidth);
overrideMeta->setInt32(kKeyHeight, mHeight);
- overrideMeta->setData(kKeyHVCC, type, data, size);
+ // The AV1 codec configuration data is passed via CSD0 to the AV1
+ // decoder.
+ const int codecConfigKey = isAvif(trackMeta()) ? kKeyOpaqueCSD0 : kKeyHVCC;
+ overrideMeta->setData(codecConfigKey, type, data, size);
options->setSeekTo(-1);
} else {
CHECK(trackMeta()->findInt32(kKeyWidth, &mWidth));
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 67493f0..48b3255 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -770,6 +770,7 @@
{ "text-format-data", kKeyTextFormatData },
{ "thumbnail-csd-hevc", kKeyThumbnailHVCC },
{ "slow-motion-markers", kKeySlowMotionMarkers },
+ { "thumbnail-csd-av1c", kKeyThumbnailAV1C },
}
};
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
index a11f55e..335846c 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
@@ -24,7 +24,6 @@
#define OSCL_DISABLE_WARNING_CONV_POSSIBLE_LOSS_OF_DATA
-#ifdef PV_SUPPORT_MAIN_PROFILE
/* INTRA */
const static int mpeg_iqmat_def[NCOEFF_BLOCK] =
{
@@ -50,7 +49,6 @@
22, 23, 24, 26, 27, 28, 30, 31,
23, 24, 25, 27, 28, 30, 31, 33
};
-#endif
/* ======================================================================== */
/* Function : CalcNumBits() */
@@ -86,9 +84,7 @@
BitstreamDecVideo *stream;
uint32 tmpvar, vol_shape;
uint32 startCode;
-#ifdef PV_SUPPORT_MAIN_PROFILE
int *qmat, i, j;
-#endif
int version_id = 1;
#ifdef PV_TOLERATE_VOL_ERRORS
uint32 profile = 0x01;
@@ -317,7 +313,8 @@
}
else
{
- if (tmpvar != 0x01) return PV_FAIL;
+ // Simple and advanced simple (for quant-type 1)
+ if (tmpvar != 0x01 && tmpvar != 0x11) return PV_FAIL;
}
/* version id specified? */
@@ -486,7 +483,6 @@
currVol->quantType = BitstreamRead1Bits(stream);
if (currVol->quantType)
{
-#ifdef PV_SUPPORT_MAIN_PROFILE
/* load quantization matrices. 5/22/2000 */
/* load_intra_quant_mat (1 bit) */
qmat = currVol->iqmat;
@@ -531,9 +527,6 @@
{
oscl_memcpy(qmat, mpeg_nqmat_def, 64*sizeof(int));
}
-#else
- return PV_FAIL;
-#endif
}
if (version_id != 1)
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
index 47e10ca..f572b0c 100755
--- a/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="Mpeg4H263DecoderTest->/data/local/tmp/Mpeg4H263DecoderTest" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip?unzip=true"
value="/data/local/tmp/Mpeg4H263DecoderTestRes/" />
</target_preparer>
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
index 967c1ea..53d66ea 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
@@ -404,6 +404,9 @@
make_tuple("swirl_352x288_h263.h263", "swirl_352x288_h263.info", false),
make_tuple("bbb_352x288_h263.h263", "bbb_352x288_h263.info", false),
make_tuple("bbb_352x288_mpeg4.m4v", "bbb_352x288_mpeg4.info", true),
+ make_tuple("qtype0_mpeg4.m4v", "qtype0_mpeg4.info", true),
+ make_tuple("qtype1_mpeg4.m4v", "qtype1_mpeg4.info", true),
+ make_tuple("qtype1_qmatrix_mpeg4.m4v", "qtype1_qmatrix_mpeg4.info", true),
make_tuple("swirl_128x128_mpeg4.m4v", "swirl_128x128_mpeg4.info", true),
make_tuple("swirl_130x132_mpeg4.m4v", "swirl_130x132_mpeg4.info", true),
make_tuple("swirl_132x130_mpeg4.m4v", "swirl_132x130_mpeg4.info", true),
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/README.md b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
index 7e4aea1..38ac567 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/test/README.md
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
@@ -22,7 +22,8 @@
adb push ${OUT}/data/nativetest/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip).
+Download, unzip and push these files into device for testing.
```
adb push Mpeg4H263Decoder /data/local/tmp/
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp b/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
index 56fc782..778dafb 100644
--- a/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
@@ -18,25 +18,24 @@
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
-cc_fuzz {
- name: "mpeg4_dec_fuzzer",
+cc_defaults {
+ name: "mpeg4_h263_dec_fuzz_defaults",
+
host_supported: true,
+
srcs: [
"mpeg4_h263_dec_fuzzer.cpp",
],
+
static_libs: [
"libstagefright_m4vh263dec",
"liblog",
],
+
cflags: [
"-DOSCL_IMPORT_REF=",
- "-DMPEG4",
],
- target: {
- darwin: {
- enabled: false,
- },
- },
+
fuzz_config: {
cc: [
"android-media-fuzzing-reports@google.com",
@@ -46,23 +45,45 @@
}
cc_fuzz {
- name: "h263_dec_fuzzer",
- host_supported: true,
- srcs: [
- "mpeg4_h263_dec_fuzzer.cpp",
+ name: "mpeg4_dec_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_dec_fuzz_defaults",
],
- static_libs: [
- "libstagefright_m4vh263dec",
+
+ cflags: [
+ "-DMPEG4",
+ ],
+}
+
+cc_fuzz {
+ name: "h263_dec_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_dec_fuzz_defaults",
+ ],
+}
+
+cc_defaults {
+ name: "mpeg4_h263_enc_fuzz_defaults",
+
+ host_supported: true,
+
+ srcs: ["mpeg4_h263_enc_fuzzer.cpp"],
+
+ shared_libs: [
+ "libutils",
"liblog",
],
- cflags: [
- "-DOSCL_IMPORT_REF=",
+
+ static_libs: [
+ "libstagefright_m4vh263enc",
],
- target: {
- darwin: {
- enabled: false,
- },
- },
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
fuzz_config: {
cc: [
"android-media-fuzzing-reports@google.com",
@@ -70,3 +91,21 @@
componentid: 155276,
},
}
+
+cc_fuzz {
+ name: "mpeg4_enc_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_enc_fuzz_defaults",
+ ],
+
+ cflags: ["-DMPEG4"],
+}
+
+cc_fuzz {
+ name: "h263_enc_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_enc_fuzz_defaults",
+ ],
+}
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/README.md b/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
index c2a4f69..ad4ff97 100644
--- a/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
@@ -52,6 +52,107 @@
$ $ANDROID_HOST_OUT/fuzz/x86_64/h263_dec_fuzzer/h263_dec_fuzzer CORPUS_DIR
```
+# Fuzzer for libstagefright_m4vh263enc encoder
+
+## Plugin Design Considerations
+The fuzzer plugin for MPEG4/H263 is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+MPEG4/H263 supports the following parameters:
+1. Frame Width (parameter name: `encWidth`)
+2. Frame Height (parameter name: `encHeight`)
+3. Rate control mode (parameter name: `rcType`)
+4. Number of bytes per packet (parameter name: `packetSize`)
+5. Qp for I-Vop(parameter name: `iQuant`)
+6. Qp for P-Vop (parameter name: `pQuant`)
+7. Enable RVLC mode (parameter name: `rvlcEnable`)
+8. Quantization mode (parameter name: `quantType`)
+9. Disable frame skipping (parameter name: `noFrameSkipped`)
+10. Enable scene change detection (parameter name: `sceneDetect`)
+11. Number of intra MBs in P-frame(parameter name: `numIntraMB`)
+12. Search range of ME (parameter name: `searchRange`)
+13. Enable 8x8 ME and MC (parameter name: `mv8x8Enable`)
+14. Enable AC prediction (parameter name: `useACPred`)
+15. Threshold for intra DC VLC (parameter name: `intraDCVlcTh`)
+16. Encoding Mode (parameter name: `encMode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `rcType` | 0. `CONSTANT_Q` 1. `CBR_1` 2. `VBR_1` 3. `CBR_2` 4. `VBR_2` 5. `CBR_LOWDELAY` | All the bits of 6th byte of data modulus 6 |
+| `packetSize` | In the range `0 to 255` | All the bits of 7th byte of data |
+| `iQuant` | In the range `1 to 31` | All the bits of 8th byte of data |
+| `pQuant` | In the range `1 to 31` | All the bits of 9th byte of data |
+| `rvlcEnable` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 10th byte of data |
+| `quantType` | 0. `0` 1. `1` | bit 0 of 11th byte of data |
+| `noFrameSkipped` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 12th byte of data |
+| `sceneDetect` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 13th byte of data |
+| `numIntraMB` | In the range `0 to 7` | bit 0, 1 and 2 of 14th byte of data |
+| `searchRange` | In the range `0 to 31` | bit 0, 1, 2, 3 and 4 of 15th byte of data |
+| `mv8x8Enable` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 16th byte of data |
+| `useACPred` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 17th byte of data |
+| `intraDCVlcTh` | In the range `0 to 7` | bit 0, 1 and 2 of 18th byte of data |
+
+Following parameters are only for mpeg4_enc_fuzzer
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `encWidth` | In the range `0 to 10239` | All the bits of 1st and 2nd byte of data |
+| `encHeight` | In the range `0 to 10239` | All the bits of 3rd and 4th byte of data |
+| `encMode` | 0. `H263_MODE` 1. `H263_MODE_WITH_ERR_RES` 2. `DATA_PARTITIONING_MODE` 3. `COMBINE_MODE_NO_ERR_RES` 4. `COMBINE_MODE_WITH_ERR_RES` | All the bits of 19th byte of data modulus 5 |
+
+Following parameters are only for h263_enc_fuzzer
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `encWidth` | 0. `128` 1. `176` 2. `352` 3. `704` 4. `1408` | All the bits of 1st byte of data modulus 5|
+| `encHeight` | 0. `96` 1. `144` 2. `288` 3. `576` 4. `1152 ` | All the bits of 3rd byte of data modulus 5|
+| `encMode` | 0. `SHORT_HEADER` 1. `SHORT_HEADER_WITH_ERR_RES` | All the bits of 19th byte of data modulus 2 |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the encode operation was successful, the input is advanced by the frame size.
+If the encode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build mpeg4_enc_fuzzer and h263_enc_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) mpeg4_enc_fuzzer
+ $ mm -j$(nproc) h263_enc_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some yuv files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/m4v_h263_enc_fuzzer/m4v_h263_enc_fuzzer CORPUS_DIR
+ $ adb shell /data/fuzz/arm64/h263_enc_fuzzer/h263_enc_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/mpeg4_enc_fuzzer/mpeg4_enc_fuzzer CORPUS_DIR
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/h263_enc_fuzzer/h263_enc_fuzzer CORPUS_DIR
+```
+
## References:
* http://llvm.org/docs/LibFuzzer.html
* https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_enc_fuzzer.cpp b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_enc_fuzzer.cpp
new file mode 100644
index 0000000..f154706
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_enc_fuzzer.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2020 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 <algorithm>
+#include "mp4enc_api.h"
+
+constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;
+constexpr MP4RateControlType krcType[] = {CONSTANT_Q, CBR_1, VBR_1, CBR_2, VBR_2, CBR_LOWDELAY};
+#ifdef MPEG4
+constexpr MP4EncodingMode kEncodingMode[] = {SHORT_HEADER, SHORT_HEADER_WITH_ERR_RES,
+ DATA_PARTITIONING_MODE, COMBINE_MODE_NO_ERR_RES,
+ COMBINE_MODE_WITH_ERR_RES};
+constexpr size_t kMaxWidth = 10240;
+constexpr size_t kMaxHeight = 10240;
+#else
+constexpr MP4EncodingMode kEncodingMode[] = {H263_MODE, H263_MODE_WITH_ERR_RES};
+constexpr int kWidth[] = {128, 176, 352, 704, 1408};
+constexpr int kHeight[] = {96, 144, 288, 576, 1152};
+constexpr size_t kWidthNum = std::size(kWidth);
+constexpr size_t kHeightNum = std::size(kHeight);
+#endif
+
+constexpr size_t krcTypeNum = std::size(krcType);
+constexpr size_t kEncodingModeNum = std::size(kEncodingMode);
+constexpr size_t kMaxQP = 51;
+
+enum {
+ IDX_WD_BYTE_1,
+ IDX_WD_BYTE_2,
+ IDX_HT_BYTE_1,
+ IDX_HT_BYTE_2,
+ IDX_FRAME_RATE,
+ IDX_RC_TYPE,
+ IDX_PACKET_SIZE,
+ IDX_I_FRAME_QP,
+ IDX_P_FRAME_QP,
+ IDX_ENABLE_RVLC,
+ IDX_QUANT_TYPE,
+ IDX_NO_FRAME_SKIPPED_FLAG,
+ IDX_ENABLE_SCENE_DETECT,
+ IDX_NUM_INTRA_MB,
+ IDX_SEARCH_RANGE,
+ IDX_ENABLE_MV_8x8,
+ IDX_USE_AC_PRED,
+ IDX_INTRA_DC_VLC_THRESHOLD,
+ IDX_ENC_MODE,
+ IDX_LAST
+};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitEncoder(); }
+ bool initEncoder(const uint8_t *data);
+ void encodeFrames(const uint8_t *data, size_t size);
+ void deInitEncoder();
+
+ private:
+ int32_t mFrameWidth = 352;
+ int32_t mFrameHeight = 288;
+ float mFrameRate = 25.0f;
+ VideoEncOptions *mEncodeHandle = nullptr;
+ VideoEncControls *mEncodeControl = nullptr;
+};
+
+bool Codec::initEncoder(const uint8_t *data) {
+ mEncodeHandle = new VideoEncOptions;
+ if (!mEncodeHandle) {
+ return false;
+ }
+ memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
+ mEncodeControl = new VideoEncControls;
+ if (!mEncodeControl) {
+ return false;
+ }
+ memset(mEncodeControl, 0, sizeof(VideoEncControls));
+ PVGetDefaultEncOption(mEncodeHandle, 0);
+
+#ifdef MPEG4
+ mFrameWidth = ((data[IDX_WD_BYTE_1] << 8) | data[IDX_WD_BYTE_2]) % kMaxWidth;
+ mFrameHeight = ((data[IDX_HT_BYTE_1] << 8) | data[IDX_HT_BYTE_2]) % kMaxHeight;
+#else
+ mFrameWidth = kWidth[data[IDX_WD_BYTE_1] % kWidthNum];
+ mFrameHeight = kHeight[data[IDX_HT_BYTE_1] % kHeightNum];
+#endif
+ mFrameRate = data[IDX_FRAME_RATE];
+ mEncodeHandle->rcType = krcType[data[IDX_RC_TYPE] % krcTypeNum];
+ mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
+ mEncodeHandle->packetSize = data[IDX_PACKET_SIZE];
+ mEncodeHandle->iQuant[0] = (data[IDX_I_FRAME_QP] % kMaxQP) + 1;
+ mEncodeHandle->pQuant[0] = (data[IDX_P_FRAME_QP] % kMaxQP) + 1;
+ mEncodeHandle->rvlcEnable = (data[IDX_ENABLE_RVLC] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->quantType[0] = (data[IDX_QUANT_TYPE] & 0x01) ? 0 : 1;
+ mEncodeHandle->noFrameSkipped = (data[IDX_NO_FRAME_SKIPPED_FLAG] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->sceneDetect = (data[IDX_ENABLE_SCENE_DETECT] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->numIntraMB = data[IDX_NUM_INTRA_MB] & 0x07;
+ mEncodeHandle->searchRange = data[IDX_SEARCH_RANGE] & 0x1F;
+ mEncodeHandle->mv8x8Enable = (data[IDX_ENABLE_MV_8x8] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->useACPred = (data[IDX_USE_AC_PRED] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->intraDCVlcTh = data[IDX_INTRA_DC_VLC_THRESHOLD] & 0x07;
+ mEncodeHandle->encMode = kEncodingMode[data[IDX_ENC_MODE] % kEncodingModeNum];
+ mEncodeHandle->encWidth[0] = mFrameWidth;
+ mEncodeHandle->encHeight[0] = mFrameHeight;
+ mEncodeHandle->encFrameRate[0] = mFrameRate;
+ mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
+ mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
+ if (!PVInitVideoEncoder(mEncodeControl, mEncodeHandle)) {
+ return false;
+ }
+ return true;
+}
+
+void Codec::deInitEncoder() {
+ if (mEncodeControl) {
+ PVCleanUpVideoEncoder(mEncodeControl);
+ delete mEncodeControl;
+ mEncodeControl = nullptr;
+ }
+ if (mEncodeHandle) {
+ delete mEncodeHandle;
+ mEncodeHandle = nullptr;
+ }
+}
+
+void Codec::encodeFrames(const uint8_t *data, size_t size) {
+ size_t inputBufferSize = (mFrameWidth * mFrameHeight * 3) / 2;
+ size_t outputBufferSize = inputBufferSize * 2;
+ uint8_t outputBuffer[outputBufferSize];
+
+ // Get VOL header.
+ int32_t sizeOutputBuffer = outputBufferSize;
+ PVGetVolHeader(mEncodeControl, outputBuffer, &sizeOutputBuffer, 0);
+
+ size_t numFrame = 0;
+ while (size > 0) {
+ size_t bytesConsumed = std::min(size, inputBufferSize);
+ uint8_t inputBuffer[inputBufferSize];
+ memcpy(inputBuffer, data, bytesConsumed);
+ if (bytesConsumed < sizeof(inputBuffer)) {
+ memset(inputBuffer + bytesConsumed, data[0], sizeof(inputBuffer) - bytesConsumed);
+ }
+ VideoEncFrameIO videoIn{}, videoOut{};
+ videoIn.height = mFrameHeight;
+ videoIn.pitch = mFrameWidth;
+ videoIn.timestamp = (numFrame * 1000) / mFrameRate;
+ videoIn.yChan = inputBuffer;
+ videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
+ videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
+ uint32_t modTimeMs = 0;
+ int32_t dataLength = outputBufferSize;
+ int32_t nLayer = 0;
+ PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, outputBuffer,
+ &dataLength, &nLayer);
+ MP4HintTrack hintTrack;
+ PVGetHintTrack(mEncodeControl, &hintTrack);
+ PVGetOverrunBuffer(mEncodeControl);
+ ++numFrame;
+ data += bytesConsumed;
+ size -= bytesConsumed;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < IDX_LAST) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initEncoder(data)) {
+ data += IDX_LAST;
+ size -= IDX_LAST;
+ codec->encodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 6b0d28f..f260510 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -62,6 +62,7 @@
kKeyDVCC = 'dvcc', // raw data
kKeyAV1C = 'av1c', // raw data
kKeyThumbnailHVCC = 'thvc', // raw data
+ kKeyThumbnailAV1C = 'tav1', // raw data
kKeyD263 = 'd263', // raw data
kKeyOpusHeader = 'ohdr', // raw data
kKeyOpusCodecDelay = 'ocod', // uint64_t (codec delay in ns)
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 3be5e74..dbdb43c 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -493,7 +493,7 @@
mPath(path),
mStatus(NO_INIT) {
// determine href_base
- std::string::size_type end = path.rfind("/");
+ std::string::size_type end = path.rfind('/');
if (end != std::string::npos) {
mHrefBase = path.substr(0, end + 1);
}
diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/MtpFfsHandleTest/Android.bp
similarity index 71%
copy from media/mtp/tests/Android.bp
copy to media/mtp/tests/MtpFfsHandleTest/Android.bp
index 0750208..e393067 100644
--- a/media/mtp/tests/Android.bp
+++ b/media/mtp/tests/MtpFfsHandleTest/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2020 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.
@@ -30,18 +30,3 @@
],
}
-cc_test {
- name: "posix_async_io_test",
- test_suites: ["device-tests"],
- srcs: ["PosixAsyncIO_test.cpp"],
- shared_libs: [
- "libbase",
- "libmtp",
- "liblog",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/MtpFfsHandleTest/AndroidTest.xml
similarity index 95%
rename from media/mtp/tests/AndroidTest.xml
rename to media/mtp/tests/MtpFfsHandleTest/AndroidTest.xml
index c1f4753..38bab27 100644
--- a/media/mtp/tests/AndroidTest.xml
+++ b/media/mtp/tests/MtpFfsHandleTest/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2020 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.
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandleTest/MtpFfsHandle_test.cpp
similarity index 100%
rename from media/mtp/tests/MtpFfsHandle_test.cpp
rename to media/mtp/tests/MtpFfsHandleTest/MtpFfsHandle_test.cpp
diff --git a/media/mtp/tests/MtpFuzzer/Android.bp b/media/mtp/tests/MtpFuzzer/Android.bp
new file mode 100644
index 0000000..9cd4669
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/Android.bp
@@ -0,0 +1,31 @@
+cc_fuzz {
+ name: "mtp_fuzzer",
+ srcs: [
+ "mtp_fuzzer.cpp",
+ "MtpMockDatabase.cpp",
+ ],
+ shared_libs: [
+ "libmtp",
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-DMTP_DEVICE",
+ "-Wno-unused-parameter",
+ ],
+ dictionary: "mtp_fuzzer.dict",
+ corpus: ["corpus/*"],
+
+ fuzz_config: {
+
+ cc: ["jameswei@google.com"],
+ componentid: 1344,
+ acknowledgement: [
+ "Grant Hernandez of Google",
+ ],
+ },
+}
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
new file mode 100644
index 0000000..5d95aa2
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2020 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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <string>
+
+#define LOG_TAG "MtpFuzzer"
+
+#include <log/log.h>
+
+#include "MtpDebug.h"
+#include "MtpMockDatabase.h"
+#include "MtpObjectInfo.h"
+
+namespace android {
+
+MtpMockDatabase::MtpMockDatabase() : mLastObjectHandle(0) {}
+
+MtpMockDatabase::~MtpMockDatabase() {
+ for (MtpObjectInfo* i : mObjects) {
+ delete i;
+ }
+ mObjects.clear();
+}
+
+void MtpMockDatabase::addObject(MtpObjectInfo* info) {
+ assert(hasStorage(info->storageID));
+
+ // we take ownership
+ mObjects.push_back(info);
+
+ return;
+}
+
+MtpObjectHandle MtpMockDatabase::allocateObjectHandle() {
+ // this is in sync with our mObjects database
+ return mLastObjectHandle++;
+}
+
+// Called from SendObjectInfo to reserve a database entry for the incoming file.
+MtpObjectHandle MtpMockDatabase::beginSendObject(const char* path, MtpObjectFormat format,
+ MtpObjectHandle parent, MtpStorageID storage) {
+ if (!hasStorage(storage)) {
+ ALOGW("%s: Tried to lookup storageID %u, but doesn't exist\n", __func__, storage);
+ return kInvalidObjectHandle;
+ }
+
+ ALOGD("MockDatabase %s: path=%s oformat=0x%04x parent_handle=%u "
+ "storage_id=%u\n",
+ __func__, path, format, parent, storage);
+
+ return mLastObjectHandle;
+}
+
+// Called to report success or failure of the SendObject file transfer.
+void MtpMockDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
+}
+
+// Called to rescan a file, such as after an edit.
+void MtpMockDatabase::rescanFile(const char* path, MtpObjectHandle handle, MtpObjectFormat format) {
+ ALOGD("MockDatabase %s: path=%s ohandle=%u, oformat=0x%04x\n", __func__, path, handle, format);
+}
+
+MtpObjectHandleList* MtpMockDatabase::getObjectList(MtpStorageID storageID, MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ ALOGD("MockDatabase %s: storage_id=%u oformat=0x%04x ohandle=%u\n", __func__, storageID, format,
+ parent);
+ return nullptr;
+}
+
+int MtpMockDatabase::getNumObjects(MtpStorageID storageID, MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ ALOGD("MockDatabase %s: storage_id=%u oformat=0x%04x ohandle=%u\n", __func__, storageID, format,
+ parent);
+ // TODO: return MTP_RESPONSE_OK when it stops segfaulting
+ return 0;
+}
+
+// callee should delete[] the results from these
+// results can be NULL
+MtpObjectFormatList* MtpMockDatabase::getSupportedPlaybackFormats() {
+ ALOGD("MockDatabase %s\n", __func__);
+ return nullptr;
+}
+MtpObjectFormatList* MtpMockDatabase::getSupportedCaptureFormats() {
+ ALOGD("MockDatabase %s\n", __func__);
+ return nullptr;
+}
+MtpObjectPropertyList* MtpMockDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
+ ALOGD("MockDatabase %s: oformat=0x%04x\n", __func__, format);
+ return nullptr;
+}
+MtpDevicePropertyList* MtpMockDatabase::getSupportedDeviceProperties() {
+ ALOGD("MockDatabase %s\n", __func__);
+ return nullptr;
+}
+
+MtpResponseCode MtpMockDatabase::getObjectPropertyValue(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: ohandle=%u property=%s\n", __func__, handle,
+ MtpDebug::getObjectPropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::setObjectPropertyValue(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: ohandle=%u property=%s\n", __func__, handle,
+ MtpDebug::getObjectPropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::getDevicePropertyValue(MtpDeviceProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::setDevicePropertyValue(MtpDeviceProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::resetDeviceProperty(MtpDeviceProperty property) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::getObjectPropertyList(MtpObjectHandle handle, uint32_t format,
+ uint32_t property, int groupCode, int depth,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: ohandle=%u format=%s property=%s groupCode=%d "
+ "depth=%d\n",
+ __func__, handle, MtpDebug::getFormatCodeName(format),
+ MtpDebug::getObjectPropCodeName(property), groupCode, depth);
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+
+ // used for the root
+ if (handle == kInvalidObjectHandle) {
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ } else {
+ if (mObjects.size() == 0) {
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ // this is used to let the fuzzer make progress, otherwise
+ // it has to brute-force a 32-bit handle
+ MtpObjectHandle reducedHandle = handle % mObjects.size();
+ MtpObjectInfo* obj = mObjects[reducedHandle];
+
+ // make a copy, but make sure to maintain ownership of string pointers
+ info = *obj;
+
+ // fixup the response handle
+ info.mHandle = handle;
+
+ if (obj->mName) info.mName = strdup(obj->mName);
+ if (obj->mKeywords) info.mKeywords = strdup(obj->mKeywords);
+
+ return MTP_RESPONSE_OK;
+ }
+}
+
+void* MtpMockDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+
+ size_t allocSize = handle % 0x1000;
+ void* data = calloc(allocSize, sizeof(uint8_t));
+ if (!data) {
+ return nullptr;
+ } else {
+ ALOGD("MockDatabase %s\n", __func__);
+ outThumbSize = allocSize;
+ return data;
+ }
+}
+
+MtpResponseCode MtpMockDatabase::getObjectFilePath(MtpObjectHandle handle,
+ MtpStringBuffer& outFilePath,
+ int64_t& outFileLength,
+ MtpObjectFormat& outFormat) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+
+ if (mObjects.size() == 0) {
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ // this is used to let the fuzzer make progress, otherwise
+ // it has to brute-force a 32-bit handle
+ MtpObjectHandle reducedHandle = handle % mObjects.size();
+ MtpObjectInfo* obj = mObjects[reducedHandle];
+ MtpStorage* storage = mStorage[obj->mStorageID];
+
+ // walk up the tree to build a full path of the object
+ MtpObjectHandle currentHandle = reducedHandle;
+ std::string path = "";
+
+ while (currentHandle != MTP_PARENT_ROOT) {
+ MtpObjectInfo* next = mObjects[currentHandle];
+
+ // prepend the name
+ if (path == "")
+ path = std::string(next->mName);
+ else
+ path = std::string(next->mName) + "/" + path;
+
+ currentHandle = next->mParent;
+ }
+
+ outFilePath.set(storage->getPath());
+ outFilePath.append("/");
+ outFilePath.append(path.c_str());
+
+ outFormat = obj->mFormat;
+
+ ALOGD("MockDatabase %s: get file %s\n", __func__, (const char*)outFilePath);
+
+ struct stat sstat;
+ // this should not happen unless our database view of the filesystem is out of
+ // sync
+ if (stat((const char*)outFilePath, &sstat) < 0) {
+ ALOGE("MockDatabase %s: unable to stat %s\n", __func__, (const char*)outFilePath);
+
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ outFileLength = sstat.st_size;
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::beginDeleteObject(MtpObjectHandle handle) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+ return MTP_RESPONSE_OK;
+}
+void MtpMockDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
+ return;
+}
+
+MtpObjectHandleList* MtpMockDatabase::getObjectReferences(MtpObjectHandle handle) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+ return nullptr;
+}
+
+MtpResponseCode MtpMockDatabase::setObjectReferences(MtpObjectHandle handle,
+ MtpObjectHandleList* references) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+ return MTP_RESPONSE_OK;
+}
+
+MtpProperty* MtpMockDatabase::getObjectPropertyDesc(MtpObjectProperty property,
+ MtpObjectFormat format) {
+ ALOGD("MockDatabase %s: property=%s format=%s\n", __func__,
+ MtpDebug::getObjectPropCodeName(property), MtpDebug::getFormatCodeName(format));
+
+ return nullptr;
+}
+
+MtpProperty* MtpMockDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return nullptr;
+}
+
+MtpResponseCode MtpMockDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage) {
+ ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
+ newStorage);
+ return MTP_RESPONSE_OK;
+}
+
+void MtpMockDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
+ MtpStorageID oldStorage, MtpStorageID newStorage,
+ MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: oldParent=%u newParent=%u oldStorage=%u newStorage=%u "
+ "ohandle=%u succeeded=%d\n",
+ __func__, oldParent, newParent, oldStorage, newStorage, handle, succeeded);
+ return;
+}
+
+MtpResponseCode MtpMockDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage) {
+ ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
+ newStorage);
+ return MTP_RESPONSE_OK;
+}
+
+void MtpMockDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
+}
+
+}; // namespace android
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockDatabase.h b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.h
new file mode 100644
index 0000000..876719e
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+#ifndef _MTP_MOCK_DATABASE_H
+#define _MTP_MOCK_DATABASE_H
+
+#include <map>
+
+#include "IMtpDatabase.h"
+#include "MtpStorage.h"
+
+namespace android {
+
+class MtpMockDatabase : public IMtpDatabase {
+ std::map<MtpStorageID, MtpStorage*> mStorage;
+ std::vector<MtpObjectInfo*> mObjects;
+ uint32_t mLastObjectHandle;
+
+public:
+ MtpMockDatabase();
+ virtual ~MtpMockDatabase();
+
+ // MtpFuzzer methods
+ void addStorage(MtpStorage* storage) {
+ // we don't own this
+ mStorage[storage->getStorageID()] = storage;
+ }
+
+ bool hasStorage(MtpStorageID storage) { return mStorage.find(storage) != mStorage.end(); }
+
+ void addObject(MtpObjectInfo* info);
+ MtpObjectHandle allocateObjectHandle();
+
+ // libmtp interface methods
+ // Called from SendObjectInfo to reserve a database entry for the incoming
+ // file.
+ MtpObjectHandle beginSendObject(const char* path, MtpObjectFormat format,
+ MtpObjectHandle parent, MtpStorageID storage);
+
+ // Called to report success or failure of the SendObject file transfer.
+ void endSendObject(MtpObjectHandle handle, bool succeeded);
+
+ // Called to rescan a file, such as after an edit.
+ void rescanFile(const char* path, MtpObjectHandle handle, MtpObjectFormat format);
+
+ MtpObjectHandleList* getObjectList(MtpStorageID storageID, MtpObjectFormat format,
+ MtpObjectHandle parent);
+
+ int getNumObjects(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent);
+
+ // callee should delete[] the results from these
+ // results can be NULL
+ MtpObjectFormatList* getSupportedPlaybackFormats();
+ MtpObjectFormatList* getSupportedCaptureFormats();
+ MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
+ MtpDevicePropertyList* getSupportedDeviceProperties();
+
+ MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet);
+
+ MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet);
+
+ MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
+
+ MtpResponseCode getObjectPropertyList(MtpObjectHandle handle, uint32_t format,
+ uint32_t property, int groupCode, int depth,
+ MtpDataPacket& packet);
+
+ MtpResponseCode getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info);
+
+ void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
+
+ MtpResponseCode getObjectFilePath(MtpObjectHandle handle, MtpStringBuffer& outFilePath,
+ int64_t& outFileLength, MtpObjectFormat& outFormat);
+
+ MtpResponseCode beginDeleteObject(MtpObjectHandle handle);
+ void endDeleteObject(MtpObjectHandle handle, bool succeeded);
+
+ MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
+
+ MtpResponseCode setObjectReferences(MtpObjectHandle handle, MtpObjectHandleList* references);
+
+ MtpProperty* getObjectPropertyDesc(MtpObjectProperty property, MtpObjectFormat format);
+
+ MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
+
+ MtpResponseCode beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage);
+
+ void endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
+ MtpStorageID oldStorage, MtpStorageID newStorage, MtpObjectHandle handle,
+ bool succeeded);
+
+ MtpResponseCode beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage);
+ void endCopyObject(MtpObjectHandle handle, bool succeeded);
+};
+
+}; // namespace android
+
+#endif // _MTP_MOCK_DATABASE_H
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
new file mode 100644
index 0000000..111485c
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef _MTP_MOCK_HANDLE_H
+#define _MTP_MOCK_HANDLE_H
+
+#include <vector>
+
+typedef std::vector<uint8_t> packet_t;
+
+namespace android {
+class MtpMockHandle : public IMtpHandle {
+private:
+ size_t mPacketNumber;
+ size_t mPacketOffset;
+ std::vector<packet_t> mPackets;
+
+public:
+ MtpMockHandle() : mPacketNumber(0), mPacketOffset(0) {}
+
+ void add_packet(packet_t pkt) { mPackets.push_back(pkt); }
+
+ // Return number of bytes read/written, or -1 and errno is set
+ int read(void *data, size_t len) {
+ if (mPacketNumber >= mPackets.size()) {
+ return 0;
+ } else {
+ int readAmt = 0;
+ packet_t pkt = mPackets[mPacketNumber];
+
+ ALOGD("%s: sz %zu, pkt %zu+%zu/%zu\n", __func__, len, mPacketNumber, mPacketOffset,
+ pkt.size());
+
+ // packet is bigger than what the caller can handle,
+ if (pkt.size() > len) {
+ memcpy(data, pkt.data() + mPacketOffset, len);
+
+ mPacketOffset += len;
+ readAmt = len;
+ // packet is equal or smaller than the caller buffer
+ } else {
+ memcpy(data, pkt.data() + mPacketOffset, pkt.size());
+
+ mPacketNumber++;
+ mPacketOffset = 0;
+ readAmt = pkt.size();
+ }
+
+ return readAmt;
+ }
+ }
+ int write(const void *data, size_t len) {
+ ALOGD("MockHandle %s: len=%zu\n", __func__, len);
+ // fake the write
+ return len;
+ }
+
+ // Return 0 if send/receive is successful, or -1 and errno is set
+ int receiveFile(mtp_file_range mfr, bool zero_packet) {
+ ALOGD("MockHandle %s\n", __func__);
+ return 0;
+ }
+ int sendFile(mtp_file_range mfr) {
+ ALOGD("MockHandle %s\n", __func__);
+ return 0;
+ }
+ int sendEvent(mtp_event me) {
+ ALOGD("MockHandle %s: len=%zu\n", __func__, me.length);
+ return 0;
+ }
+
+ // Return 0 if operation is successful, or -1 else
+ int start(bool ptp) { return 0; }
+
+ void close() {}
+
+ virtual ~MtpMockHandle() {}
+};
+}; // namespace android
+
+#endif // _MTP_MOCK_HANDLE_H
diff --git a/media/mtp/tests/MtpFuzzer/corpus/1-mtp-open_session.pkt b/media/mtp/tests/MtpFuzzer/corpus/1-mtp-open_session.pkt
new file mode 100644
index 0000000..38f8ed2
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/1-mtp-open_session.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/2-mtp-get_device_info.pkt b/media/mtp/tests/MtpFuzzer/corpus/2-mtp-get_device_info.pkt
new file mode 100644
index 0000000..7759380
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/2-mtp-get_device_info.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/3-mtp-get_object_handles.pkt b/media/mtp/tests/MtpFuzzer/corpus/3-mtp-get_object_handles.pkt
new file mode 100644
index 0000000..e88410f
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/3-mtp-get_object_handles.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/4-mtp-get_object_info.pkt b/media/mtp/tests/MtpFuzzer/corpus/4-mtp-get_object_info.pkt
new file mode 100644
index 0000000..e283fb4
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/4-mtp-get_object_info.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/5-mtp-send_object_info.pkt b/media/mtp/tests/MtpFuzzer/corpus/5-mtp-send_object_info.pkt
new file mode 100644
index 0000000..7627f88
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/5-mtp-send_object_info.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp
new file mode 100644
index 0000000..f578462
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 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/unique_fd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string>
+
+#define LOG_TAG "MtpFuzzer"
+
+#include "IMtpHandle.h"
+#include "MtpMockDatabase.h"
+#include "MtpMockHandle.h"
+#include "MtpObjectInfo.h"
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "MtpUtils.h"
+
+const char* storage_desc = "Fuzz Storage";
+// prefer tmpfs for file operations to avoid wearing out flash
+const char* storage_path = "/storage/fuzzer/0";
+const char* source_database = "srcdb/";
+
+namespace android {
+class MtpMockServer {
+public:
+ std::unique_ptr<MtpMockHandle> mHandle;
+ std::unique_ptr<MtpStorage> mStorage;
+ std::unique_ptr<MtpMockDatabase> mDatabase;
+ std::unique_ptr<MtpServer> mMtp;
+ int mStorageId;
+
+ MtpMockServer(const char* storage_path) : mStorageId(0) {
+ bool ptp = false;
+ const char* manu = "Google";
+ const char* model = "Pixel 3XL";
+ const char* version = "1.0";
+ const char* serial = "ABDEF1231";
+
+ // This is unused in our harness
+ int controlFd = -1;
+
+ mHandle = std::make_unique<MtpMockHandle>();
+ mStorage = std::make_unique<MtpStorage>(mStorageId, storage_path, storage_desc, true,
+ 0x200000000L);
+ mDatabase = std::make_unique<MtpMockDatabase>();
+ mDatabase->addStorage(mStorage.get());
+
+ mMtp = std::make_unique<MtpServer>(mDatabase.get(), controlFd, ptp, manu, model, version,
+ serial);
+ mMtp->addStorage(mStorage.get());
+
+ // clear the old handle first, so we don't leak memory
+ delete mMtp->mHandle;
+ mMtp->mHandle = mHandle.get();
+ }
+
+ void run() { mMtp->run(); }
+
+ int createDatabaseFromSourceDir(const char* fromPath, const char* toPath,
+ MtpObjectHandle parentHandle) {
+ int ret = 0;
+ std::string fromPathStr(fromPath);
+ std::string toPathStr(toPath);
+
+ DIR* dir = opendir(fromPath);
+ if (!dir) {
+ ALOGE("opendir %s failed", fromPath);
+ return -1;
+ }
+ if (fromPathStr[fromPathStr.size() - 1] != '/') fromPathStr += '/';
+ if (toPathStr[toPathStr.size() - 1] != '/') toPathStr += '/';
+
+ struct dirent* entry;
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+
+ std::string oldFile = fromPathStr + name;
+ std::string newFile = toPathStr + name;
+
+ if (entry->d_type == DT_DIR) {
+ ret += makeFolder(newFile.c_str());
+
+ MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle());
+ objectInfo->mStorageID = mStorage->getStorageID();
+ objectInfo->mParent = parentHandle;
+ objectInfo->mFormat = MTP_FORMAT_ASSOCIATION; // folder
+ objectInfo->mName = strdup(name);
+ objectInfo->mKeywords = strdup("");
+
+ mDatabase->addObject(objectInfo);
+
+ ret += createDatabaseFromSourceDir(oldFile.c_str(), newFile.c_str(),
+ objectInfo->mHandle);
+ } else {
+ ret += copyFile(oldFile.c_str(), newFile.c_str());
+
+ MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle());
+ objectInfo->mStorageID = mStorage->getStorageID();
+ objectInfo->mParent = parentHandle;
+ objectInfo->mFormat = MTP_FORMAT_TEXT;
+ objectInfo->mName = strdup(name);
+ objectInfo->mKeywords = strdup("");
+
+ mDatabase->addObject(objectInfo);
+ }
+ }
+
+ closedir(dir);
+ return ret;
+ }
+};
+}; // namespace android
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) __attribute__((optnone)) {
+ // reset our storage (from MtpUtils.h)
+ android::deletePath(storage_path);
+ android::makeFolder("/storage/fuzzer");
+ android::makeFolder(storage_path);
+
+ std::unique_ptr<android::MtpMockServer> mtp =
+ std::make_unique<android::MtpMockServer>(storage_path);
+
+ size_t off = 0;
+
+ // Packetize the input stream
+ for (size_t i = 0; i < size; i++) {
+ // A longer delimiter could be used, but this worked in practice
+ if (data[i] == '@') {
+ size_t pktsz = i - off;
+ if (pktsz > 0) {
+ packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i);
+ // insert into packet buffer
+ mtp->mHandle->add_packet(pkt);
+ off = i;
+ }
+ }
+ }
+
+ mtp->createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT);
+ mtp->run();
+
+ return 0;
+}
diff --git a/media/mtp/tests/MtpFuzzer/mtp_fuzzer.dict b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.dict
new file mode 100644
index 0000000..4c3f136
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.dict
@@ -0,0 +1,74 @@
+mtp_operation_get_device_info="\x01\x10"
+mtp_operation_open_session="\x02\x10"
+mtp_operation_close_session="\x03\x10"
+mtp_operation_get_storage_ids="\x04\x10"
+mtp_operation_get_storage_info="\x05\x10"
+mtp_operation_get_num_objects="\x06\x10"
+mtp_operation_get_object_handles="\x07\x10"
+mtp_operation_get_object_info="\x08\x10"
+mtp_operation_get_object="\x09\x10"
+mtp_operation_get_thumb="\x0A\x10"
+mtp_operation_delete_object="\x0B\x10"
+mtp_operation_send_object_info="\x0C\x10"
+mtp_operation_send_object="\x0D\x10"
+mtp_operation_initiate_capture="\x0E\x10"
+mtp_operation_format_store="\x0F\x10"
+mtp_operation_reset_device="\x10\x10"
+mtp_operation_self_test="\x11\x10"
+mtp_operation_set_object_protection="\x12\x10"
+mtp_operation_power_down="\x13\x10"
+mtp_operation_get_device_prop_desc="\x14\x10"
+mtp_operation_get_device_prop_value="\x15\x10"
+mtp_operation_set_device_prop_value="\x16\x10"
+mtp_operation_reset_device_prop_value="\x17\x10"
+mtp_operation_terminate_open_capture="\x18\x10"
+mtp_operation_move_object="\x19\x10"
+mtp_operation_copy_object="\x1A\x10"
+mtp_operation_get_partial_object="\x1B\x10"
+mtp_operation_initiate_open_capture="\x1C\x10"
+mtp_operation_get_object_props_supported="\x01\x98"
+mtp_operation_get_object_prop_desc="\x02\x98"
+mtp_operation_get_object_prop_value="\x03\x98"
+mtp_operation_set_object_prop_value="\x04\x98"
+mtp_operation_get_object_prop_list="\x05\x98"
+mtp_operation_set_object_prop_list="\x06\x98"
+mtp_operation_get_interdependent_prop_desc="\x07\x98"
+mtp_operation_send_object_prop_list="\x08\x98"
+mtp_operation_get_object_references="\x10\x98"
+mtp_operation_set_object_references="\x11\x98"
+mtp_operation_skip="\x20\x98"
+mtp_operation_get_partial_object_64="\xC1\x95"
+mtp_operation_send_partial_object="\xC2\x95"
+mtp_operation_truncate_object="\xC3\x95"
+mtp_operation_begin_edit_object="\xC4\x95"
+mtp_operation_end_edit_object="\xC5\x95"
+
+# Association (for example, a folder)
+mtp_format_association="\x01\x30"
+
+# types
+mtp_type_undefined="\x00\x00"
+mtp_type_int8="\x01\x00"
+mtp_type_uint8="\x02\x00"
+mtp_type_int16="\x03\x00"
+mtp_type_uint16="\x04\x00"
+mtp_type_int32="\x05\x00"
+mtp_type_uint32="\x06\x00"
+mtp_type_int64="\x07\x00"
+mtp_type_uint64="\x08\x00"
+mtp_type_int128="\x09\x00"
+mtp_type_uint128="\x0A\x00"
+mtp_type_aint8="\x01\x40"
+mtp_type_auint8="\x02\x40"
+mtp_type_aint16="\x03\x40"
+mtp_type_auint16="\x04\x40"
+mtp_type_aint32="\x05\x40"
+mtp_type_auint32="\x06\x40"
+mtp_type_aint64="\x07\x40"
+mtp_type_auint64="\x08\x40"
+mtp_type_aint128="\x09\x40"
+mtp_type_auint128="\x0A\x40"
+mtp_type_str="\xFF\xFF"
+
+# also used for max size (>4GB)
+mtp_parent_root="\xFF\xFF\xFF\xFF"
diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/PosixAsyncIOTest/Android.bp
similarity index 71%
rename from media/mtp/tests/Android.bp
rename to media/mtp/tests/PosixAsyncIOTest/Android.bp
index 0750208..1d401b8 100644
--- a/media/mtp/tests/Android.bp
+++ b/media/mtp/tests/PosixAsyncIOTest/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2020 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.
@@ -15,22 +15,6 @@
//
cc_test {
- name: "mtp_ffs_handle_test",
- test_suites: ["device-tests"],
- srcs: ["MtpFfsHandle_test.cpp"],
- shared_libs: [
- "libbase",
- "libmtp",
- "liblog",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
-
-cc_test {
name: "posix_async_io_test",
test_suites: ["device-tests"],
srcs: ["PosixAsyncIO_test.cpp"],
diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/PosixAsyncIOTest/AndroidTest.xml
similarity index 77%
copy from media/mtp/tests/AndroidTest.xml
copy to media/mtp/tests/PosixAsyncIOTest/AndroidTest.xml
index c1f4753..cbb10fb 100644
--- a/media/mtp/tests/AndroidTest.xml
+++ b/media/mtp/tests/PosixAsyncIOTest/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2020 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.
@@ -13,14 +13,14 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for mtp_ffs_handle_test">
+<configuration description="Config for posix_async_io_test">
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
- <option name="push" value="mtp_ffs_handle_test->/data/local/tmp/mtp_ffs_handle_test" />
+ <option name="push" value="posix_async_io_test->/data/local/tmp/posix_async_io_test" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="mtp_ffs_handle_test" />
+ <option name="module-name" value="posix_async_io_test" />
</test>
</configuration>
\ No newline at end of file
diff --git a/media/mtp/tests/PosixAsyncIO_test.cpp b/media/mtp/tests/PosixAsyncIOTest/PosixAsyncIO_test.cpp
similarity index 100%
rename from media/mtp/tests/PosixAsyncIO_test.cpp
rename to media/mtp/tests/PosixAsyncIOTest/PosixAsyncIO_test.cpp
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 73c52a9..47214c5 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -371,6 +371,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
EXPORT const char* AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA = "text-format-data";
+EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C = "thumbnail-csd-av1c";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC = "thumbnail-csd-hevc";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT = "thumbnail-height";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME = "thumbnail-time";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 394b972..8f39929 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -324,6 +324,7 @@
#if __ANDROID_API__ >= 31
extern const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS __INTRODUCED_IN(31);
+extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C __INTRODUCED_IN(31);
#endif /* __ANDROID_API__ >= 31 */
__END_DECLS
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index bd3337e..44c3e52 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -138,6 +138,7 @@
AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID; # var introduced=28
AMEDIAFORMAT_KEY_TEMPORAL_LAYERING; # var introduced=28
AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA; # var introduced=29
+ AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C; # var introduced=31
AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_TIME; # var introduced=29
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 4929346..959e858 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1468,7 +1468,7 @@
}
-void AudioFlinger::broacastParametersToRecordThreads_l(const String8& keyValuePairs)
+void AudioFlinger::broadcastParametersToRecordThreads_l(const String8& keyValuePairs)
{
for (size_t i = 0; i < mRecordThreads.size(); i++) {
mRecordThreads.valueAt(i)->setParameters(keyValuePairs);
@@ -1626,7 +1626,7 @@
int value;
if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) &&
(value != 0)) {
- broacastParametersToRecordThreads_l(filteredKeyValuePairs);
+ broadcastParametersToRecordThreads_l(filteredKeyValuePairs);
}
}
}
@@ -3202,7 +3202,8 @@
// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread)
{
- audio_utils::FdToString fdToString;
+ constexpr int THREAD_DUMP_TIMEOUT_MS = 2;
+ audio_utils::FdToString fdToString("- ", THREAD_DUMP_TIMEOUT_MS);
const int fd = fdToString.fd();
if (fd >= 0) {
thread->dump(fd, {} /* args */);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2ff6af5..cfe9264 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -787,7 +787,7 @@
std::vector< sp<EffectModule> > purgeStaleEffects_l();
- void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
+ void broadcastParametersToRecordThreads_l(const String8& keyValuePairs);
void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
void forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c1c3c44..b13b7be 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7477,7 +7477,7 @@
(framesRead - part1) * mFrameSize);
}
}
- rear = mRsmpInRear += framesRead;
+ mRsmpInRear = audio_utils::safe_add_overflow(mRsmpInRear, (int32_t)framesRead);
size = activeTracks.size();
diff --git a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
index f060d45..5083b14 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
@@ -126,9 +126,9 @@
ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
criteria_pattern = re.compile(
- r"\s*(?P<type>(?:"+'|'.join(component_type_mapping_table.keys()) + "))_" \
- r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
- r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
+ r"\s*V\((?P<type>(?:"+'|'.join(component_type_mapping_table.keys()) + "))_" \
+ r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
+ r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])[0-9a-fA-F]+|[0-9]+)")
logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
@@ -164,6 +164,13 @@
logging.debug("type:{}, literal:{}, values:{}.".format(component_type_name, component_type_literal, component_type_numerical_value))
+ if "stub" not in all_component_types["OutputDevicesMask"]:
+ all_component_types["OutputDevicesMask"]["stub"] = 0x40000000
+ logging.info("added stub output device mask")
+ if "stub" not in all_component_types["InputDevicesMask"]:
+ all_component_types["InputDevicesMask"]["stub"] = 0x40000000
+ logging.info("added stub input device mask")
+
# Transform input source in inclusive criterion
shift = len(all_component_types['OutputDevicesMask'])
if shift > 32:
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index ca03e1f..daedf31 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -45,6 +45,7 @@
cc_test {
name: "audio_health_tests",
+ require_root: true,
shared_libs: [
"libaudiofoundation",
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index b5c67a1..9a62e72 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "AudioPolicy_Boot_Test"
+#include <string>
#include <unordered_set>
#include <gtest/gtest.h>
@@ -74,3 +75,43 @@
ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
}
}
+
+TEST(AudioHealthTest, ConnectSupportedDevice) {
+ AudioPolicyManagerTestClient client;
+ AudioPolicyTestManager manager(&client);
+ manager.loadConfig();
+ ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+
+ DeviceVector devices;
+ for (const auto& hwModule : manager.getConfig().getHwModules()) {
+ for (const auto& profile : hwModule->getOutputProfiles()) {
+ devices.merge(profile->getSupportedDevices());
+ }
+ for (const auto& profile : hwModule->getInputProfiles()) {
+ devices.merge(profile->getSupportedDevices());
+ }
+ }
+ for (const auto& device : devices) {
+ if (!audio_is_bluetooth_out_sco_device(device->type()) &&
+ !audio_is_bluetooth_in_sco_device(device->type())) {
+ // There are two reasons to only test connecting BT devices.
+ // 1) It is easier to construct a fake address.
+ // 2) This test will be run in presubmit. In that case, it makes sense to make the test
+ // processing time short.
+ continue;
+ }
+ std::string address = "11:22:33:44:55:66";
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
+ ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
+ device->type(), AUDIO_POLICY_DEVICE_STATE_AVAILABLE, address.c_str(),
+ "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
+ ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
+ device->type(), AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, address.c_str(),
+ "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
+ }
+}
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index c4c7a85..ee9ed25 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -36,7 +36,6 @@
#include "device3/RotateAndCropMapper.h"
#include "device3/ZoomRatioMapper.h"
#include "utils/TagMonitor.h"
-#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
namespace android {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 889ce86..90f6216 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -182,7 +182,33 @@
return;
}
- insertResultLocked(states, &captureResult, frameNumber);
+ // Update partial result by removing keys remapped by DistortionCorrection, ZoomRatio,
+ // and RotationAndCrop mappers.
+ std::set<uint32_t> keysToRemove;
+
+ auto iter = states.distortionMappers.find(states.cameraId.c_str());
+ if (iter != states.distortionMappers.end()) {
+ const auto& remappedKeys = iter->second.getRemappedKeys();
+ keysToRemove.insert(remappedKeys.begin(), remappedKeys.end());
+ }
+
+ const auto& remappedKeys = states.zoomRatioMappers[states.cameraId.c_str()].getRemappedKeys();
+ keysToRemove.insert(remappedKeys.begin(), remappedKeys.end());
+
+ auto mapper = states.rotateAndCropMappers.find(states.cameraId.c_str());
+ if (mapper != states.rotateAndCropMappers.end()) {
+ const auto& remappedKeys = iter->second.getRemappedKeys();
+ keysToRemove.insert(remappedKeys.begin(), remappedKeys.end());
+ }
+
+ for (uint32_t key : keysToRemove) {
+ captureResult.mMetadata.erase(key);
+ }
+
+ // Send partial result
+ if (captureResult.mMetadata.entryCount() > 0) {
+ insertResultLocked(states, &captureResult, frameNumber);
+ }
}
void sendCaptureResult(
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 9946312..3ebbc17 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -72,8 +72,8 @@
const String8& cameraId;
std::mutex& inflightLock;
int64_t& lastCompletedRegularFrameNumber;
- int64_t& lastCompletedZslFrameNumber;
int64_t& lastCompletedReprocessFrameNumber;
+ int64_t& lastCompletedZslFrameNumber;
InFlightRequestMap& inflightMap; // end of inflightLock scope
std::mutex& outputLock;
std::list<CaptureResult>& resultQueue;
diff --git a/services/camera/libcameraservice/device3/CoordinateMapper.h b/services/camera/libcameraservice/device3/CoordinateMapper.h
index 5164856..558f4c0 100644
--- a/services/camera/libcameraservice/device3/CoordinateMapper.h
+++ b/services/camera/libcameraservice/device3/CoordinateMapper.h
@@ -18,16 +18,23 @@
#define ANDROID_SERVERS_COORDINATEMAPPER_H
#include <array>
+#include <set>
namespace android {
namespace camera3 {
class CoordinateMapper {
- // Right now only stores metadata tags containing 2D coordinates
- // to be corrected.
+public:
+ // The result metadata tags that are to be re-mapped
+ const std::set<uint32_t>& getRemappedKeys() const {
+ return mRemappedKeys;
+ }
+
+ virtual ~CoordinateMapper() = default;
+
protected:
- // Metadata key lists to correct
+ // Metadata tags containing 2D coordinates to be corrected.
// Both capture request and result
static const std::array<uint32_t, 3> kMeteringRegionsToCorrect;
@@ -37,6 +44,10 @@
// Only for capture results; don't clamp
static const std::array<uint32_t, 2> kResultPointsToCorrectNoClamp;
+
+ virtual void initRemappedKeys() = 0;
+ std::set<uint32_t> mRemappedKeys;
+
}; // class CoordinateMapper
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 2f388f2..316303e 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -29,6 +29,20 @@
DistortionMapper::DistortionMapper() : mValidMapping(false), mValidGrids(false) {
+ initRemappedKeys();
+}
+
+void DistortionMapper::initRemappedKeys() {
+ mRemappedKeys.insert(
+ kMeteringRegionsToCorrect.begin(),
+ kMeteringRegionsToCorrect.end());
+ mRemappedKeys.insert(
+ kRectsToCorrect.begin(),
+ kRectsToCorrect.end());
+ mRemappedKeys.insert(
+ kResultPointsToCorrectNoClamp.begin(),
+ kResultPointsToCorrectNoClamp.end());
+ mRemappedKeys.insert(ANDROID_DISTORTION_CORRECTION_MODE);
}
bool DistortionMapper::isDistortionSupported(const CameraMetadata &deviceInfo) {
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.h b/services/camera/libcameraservice/device3/DistortionMapper.h
index 7dcb67b..5027bd0 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.h
+++ b/services/camera/libcameraservice/device3/DistortionMapper.h
@@ -32,7 +32,7 @@
* Utilities to transform between raw (distorted) and warped (corrected) coordinate systems
* for cameras that support geometric distortion
*/
-class DistortionMapper : private CoordinateMapper {
+class DistortionMapper : public CoordinateMapper {
public:
DistortionMapper();
@@ -43,7 +43,10 @@
mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
mActiveWidth(other.mActiveWidth), mActiveHeight(other.mActiveHeight),
mArrayDiffX(other.mArrayDiffX), mArrayDiffY(other.mArrayDiffY),
- mCorrectedGrid(other.mCorrectedGrid), mDistortedGrid(other.mDistortedGrid) {}
+ mCorrectedGrid(other.mCorrectedGrid), mDistortedGrid(other.mDistortedGrid) {
+ initRemappedKeys(); }
+
+ void initRemappedKeys() override;
/**
* Check whether distortion correction is supported by the camera HAL
diff --git a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
index 3718f54..a02e5f6 100644
--- a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
+++ b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
@@ -27,6 +27,18 @@
namespace camera3 {
+void RotateAndCropMapper::initRemappedKeys() {
+ mRemappedKeys.insert(
+ kMeteringRegionsToCorrect.begin(),
+ kMeteringRegionsToCorrect.end());
+ mRemappedKeys.insert(
+ kResultPointsToCorrectNoClamp.begin(),
+ kResultPointsToCorrectNoClamp.end());
+
+ mRemappedKeys.insert(ANDROID_SCALER_ROTATE_AND_CROP);
+ mRemappedKeys.insert(ANDROID_SCALER_CROP_REGION);
+}
+
bool RotateAndCropMapper::isNeeded(const CameraMetadata* deviceInfo) {
auto entry = deviceInfo->find(ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
for (size_t i = 0; i < entry.count; i++) {
@@ -36,6 +48,8 @@
}
RotateAndCropMapper::RotateAndCropMapper(const CameraMetadata* deviceInfo) {
+ initRemappedKeys();
+
auto entry = deviceInfo->find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
if (entry.count != 4) return;
diff --git a/services/camera/libcameraservice/device3/RotateAndCropMapper.h b/services/camera/libcameraservice/device3/RotateAndCropMapper.h
index 459e27f..f9e2263 100644
--- a/services/camera/libcameraservice/device3/RotateAndCropMapper.h
+++ b/services/camera/libcameraservice/device3/RotateAndCropMapper.h
@@ -32,12 +32,14 @@
* Utilities to transform between unrotated and rotated-and-cropped coordinate systems
* for cameras that support SCALER_ROTATE_AND_CROP controls in AUTO mode.
*/
-class RotateAndCropMapper : private CoordinateMapper {
+class RotateAndCropMapper : public CoordinateMapper {
public:
static bool isNeeded(const CameraMetadata* deviceInfo);
RotateAndCropMapper(const CameraMetadata* deviceInfo);
+ void initRemappedKeys() override;
+
/**
* Adjust capture request assuming rotate and crop AUTO is enabled
*/
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index a87de77..81d7bf9 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -25,6 +25,19 @@
namespace camera3 {
+void ZoomRatioMapper::initRemappedKeys() {
+ mRemappedKeys.insert(
+ kMeteringRegionsToCorrect.begin(),
+ kMeteringRegionsToCorrect.end());
+ mRemappedKeys.insert(
+ kRectsToCorrect.begin(),
+ kRectsToCorrect.end());
+ mRemappedKeys.insert(
+ kResultPointsToCorrectNoClamp.begin(),
+ kResultPointsToCorrectNoClamp.end());
+
+ mRemappedKeys.insert(ANDROID_CONTROL_ZOOM_RATIO);
+}
status_t ZoomRatioMapper::initZoomRatioInTemplate(CameraMetadata *request) {
camera_metadata_entry_t entry;
@@ -117,6 +130,8 @@
ZoomRatioMapper::ZoomRatioMapper(const CameraMetadata* deviceInfo,
bool supportNativeZoomRatio, bool usePrecorrectArray) {
+ initRemappedKeys();
+
camera_metadata_ro_entry_t entry;
entry = deviceInfo->find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
index 698f87f..3769299 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.h
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -33,7 +33,7 @@
* - HAL supports zoomRatio and the application uses cropRegion, or
* - HAL doesn't support zoomRatio, but the application uses zoomRatio
*/
-class ZoomRatioMapper : private CoordinateMapper {
+class ZoomRatioMapper : public CoordinateMapper {
public:
ZoomRatioMapper() = default;
ZoomRatioMapper(const CameraMetadata *deviceInfo,
@@ -41,7 +41,9 @@
ZoomRatioMapper(const ZoomRatioMapper& other) :
mHalSupportsZoomRatio(other.mHalSupportsZoomRatio),
mArrayWidth(other.mArrayWidth), mArrayHeight(other.mArrayHeight),
- mIsValid(other.mIsValid) {}
+ mIsValid(other.mIsValid) { initRemappedKeys(); }
+
+ void initRemappedKeys() override;
/**
* Initialize request template with valid zoomRatio if necessary.
diff --git a/services/camera/libcameraservice/fuzzer/Android.bp b/services/camera/libcameraservice/fuzzer/Android.bp
new file mode 100644
index 0000000..c5b7f00
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/Android.bp
@@ -0,0 +1,44 @@
+// Copyright 2020 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.
+
+cc_defaults {
+ name: "libcameraservice_fuzz_defaults",
+ fuzz_config: {
+ componentid: 41727
+ },
+}
+
+cc_fuzz {
+ name: "libcameraservice_distortion_mapper_fuzzer",
+ defaults: ["libcameraservice_fuzz_defaults"],
+ srcs: [
+ "DistortionMapperFuzzer.cpp",
+ ],
+ shared_libs: [
+ "libcameraservice",
+ "libcamera_client",
+ ],
+}
+
+cc_fuzz {
+ name: "libcameraservice_depth_processor_fuzzer",
+ defaults: ["libcameraservice_fuzz_defaults"],
+ srcs: [
+ "DepthProcessorFuzzer.cpp",
+ ],
+ shared_libs: [
+ "libcameraservice",
+ ],
+ corpus: ["corpus/*.jpg"],
+}
diff --git a/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp b/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
new file mode 100644
index 0000000..650ca91
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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 <array>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "common/DepthPhotoProcessor.h"
+
+using namespace android;
+using namespace android::camera3;
+
+static const size_t kTestBufferWidth = 640;
+static const size_t kTestBufferHeight = 480;
+static const size_t kTestBufferDepthSize (kTestBufferWidth * kTestBufferHeight);
+
+void generateDepth16Buffer(const uint8_t* data, size_t size, std::array<uint16_t, kTestBufferDepthSize> *depth16Buffer /*out*/) {
+ FuzzedDataProvider dataProvider(data, size);
+ for (size_t i = 0; i < depth16Buffer->size(); i++) {
+ (*depth16Buffer)[i] = dataProvider.ConsumeIntegral<uint16_t>();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ DepthPhotoInputFrame inputFrame;
+ // Worst case both depth and confidence maps have the same size as the main color image.
+ inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
+
+ std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
+ size_t actualDepthPhotoSize = 0;
+
+ std::array<uint16_t, kTestBufferDepthSize> depth16Buffer;
+ generateDepth16Buffer(data, size, &depth16Buffer);
+
+ inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (data);
+ inputFrame.mMainJpegSize = size;
+ inputFrame.mDepthMapBuffer = depth16Buffer.data();
+ inputFrame.mDepthMapStride = kTestBufferWidth;
+ inputFrame.mDepthMapWidth = kTestBufferWidth;
+ inputFrame.mDepthMapHeight = kTestBufferHeight;
+ processDepthPhotoFrame(
+ inputFrame,
+ depthPhotoBuffer.size(),
+ depthPhotoBuffer.data(),
+ &actualDepthPhotoSize);
+
+ return 0;
+}
diff --git a/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp b/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
new file mode 100644
index 0000000..96bab4e
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 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 <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "device3/DistortionMapper.h"
+#include <camera/CameraMetadata.h>
+
+using namespace android;
+using namespace android::camera3;
+
+int32_t testActiveArray[] = {100, 100, 1000, 750};
+float testICal[] = { 1000.f, 1000.f, 500.f, 500.f, 0.f };
+float identityDistortion[] = { 0.f, 0.f, 0.f, 0.f, 0.f};
+
+void setupTestMapper(DistortionMapper *m,
+ float distortion[5], float intrinsics[5],
+ int32_t activeArray[4], int32_t preCorrectionActiveArray[4]) {
+ CameraMetadata deviceInfo;
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+ preCorrectionActiveArray, 4);
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ activeArray, 4);
+
+ deviceInfo.update(ANDROID_LENS_INTRINSIC_CALIBRATION,
+ intrinsics, 5);
+
+ deviceInfo.update(ANDROID_LENS_DISTORTION,
+ distortion, 5);
+
+ m->setupStaticInfo(deviceInfo);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ DistortionMapper m;
+ setupTestMapper(&m, identityDistortion, testICal,
+ /*activeArray*/ testActiveArray,
+ /*preCorrectionActiveArray*/ testActiveArray);
+
+ bool clamp = fdp.ConsumeBool();
+ bool simple = fdp.ConsumeBool();
+ std::vector<int32_t> input;
+ for (int index = 0; fdp.remaining_bytes() > 0; index++) {
+ input.push_back(fdp.ConsumeIntegral<int32_t>());
+ }
+
+ // The size argument counts how many coordinate pairs there are, so
+ // it is expected to be 1/2 the size of the input.
+ m.mapCorrectedToRaw(input.data(), input.size()/2, clamp, simple);
+
+ return 0;
+}
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Canon_MakerNote_variant_type_1.jpg b/services/camera/libcameraservice/fuzzer/corpus/Canon_MakerNote_variant_type_1.jpg
new file mode 100644
index 0000000..1eb37d0
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Canon_MakerNote_variant_type_1.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Fuji_MakerNote_variant_type_1.jpg b/services/camera/libcameraservice/fuzzer/corpus/Fuji_MakerNote_variant_type_1.jpg
new file mode 100644
index 0000000..75e0371
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Fuji_MakerNote_variant_type_1.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_2.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_2.jpg
new file mode 100644
index 0000000..461d613
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_2.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_3.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_3.jpg
new file mode 100644
index 0000000..42498e2
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_3.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_4.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_4.jpg
new file mode 100644
index 0000000..233ff78
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_4.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_5.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_5.jpg
new file mode 100644
index 0000000..f083f75
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_5.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_2.jpg b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_2.jpg
new file mode 100644
index 0000000..0ef0ef2
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_2.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_3.jpg b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_3.jpg
new file mode 100644
index 0000000..d93b86f
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_3.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_4.jpg b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_4.jpg
new file mode 100644
index 0000000..297ea1c
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_4.jpg
Binary files differ
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index 74b63d5..3a27a43 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
name: "libmedialogservice",
srcs: [
diff --git a/services/medialog/fuzzer/Android.bp b/services/medialog/fuzzer/Android.bp
new file mode 100644
index 0000000..2afaaae
--- /dev/null
+++ b/services/medialog/fuzzer/Android.bp
@@ -0,0 +1,33 @@
+cc_fuzz {
+ name: "media_log_fuzzer",
+ static_libs: [
+ "libmedialogservice",
+ ],
+ srcs: [
+ "media_log_fuzzer.cpp",
+ ],
+ header_libs: [
+ "libmedia_headers",
+ ],
+ shared_libs: [
+ "libaudioutils",
+ "libbinder",
+ "liblog",
+ "libmediautils",
+ "libnblog",
+ "libutils",
+ ],
+ include_dirs: [
+ "frameworks/av/services/medialog",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/services/medialog/fuzzer/README.md b/services/medialog/fuzzer/README.md
new file mode 100644
index 0000000..b79e5c8
--- /dev/null
+++ b/services/medialog/fuzzer/README.md
@@ -0,0 +1,50 @@
+# Fuzzer for libmedialogservice
+
+## Plugin Design Considerations
+The fuzzer plugin for libmedialogservice is designed based on the understanding of the
+service and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+medialogservice supports the following parameters:
+1. Writer name (parameter name: `writerNameIdx`)
+2. Log size (parameter name: `logSize`)
+3. Enable dump before unrgister API (parameter name: `shouldDumpBeforeUnregister`)
+5. size of string for log dump (parameter name: `numberOfLines`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `writerNameIdx` | 0. `0` 1. `1` | Value obtained from FuzzedDataProvider |
+| `logSize` | In the range `256 to 65536` | Value obtained from FuzzedDataProvider |
+| `shouldDumpBeforeUnregister` | 0. `0` 1. `1` | Value obtained from FuzzedDataProvider |
+| `numberOfLines` | In the range `0 to 65535` | Value obtained from FuzzedDataProvider |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+## Build
+
+This describes steps to build media_log_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) media_log_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/media_log_fuzzer/media_log_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/services/medialog/fuzzer/media_log_fuzzer.cpp b/services/medialog/fuzzer/media_log_fuzzer.cpp
new file mode 100644
index 0000000..bd50d0f
--- /dev/null
+++ b/services/medialog/fuzzer/media_log_fuzzer.cpp
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2020 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 <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <private/android_filesystem_config.h>
+#include "MediaLogService.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+constexpr const char* kWriterNames[2] = {"FastMixer", "FastCapture"};
+constexpr size_t kMinSize = 0x100;
+constexpr size_t kMaxSize = 0x10000;
+constexpr size_t kLogMemorySize = 400 * 1024;
+constexpr size_t kMaxNumLines = USHRT_MAX;
+
+using namespace android;
+
+class MediaLogFuzzer {
+ public:
+ void init();
+ void process(const uint8_t* data, size_t size);
+
+ private:
+ sp<MemoryDealer> mMemoryDealer = nullptr;
+ sp<MediaLogService> mService = nullptr;
+};
+
+void MediaLogFuzzer::init() {
+ setuid(AID_MEDIA);
+ mService = new MediaLogService();
+ mMemoryDealer = new MemoryDealer(kLogMemorySize, "MediaLogFuzzer", MemoryHeapBase::READ_ONLY);
+}
+
+void MediaLogFuzzer::process(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fuzzedDataProvider(data, size);
+ size_t writerNameIdx =
+ fuzzedDataProvider.ConsumeIntegralInRange<size_t>(0, std::size(kWriterNames) - 1);
+ bool shouldDumpBeforeUnregister = fuzzedDataProvider.ConsumeBool();
+ size_t logSize = fuzzedDataProvider.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ sp<IMemory> logBuffer = mMemoryDealer->allocate(NBLog::Timeline::sharedSize(logSize));
+ Vector<String16> args;
+ size_t numberOfLines = fuzzedDataProvider.ConsumeIntegralInRange<size_t>(0, kMaxNumLines);
+ for (size_t lineIdx = 0; lineIdx < numberOfLines; ++lineIdx) {
+ args.add(static_cast<String16>(fuzzedDataProvider.ConsumeRandomLengthString().c_str()));
+ }
+ const char* fileName = "logDumpFile";
+ int fd = memfd_create(fileName, MFD_ALLOW_SEALING);
+ fuzzedDataProvider.ConsumeData(logBuffer->unsecurePointer(), logBuffer->size());
+ mService->registerWriter(logBuffer, logSize, kWriterNames[writerNameIdx]);
+ if (shouldDumpBeforeUnregister) {
+ mService->dump(fd, args);
+ mService->unregisterWriter(logBuffer);
+ } else {
+ mService->unregisterWriter(logBuffer);
+ mService->dump(fd, args);
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ MediaLogFuzzer mediaLogFuzzer = MediaLogFuzzer();
+ mediaLogFuzzer.init();
+ mediaLogFuzzer.process(data, size);
+ return 0;
+}