From 1815a762fc746458ff71627fc9272256d65e8a1c Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Fri, 24 May 2019 08:52:27 -0700 Subject: [PATCH 01/44] aaudio: fix IsochronousClockModel drift calculation Correct an error that caused the timing window to jump forward in time by one burst when a late timestamp was detected. Bug: 133513175 Bug: 122680738 Bug: 123643363 Test: aaudio_loopback -tm -s20 Change-Id: I65c05d2ab123bcd347cb900de055c49c0c9beada --- .../src/client/IsochronousClockModel.cpp | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp index 747d0e14bc..d26b3523ac 100644 --- a/media/libaaudio/src/client/IsochronousClockModel.cpp +++ b/media/libaaudio/src/client/IsochronousClockModel.cpp @@ -108,17 +108,24 @@ void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nano case STATE_RUNNING: if (nanosDelta < expectedNanosDelta) { // Earlier than expected timestamp. - // This data is probably more accurate so use it. - // or we may be drifting due to a slow HW clock. -// ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY", -// (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000)); + // This data is probably more accurate, so use it. + // Or we may be drifting due to a fast HW clock. +// int microsDelta = (int) (nanosDelta / 1000); +// int expectedMicrosDelta = (int) (expectedNanosDelta / 1000); +// ALOGD("processTimestamp() - STATE_RUNNING - %7d < %7d so %4d micros EARLY", +// microsDelta, expectedMicrosDelta, (expectedMicrosDelta - microsDelta)); + setPositionAndTime(framePosition, nanoTime); } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) { // Later than expected timestamp. -// ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE", -// (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000), -// (int) (mMaxLatenessInNanos / 1000)); - setPositionAndTime(framePosition - mFramesPerBurst, nanoTime - mMaxLatenessInNanos); +// int microsDelta = (int) (nanosDelta / 1000); +// int expectedMicrosDeadline = (int) ((expectedNanosDelta + mMaxLatenessInNanos) / 1000); +// ALOGD("processTimestamp() - STATE_RUNNING - %7d > %7d so %4d micros LATE", +// microsDelta, expectedMicrosDeadline, (microsDelta - expectedMicrosDeadline)); + + // When we are late it may be because of preemption in the kernel or + // we may be drifting due to a slow HW clock. + setPositionAndTime(framePosition, nanoTime - mMaxLatenessInNanos); } break; default: From d032f2dff9d8f5362fe3ca885f548539bf5dbdb2 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Wed, 15 May 2019 08:42:44 -0700 Subject: [PATCH 02/44] Add support for graphics.mapper@3.0 Test: atest CtsMediaTestCases -- --module-arg CtsMediaTestCases:size:small Bug: 128013727 Bug: 129670826 Change-Id: Iaa7a3f06956f9f81b3d4338bbf32fea282cdd511 --- media/codec2/vndk/Android.bp | 2 + media/codec2/vndk/C2AllocatorGralloc.cpp | 678 ++++++++++++++++------- 2 files changed, 483 insertions(+), 197 deletions(-) diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp index ca69810039..b6ddfabf2d 100644 --- a/media/codec2/vndk/Android.bp +++ b/media/codec2/vndk/Android.bp @@ -50,8 +50,10 @@ cc_library_shared { shared_libs: [ "android.hardware.graphics.allocator@2.0", + "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.mapper@2.0", + "android.hardware.graphics.mapper@3.0", "android.hardware.media.bufferpool@2.0", "libbase", "libbinder", diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp index e698bf4b9a..dab469770a 100644 --- a/media/codec2/vndk/C2AllocatorGralloc.cpp +++ b/media/codec2/vndk/C2AllocatorGralloc.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include #include @@ -29,7 +31,7 @@ namespace android { -namespace { +namespace /* unnamed */ { enum : uint64_t { /** * Usage mask that is passed through from gralloc to Codec 2.0 usage. @@ -40,7 +42,7 @@ namespace { // verify that passthrough mask is within the platform mask static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, ""); -} +} // unnamed C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) { // gralloc does not support WRITE_PROTECTED @@ -59,39 +61,59 @@ uint64_t C2AndroidMemoryUsage::asGrallocUsage() const { (expected & PASSTHROUGH_USAGE_MASK)); } -using ::android::hardware::graphics::allocator::V2_0::IAllocator; -using ::android::hardware::graphics::common::V1_0::BufferUsage; -using ::android::hardware::graphics::common::V1_0::PixelFormat; -using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor; -using ::android::hardware::graphics::mapper::V2_0::Error; -using ::android::hardware::graphics::mapper::V2_0::IMapper; -using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_vec; +using ::android::hardware::graphics::common::V1_0::BufferUsage; +using PixelFormat2 = ::android::hardware::graphics::common::V1_0::PixelFormat; +using PixelFormat3 = ::android::hardware::graphics::common::V1_2::PixelFormat; + +using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator; +using BufferDescriptor2 = ::android::hardware::graphics::mapper::V2_0::BufferDescriptor; +using Error2 = ::android::hardware::graphics::mapper::V2_0::Error; +using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper; + +using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator; +using BufferDescriptor3 = ::android::hardware::graphics::mapper::V3_0::BufferDescriptor; +using Error3 = ::android::hardware::graphics::mapper::V3_0::Error; +using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper; -namespace { +namespace /* unnamed */ { -struct BufferDescriptorInfo { - IMapper::BufferDescriptorInfo mapperInfo; +struct BufferDescriptorInfo2 { + IMapper2::BufferDescriptorInfo mapperInfo; uint32_t stride; }; -} +struct BufferDescriptorInfo3 { + IMapper3::BufferDescriptorInfo mapperInfo; + uint32_t stride; +}; /* ===================================== GRALLOC ALLOCATION ==================================== */ -static c2_status_t maperr2error(Error maperr) { +c2_status_t maperr2error(Error2 maperr) { + switch (maperr) { + case Error2::NONE: return C2_OK; + case Error2::BAD_DESCRIPTOR: return C2_BAD_VALUE; + case Error2::BAD_BUFFER: return C2_BAD_VALUE; + case Error2::BAD_VALUE: return C2_BAD_VALUE; + case Error2::NO_RESOURCES: return C2_NO_MEMORY; + case Error2::UNSUPPORTED: return C2_CANNOT_DO; + } + return C2_CORRUPTED; +} + +c2_status_t maperr2error(Error3 maperr) { switch (maperr) { - case Error::NONE: return C2_OK; - case Error::BAD_DESCRIPTOR: return C2_BAD_VALUE; - case Error::BAD_BUFFER: return C2_BAD_VALUE; - case Error::BAD_VALUE: return C2_BAD_VALUE; - case Error::NO_RESOURCES: return C2_NO_MEMORY; - case Error::UNSUPPORTED: return C2_CANNOT_DO; + case Error3::NONE: return C2_OK; + case Error3::BAD_DESCRIPTOR: return C2_BAD_VALUE; + case Error3::BAD_BUFFER: return C2_BAD_VALUE; + case Error3::BAD_VALUE: return C2_BAD_VALUE; + case Error3::NO_RESOURCES: return C2_NO_MEMORY; + case Error3::UNSUPPORTED: return C2_CANNOT_DO; } return C2_CORRUPTED; } -static bool native_handle_is_invalid(const native_handle_t *const handle) { // perform basic validation of a native handle if (handle == nullptr) { @@ -214,23 +236,6 @@ public: return res; } - static native_handle_t* UnwrapNativeHandle( - const C2Handle *const handle, - uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) { - const ExtraData *xd = getExtraData(handle); - if (xd == nullptr || xd->magic != MAGIC) { - return nullptr; - } - *generation = xd->generation; - *igbp_id = unsigned(xd->igbp_id_lo) | uint64_t(unsigned(xd->igbp_id_hi)) << 32; - *igbp_slot = xd->igbp_slot; - native_handle_t *res = native_handle_create(handle->numFds, handle->numInts - NUM_INTS); - if (res != nullptr) { - memcpy(&res->data, &handle->data, sizeof(int) * (res->numFds + res->numInts)); - } - return res; - } - static const C2HandleGralloc* Import( const C2Handle *const handle, uint32_t *width, uint32_t *height, uint32_t *format, @@ -252,16 +257,12 @@ public: } }; +} // unnamed namespace + native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) { return C2HandleGralloc::UnwrapNativeHandle(handle); } -native_handle_t *UnwrapNativeCodec2GrallocHandle( - const C2Handle *const handle, - uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) { - return C2HandleGralloc::UnwrapNativeHandle(handle, generation, igbp_id, igbp_slot); -} - C2Handle *WrapNativeCodec2GrallocHandle( const native_handle_t *const handle, uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride, @@ -286,8 +287,14 @@ public: // internal methods // |handle| will be moved. C2AllocationGralloc( - const BufferDescriptorInfo &info, - const sp &mapper, + const BufferDescriptorInfo2 &info, + const sp &mapper, + hidl_handle &hidlHandle, + const C2HandleGralloc *const handle, + C2Allocator::id_t allocatorId); + C2AllocationGralloc( + const BufferDescriptorInfo3 &info, + const sp &mapper, hidl_handle &hidlHandle, const C2HandleGralloc *const handle, C2Allocator::id_t allocatorId); @@ -295,8 +302,10 @@ public: c2_status_t status() const; private: - const BufferDescriptorInfo mInfo; - const sp mMapper; + const BufferDescriptorInfo2 mInfo2{}; + const sp mMapper2{nullptr}; + const BufferDescriptorInfo3 mInfo3{}; + const sp mMapper3{nullptr}; const hidl_handle mHidlHandle; const C2HandleGralloc *mHandle; buffer_handle_t mBuffer; @@ -307,14 +316,31 @@ private: }; C2AllocationGralloc::C2AllocationGralloc( - const BufferDescriptorInfo &info, - const sp &mapper, + const BufferDescriptorInfo2 &info, + const sp &mapper, hidl_handle &hidlHandle, const C2HandleGralloc *const handle, C2Allocator::id_t allocatorId) : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height), - mInfo(info), - mMapper(mapper), + mInfo2(info), + mMapper2(mapper), + mHidlHandle(std::move(hidlHandle)), + mHandle(handle), + mBuffer(nullptr), + mLockedHandle(nullptr), + mLocked(false), + mAllocatorId(allocatorId) { +} + +C2AllocationGralloc::C2AllocationGralloc( + const BufferDescriptorInfo3 &info, + const sp &mapper, + hidl_handle &hidlHandle, + const C2HandleGralloc *const handle, + C2Allocator::id_t allocatorId) + : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height), + mInfo3(info), + mMapper3(mapper), mHidlHandle(std::move(hidlHandle)), mHandle(handle), mBuffer(nullptr), @@ -330,7 +356,17 @@ C2AllocationGralloc::~C2AllocationGralloc() { unmap(addr, C2Rect(), nullptr); } if (mBuffer) { - mMapper->freeBuffer(const_cast(mBuffer)); + if (mMapper2) { + if (!mMapper2->freeBuffer(const_cast( + mBuffer)).isOk()) { + ALOGE("failed transaction: freeBuffer"); + } + } else { + if (!mMapper3->freeBuffer(const_cast( + mBuffer)).isOk()) { + ALOGE("failed transaction: freeBuffer"); + } + } } if (mHandle) { native_handle_delete( @@ -365,13 +401,29 @@ c2_status_t C2AllocationGralloc::map( c2_status_t err = C2_OK; if (!mBuffer) { - mMapper->importBuffer( - mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) { - err = maperr2error(maperr); - if (err == C2_OK) { - mBuffer = static_cast(buffer); - } - }); + if (mMapper2) { + if (!mMapper2->importBuffer( + mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) { + err = maperr2error(maperr); + if (err == C2_OK) { + mBuffer = static_cast(buffer); + } + }).isOk()) { + ALOGE("failed transaction: importBuffer"); + return C2_CORRUPTED; + } + } else { + if (!mMapper3->importBuffer( + mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) { + err = maperr2error(maperr); + if (err == C2_OK) { + mBuffer = static_cast(buffer); + } + }).isOk()) { + ALOGE("failed transaction: importBuffer (@3.0)"); + return C2_CORRUPTED; + } + } if (err != C2_OK) { ALOGD("importBuffer failed: %d", err); return err; @@ -386,30 +438,66 @@ c2_status_t C2AllocationGralloc::map( if (mHandle) { mHandle->getIgbpData(&generation, &igbp_id, &igbp_slot); } - mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle( - mBuffer, mInfo.mapperInfo.width, mInfo.mapperInfo.height, - (uint32_t)mInfo.mapperInfo.format, mInfo.mapperInfo.usage, mInfo.stride, - generation, igbp_id, igbp_slot); + if (mMapper2) { + mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle( + mBuffer, mInfo2.mapperInfo.width, mInfo2.mapperInfo.height, + (uint32_t)mInfo2.mapperInfo.format, mInfo2.mapperInfo.usage, + mInfo2.stride, generation, igbp_id, igbp_slot); + } else { + mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle( + mBuffer, mInfo3.mapperInfo.width, mInfo3.mapperInfo.height, + (uint32_t)mInfo3.mapperInfo.format, mInfo3.mapperInfo.usage, + mInfo3.stride, generation, igbp_id, igbp_slot); + } } - switch (mInfo.mapperInfo.format) { - case PixelFormat::RGBA_1010102: { + PixelFormat3 format = mMapper2 ? + PixelFormat3(mInfo2.mapperInfo.format) : + PixelFormat3(mInfo3.mapperInfo.format); + switch (format) { + case PixelFormat3::RGBA_1010102: { // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a // Surface. In all other cases it is RGBA. We don't know which case it is here, so // default to YUV for now. void *pointer = nullptr; - mMapper->lock( - const_cast(mBuffer), - grallocUsage, - { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height }, - // TODO: fence - hidl_handle(), - [&err, &pointer](const auto &maperr, const auto &mapPointer) { - err = maperr2error(maperr); - if (err == C2_OK) { - pointer = mapPointer; - } - }); + if (mMapper2) { + if (!mMapper2->lock( + const_cast(mBuffer), + grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto &maperr, const auto &mapPointer) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + }).isOk()) { + ALOGE("failed transaction: lock(RGBA_1010102)"); + return C2_CORRUPTED; + } + } else { + if (!mMapper3->lock( + const_cast(mBuffer), + grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto &maperr, const auto &mapPointer, + int32_t bytesPerPixel, int32_t bytesPerStride) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + (void)bytesPerPixel; + (void)bytesPerStride; + }).isOk()) { + ALOGE("failed transaction: lock(RGBA_1010102) (@3.0)"); + return C2_CORRUPTED; + } + } if (err != C2_OK) { ALOGD("lock failed: %d", err); return err; @@ -422,10 +510,13 @@ c2_status_t C2AllocationGralloc::map( layout->type = C2PlanarLayout::TYPE_YUVA; layout->numPlanes = 4; layout->rootPlanes = 1; + int32_t stride = mMapper2 ? + int32_t(mInfo2.stride) : + int32_t(mInfo3.stride); layout->planes[C2PlanarLayout::PLANE_Y] = { C2PlaneInfo::CHANNEL_Y, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth @@ -438,7 +529,7 @@ c2_status_t C2AllocationGralloc::map( layout->planes[C2PlanarLayout::PLANE_U] = { C2PlaneInfo::CHANNEL_CB, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth @@ -451,7 +542,7 @@ c2_status_t C2AllocationGralloc::map( layout->planes[C2PlanarLayout::PLANE_V] = { C2PlaneInfo::CHANNEL_CR, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth @@ -464,7 +555,7 @@ c2_status_t C2AllocationGralloc::map( layout->planes[C2PlanarLayout::PLANE_A] = { C2PlaneInfo::CHANNEL_A, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 32, // allocatedDepth @@ -477,23 +568,49 @@ c2_status_t C2AllocationGralloc::map( break; } - case PixelFormat::RGBA_8888: + case PixelFormat3::RGBA_8888: // TODO: alpha channel // fall-through - case PixelFormat::RGBX_8888: { + case PixelFormat3::RGBX_8888: { void *pointer = nullptr; - mMapper->lock( - const_cast(mBuffer), - grallocUsage, - { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height }, - // TODO: fence - hidl_handle(), - [&err, &pointer](const auto &maperr, const auto &mapPointer) { - err = maperr2error(maperr); - if (err == C2_OK) { - pointer = mapPointer; - } - }); + if (mMapper2) { + if (!mMapper2->lock( + const_cast(mBuffer), + grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto &maperr, const auto &mapPointer) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + }).isOk()) { + ALOGE("failed transaction: lock(RGBA_8888)"); + return C2_CORRUPTED; + } + } else { + if (!mMapper3->lock( + const_cast(mBuffer), + grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &pointer](const auto &maperr, const auto &mapPointer, + int32_t bytesPerPixel, int32_t bytesPerStride) { + err = maperr2error(maperr); + if (err == C2_OK) { + pointer = mapPointer; + } + (void)bytesPerPixel; + (void)bytesPerStride; + }).isOk()) { + ALOGE("failed transaction: lock(RGBA_8888) (@3.0)"); + return C2_CORRUPTED; + } + } if (err != C2_OK) { ALOGD("lock failed: %d", err); return err; @@ -504,10 +621,13 @@ c2_status_t C2AllocationGralloc::map( layout->type = C2PlanarLayout::TYPE_RGB; layout->numPlanes = 3; layout->rootPlanes = 1; + int32_t stride = mMapper2 ? + int32_t(mInfo2.stride) : + int32_t(mInfo3.stride); layout->planes[C2PlanarLayout::PLANE_R] = { C2PlaneInfo::CHANNEL_R, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth @@ -520,7 +640,7 @@ c2_status_t C2AllocationGralloc::map( layout->planes[C2PlanarLayout::PLANE_G] = { C2PlaneInfo::CHANNEL_G, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth @@ -533,7 +653,7 @@ c2_status_t C2AllocationGralloc::map( layout->planes[C2PlanarLayout::PLANE_B] = { C2PlaneInfo::CHANNEL_B, // channel 4, // colInc - 4 * (int32_t)mInfo.stride, // rowInc + 4 * stride, // rowInc 1, // mColSampling 1, // mRowSampling 8, // allocatedDepth @@ -546,23 +666,65 @@ c2_status_t C2AllocationGralloc::map( break; } - case PixelFormat::YCBCR_420_888: + case PixelFormat3::YCBCR_420_888: // fall-through - case PixelFormat::YV12: + case PixelFormat3::YV12: // fall-through default: { + struct YCbCrLayout { + void* y; + void* cb; + void* cr; + uint32_t yStride; + uint32_t cStride; + uint32_t chromaStep; + }; YCbCrLayout ycbcrLayout; - mMapper->lockYCbCr( - const_cast(mBuffer), grallocUsage, - { (int32_t)rect.left, (int32_t)rect.top, (int32_t)rect.width, (int32_t)rect.height }, - // TODO: fence - hidl_handle(), - [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) { - err = maperr2error(maperr); - if (err == C2_OK) { - ycbcrLayout = mapLayout; - } - }); + if (mMapper2) { + if (!mMapper2->lockYCbCr( + const_cast(mBuffer), grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) { + err = maperr2error(maperr); + if (err == C2_OK) { + ycbcrLayout = YCbCrLayout{ + mapLayout.y, + mapLayout.cb, + mapLayout.cr, + mapLayout.yStride, + mapLayout.cStride, + mapLayout.chromaStep}; + } + }).isOk()) { + ALOGE("failed transaction: lockYCbCr"); + return C2_CORRUPTED; + } + } else { + if (!mMapper3->lockYCbCr( + const_cast(mBuffer), grallocUsage, + { (int32_t)rect.left, (int32_t)rect.top, + (int32_t)rect.width, (int32_t)rect.height }, + // TODO: fence + hidl_handle(), + [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) { + err = maperr2error(maperr); + if (err == C2_OK) { + ycbcrLayout = YCbCrLayout{ + mapLayout.y, + mapLayout.cb, + mapLayout.cr, + mapLayout.yStride, + mapLayout.cStride, + mapLayout.chromaStep}; + } + }).isOk()) { + ALOGE("failed transaction: lockYCbCr (@3.0)"); + return C2_CORRUPTED; + } + } if (err != C2_OK) { ALOGD("lockYCbCr failed: %d", err); return err; @@ -639,17 +801,37 @@ c2_status_t C2AllocationGralloc::unmap( std::lock_guard lock(mMappedLock); c2_status_t err = C2_OK; - mMapper->unlock( - const_cast(mBuffer), - [&err, &fence](const auto &maperr, const auto &releaseFence) { - // TODO - (void) fence; - (void) releaseFence; - err = maperr2error(maperr); - if (err == C2_OK) { - // TODO: fence - } - }); + if (mMapper2) { + if (!mMapper2->unlock( + const_cast(mBuffer), + [&err, &fence](const auto &maperr, const auto &releaseFence) { + // TODO + (void) fence; + (void) releaseFence; + err = maperr2error(maperr); + if (err == C2_OK) { + // TODO: fence + } + }).isOk()) { + ALOGE("failed transaction: unlock"); + return C2_CORRUPTED; + } + } else { + if (!mMapper3->unlock( + const_cast(mBuffer), + [&err, &fence](const auto &maperr, const auto &releaseFence) { + // TODO + (void) fence; + (void) releaseFence; + err = maperr2error(maperr); + if (err == C2_OK) { + // TODO: fence + } + }).isOk()) { + ALOGE("failed transaction: unlock (@3.0)"); + return C2_CORRUPTED; + } + } if (err == C2_OK) { mLocked = false; } @@ -690,8 +872,10 @@ public: private: std::shared_ptr mTraits; c2_status_t mInit; - sp mAllocator; - sp mMapper; + sp mAllocator2; + sp mMapper2; + sp mAllocator3; + sp mMapper3; const bool mBufferQueue; }; @@ -711,10 +895,18 @@ C2AllocatorGralloc::Impl::Impl(id_t id, bool bufferQueue) mTraits = std::make_shared(traits); // gralloc allocator is a singleton, so all objects share a global service - mAllocator = IAllocator::getService(); - mMapper = IMapper::getService(); - if (mAllocator == nullptr || mMapper == nullptr) { - mInit = C2_CORRUPTED; + mAllocator3 = IAllocator3::getService(); + mMapper3 = IMapper3::getService(); + if (!mAllocator3 || !mMapper3) { + mAllocator3 = nullptr; + mMapper3 = nullptr; + mAllocator2 = IAllocator2::getService(); + mMapper2 = IMapper2::getService(); + if (!mAllocator2 || !mMapper2) { + mAllocator2 = nullptr; + mMapper2 = nullptr; + mInit = C2_CORRUPTED; + } } } @@ -725,84 +917,176 @@ c2_status_t C2AllocatorGralloc::Impl::newGraphicAllocation( ALOGV("allocating buffer with usage %#llx => %#llx", (long long)usage.expected, (long long)grallocUsage); - BufferDescriptorInfo info = { - { - width, - height, - 1u, // layerCount - (PixelFormat)format, - grallocUsage, - }, - 0u, // stride placeholder - }; c2_status_t err = C2_OK; - BufferDescriptor desc; - mMapper->createDescriptor( - info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) { - err = maperr2error(maperr); - if (err == C2_OK) { - desc = descriptor; - } - }); - if (err != C2_OK) { - return err; - } - - // IAllocator shares IMapper error codes. - hidl_handle buffer; - mAllocator->allocate( - desc, - 1u, - [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) { - err = maperr2error(maperr); - if (err != C2_OK) { - return; - } - if (buffers.size() != 1u) { - err = C2_CORRUPTED; - return; - } - info.stride = stride; - buffer = buffers[0]; - }); - if (err != C2_OK) { - return err; - } + hidl_handle buffer{}; + + if (mMapper2) { + BufferDescriptorInfo2 info = { + { + width, + height, + 1u, // layerCount + PixelFormat2(format), + grallocUsage, + }, + 0u, // stride placeholder + }; + BufferDescriptor2 desc; + if (!mMapper2->createDescriptor( + info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) { + err = maperr2error(maperr); + if (err == C2_OK) { + desc = descriptor; + } + }).isOk()) { + ALOGE("failed transaction: createDescriptor"); + return C2_CORRUPTED; + } + if (err != C2_OK) { + return err; + } + // IAllocator shares IMapper error codes. + if (!mAllocator2->allocate( + desc, + 1u, + [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) { + err = maperr2error(maperr); + if (err != C2_OK) { + return; + } + if (buffers.size() != 1u) { + err = C2_CORRUPTED; + return; + } + info.stride = stride; + buffer = buffers[0]; + }).isOk()) { + ALOGE("failed transaction: allocate"); + return C2_CORRUPTED; + } + if (err != C2_OK) { + return err; + } + allocation->reset(new C2AllocationGralloc( + info, mMapper2, buffer, + C2HandleGralloc::WrapAndMoveNativeHandle( + buffer.getNativeHandle(), + width, height, + format, grallocUsage, info.stride, + 0, 0, mBufferQueue ? ~0 : 0), + mTraits->id)); + return C2_OK; + } else { + BufferDescriptorInfo3 info = { + { + width, + height, + 1u, // layerCount + PixelFormat3(format), + grallocUsage, + }, + 0u, // stride placeholder + }; + BufferDescriptor3 desc; + if (!mMapper3->createDescriptor( + info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) { + err = maperr2error(maperr); + if (err == C2_OK) { + desc = descriptor; + } + }).isOk()) { + ALOGE("failed transaction: createDescriptor"); + return C2_CORRUPTED; + } + if (err != C2_OK) { + return err; + } - allocation->reset(new C2AllocationGralloc( - info, mMapper, buffer, - C2HandleGralloc::WrapAndMoveNativeHandle( - buffer.getNativeHandle(), - info.mapperInfo.width, info.mapperInfo.height, - (uint32_t)info.mapperInfo.format, info.mapperInfo.usage, info.stride, - 0, 0, mBufferQueue ? ~0 : 0), - mTraits->id)); - return C2_OK; + // IAllocator shares IMapper error codes. + if (!mAllocator3->allocate( + desc, + 1u, + [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) { + err = maperr2error(maperr); + if (err != C2_OK) { + return; + } + if (buffers.size() != 1u) { + err = C2_CORRUPTED; + return; + } + info.stride = stride; + buffer = buffers[0]; + }).isOk()) { + ALOGE("failed transaction: allocate"); + return C2_CORRUPTED; + } + if (err != C2_OK) { + return err; + } + allocation->reset(new C2AllocationGralloc( + info, mMapper3, buffer, + C2HandleGralloc::WrapAndMoveNativeHandle( + buffer.getNativeHandle(), + width, height, + format, grallocUsage, info.stride, + 0, 0, mBufferQueue ? ~0 : 0), + mTraits->id)); + return C2_OK; + } } c2_status_t C2AllocatorGralloc::Impl::priorGraphicAllocation( const C2Handle *handle, std::shared_ptr *allocation) { - BufferDescriptorInfo info; - info.mapperInfo.layerCount = 1u; - uint32_t generation; - uint64_t igbp_id; - uint32_t igbp_slot; - const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import( - handle, - &info.mapperInfo.width, &info.mapperInfo.height, - (uint32_t *)&info.mapperInfo.format, (uint64_t *)&info.mapperInfo.usage, &info.stride, - &generation, &igbp_id, &igbp_slot); - if (grallocHandle == nullptr) { - return C2_BAD_VALUE; - } + if (mMapper2) { + BufferDescriptorInfo2 info; + info.mapperInfo.layerCount = 1u; + uint32_t generation; + uint64_t igbp_id; + uint32_t igbp_slot; + const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import( + handle, + &info.mapperInfo.width, &info.mapperInfo.height, + (uint32_t *)&info.mapperInfo.format, + (uint64_t *)&info.mapperInfo.usage, + &info.stride, + &generation, &igbp_id, &igbp_slot); + if (grallocHandle == nullptr) { + return C2_BAD_VALUE; + } - hidl_handle hidlHandle; - hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true); + hidl_handle hidlHandle; + hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true); - allocation->reset(new C2AllocationGralloc(info, mMapper, hidlHandle, grallocHandle, mTraits->id)); - return C2_OK; + allocation->reset(new C2AllocationGralloc( + info, mMapper2, hidlHandle, grallocHandle, mTraits->id)); + return C2_OK; + } else { + BufferDescriptorInfo3 info; + info.mapperInfo.layerCount = 1u; + uint32_t generation; + uint64_t igbp_id; + uint32_t igbp_slot; + const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import( + handle, + &info.mapperInfo.width, &info.mapperInfo.height, + (uint32_t *)&info.mapperInfo.format, + (uint64_t *)&info.mapperInfo.usage, + &info.stride, + &generation, &igbp_id, &igbp_slot); + if (grallocHandle == nullptr) { + return C2_BAD_VALUE; + } + + hidl_handle hidlHandle; + hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true); + + allocation->reset(new C2AllocationGralloc( + info, mMapper3, hidlHandle, grallocHandle, mTraits->id)); + return C2_OK; + } } C2AllocatorGralloc::C2AllocatorGralloc(id_t id, bool bufferQueue) From cb260add2adea7f710e0b3238fbdee1764d198f5 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Thu, 6 Jun 2019 14:20:26 -0700 Subject: [PATCH 03/44] CCodec: fix i-frame-interval and aac configs Bug: 134533155 Test: manual Change-Id: I95ad7638148dfdfe7ecb76e8b2682e86c23812e8 --- media/codec2/sfplugin/CCodecConfig.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp index 077a91f528..1cfdc19dad 100644 --- a/media/codec2/sfplugin/CCodecConfig.cpp +++ b/media/codec2/sfplugin/CCodecConfig.cpp @@ -508,7 +508,7 @@ void CCodecConfig::initializeStandardParams() { .limitTo(D::ENCODER & D::VIDEO)); // convert to timestamp base add(ConfigMapper(KEY_I_FRAME_INTERVAL, C2_PARAMKEY_SYNC_FRAME_INTERVAL, "value") - .withMapper([](C2Value v) -> C2Value { + .withMappers([](C2Value v) -> C2Value { // convert from i32 to float int32_t i32Value; float fpValue; @@ -518,6 +518,12 @@ void CCodecConfig::initializeStandardParams() { return int64_t(c2_min(1000000 * fpValue + 0.5, (double)INT64_MAX)); } return C2Value(); + }, [](C2Value v) -> C2Value { + int64_t i64; + if (v.get(&i64)) { + return float(i64) / 1000000; + } + return C2Value(); })); // remove when codecs switch to proper coding.gop (add support for calculating gop) deprecated(ConfigMapper("i-frame-period", "coding.gop", "intra-period") @@ -711,7 +717,7 @@ void CCodecConfig::initializeStandardParams() { // convert to dBFS and add default add(ConfigMapper(KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL, "value") - .limitTo(D::AUDIO & D::DECODER) + .limitTo(D::AUDIO & D::DECODER & D::CONFIG) .withMapper([](C2Value v) -> C2Value { int32_t value; if (!v.get(&value) || value < 0) { @@ -722,7 +728,7 @@ void CCodecConfig::initializeStandardParams() { // convert to 0-1 (%) and add default add(ConfigMapper(KEY_AAC_DRC_ATTENUATION_FACTOR, C2_PARAMKEY_DRC_ATTENUATION_FACTOR, "value") - .limitTo(D::AUDIO & D::DECODER) + .limitTo(D::AUDIO & D::DECODER & D::CONFIG) .withMapper([](C2Value v) -> C2Value { int32_t value; if (!v.get(&value) || value < 0) { @@ -733,7 +739,7 @@ void CCodecConfig::initializeStandardParams() { // convert to 0-1 (%) and add default add(ConfigMapper(KEY_AAC_DRC_BOOST_FACTOR, C2_PARAMKEY_DRC_BOOST_FACTOR, "value") - .limitTo(D::AUDIO & D::DECODER) + .limitTo(D::AUDIO & D::DECODER & D::CONFIG) .withMapper([](C2Value v) -> C2Value { int32_t value; if (!v.get(&value) || value < 0) { @@ -744,7 +750,7 @@ void CCodecConfig::initializeStandardParams() { // convert to compression type and add default add(ConfigMapper(KEY_AAC_DRC_HEAVY_COMPRESSION, C2_PARAMKEY_DRC_COMPRESSION_MODE, "value") - .limitTo(D::AUDIO & D::DECODER) + .limitTo(D::AUDIO & D::DECODER & D::CONFIG) .withMapper([](C2Value v) -> C2Value { int32_t value; if (!v.get(&value) || value < 0) { @@ -755,7 +761,7 @@ void CCodecConfig::initializeStandardParams() { // convert to dBFS and add default add(ConfigMapper(KEY_AAC_ENCODED_TARGET_LEVEL, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL, "value") - .limitTo(D::AUDIO & D::DECODER) + .limitTo(D::AUDIO & D::DECODER & D::CONFIG) .withMapper([](C2Value v) -> C2Value { int32_t value; if (!v.get(&value) || value < 0) { @@ -766,7 +772,7 @@ void CCodecConfig::initializeStandardParams() { // convert to effect type (these map to SDK values) and add default add(ConfigMapper(KEY_AAC_DRC_EFFECT_TYPE, C2_PARAMKEY_DRC_EFFECT_TYPE, "value") - .limitTo(D::AUDIO & D::DECODER) + .limitTo(D::AUDIO & D::DECODER & D::CONFIG) .withMapper([](C2Value v) -> C2Value { int32_t value; if (!v.get(&value) || value < -1 || value > 8) { From 97835e9715f03014301464461bfa91015d91dfe9 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 25 Apr 2019 23:27:18 -0700 Subject: [PATCH 04/44] Add /apex/com.android.runtime/${LIB} to runtime search path. The canonical location of the HWASAN runtime, an LL-NDK library, is being moved to the runtime APEX. It is apparently the first LL-NDK library in the runtime APEX that does not require a legacy symlink in /system/${LIB}. Therefore we need to add the runtime APEX's ${LIB} directory to the various search paths used by the linker so that the library can be loaded from the default and sphal namespaces. Bug: http://b/134459232 Test: Builds Change-Id: I1f63e1a2a61e1717d00736ef431f3ec2a9334193 Merged-In: I1f63e1a2a61e1717d00736ef431f3ec2a9334193 (cherry picked from commit 61f5fdf5c907f83f777395b7ebd45432855b5e7b) --- apex/ld.config.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apex/ld.config.txt b/apex/ld.config.txt index a5937fd9d8..af8ec066c0 100644 --- a/apex/ld.config.txt +++ b/apex/ld.config.txt @@ -37,9 +37,11 @@ namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv namespace.platform.isolated = true -namespace.platform.search.paths = /system/${LIB} +namespace.platform.search.paths = /system/${LIB} +namespace.platform.search.paths += /apex/com.android.runtime/${LIB} namespace.platform.asan.search.paths = /data/asan/system/${LIB} namespace.platform.asan.search.paths += /system/${LIB} +namespace.platform.asan.search.paths += /apex/com.android.runtime/${LIB} # /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc. # Add /apex/... pat to the permitted paths because linker uses realpath(3) From 48eb9b80c4e2751488b68df29ea64a137b52e2f7 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Tue, 11 Jun 2019 13:35:42 -0700 Subject: [PATCH 05/44] AImageReaderVendorTest: Tolerate failures for ACameraDevice_isSessionConfigurationSupported. Bug: 134683975 Test: AImageReaderVendorTest on multiple devices supporting physical different stream combinations. Change-Id: I6aabd024b7092d4ecf60f8e0adbd0a2bf799cd25 Signed-off-by: Jayant Chowdhary --- .../tests/AImageReaderVendorTest.cpp | 83 ++++++++++++------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp index 37de30ab01..7ab0124be1 100644 --- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp +++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static constexpr int kTestImageHeight = 480; static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888; using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache; +using ConfiguredWindows = std::set; class CameraHelper { public: @@ -60,9 +62,12 @@ class CameraHelper { const char* physicalCameraId; native_handle_t* anw; }; - int initCamera(native_handle_t* imgReaderAnw, + + // Retaining the error code in case the caller needs to analyze it. + std::variant initCamera(native_handle_t* imgReaderAnw, const std::vector& physicalImgReaders, bool usePhysicalSettings) { + ConfiguredWindows configuredWindows; if (imgReaderAnw == nullptr) { ALOGE("Cannot initialize camera before image reader get initialized."); return -1; @@ -78,7 +83,7 @@ class CameraHelper { ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice); if (ret != AMEDIA_OK || mDevice == nullptr) { ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice); - return -1; + return ret; } // Create capture session @@ -97,8 +102,9 @@ class CameraHelper { ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret); return ret; } - + configuredWindows.insert(mImgReaderAnw); std::vector idPointerList; + std::set physicalStreamMap; for (auto& physicalStream : physicalImgReaders) { ACaptureSessionOutput* sessionOutput = nullptr; ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw, @@ -112,21 +118,25 @@ class CameraHelper { ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret); return ret; } - mExtraOutputs.push_back(sessionOutput); + ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs); + if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION) { + ALOGW("ACameraDevice_isSessionConfigurationSupported failed, ret=%d camera id %s", + ret, mCameraId); + ACaptureSessionOutputContainer_remove(mOutputs, sessionOutput); + ACaptureSessionOutput_free(sessionOutput); + continue; + } + configuredWindows.insert(physicalStream.anw); // Assume that at most one physical stream per physical camera. mPhysicalCameraIds.push_back(physicalStream.physicalCameraId); idPointerList.push_back(physicalStream.physicalCameraId); + physicalStreamMap.insert(physicalStream.anw); + mSessionPhysicalOutputs.push_back(sessionOutput); } ACameraIdList cameraIdList; cameraIdList.numCameras = idPointerList.size(); cameraIdList.cameraIds = idPointerList.data(); - ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs); - if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION) { - ALOGE("ACameraDevice_isSessionConfigurationSupported failed, ret=%d", ret); - return ret; - } - ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession); if (ret != AMEDIA_OK) { ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret); @@ -157,6 +167,10 @@ class CameraHelper { } for (auto& physicalStream : physicalImgReaders) { + if (physicalStreamMap.find(physicalStream.anw) == physicalStreamMap.end()) { + ALOGI("Skipping physicalStream anw=%p", physicalStream.anw); + continue; + } ACameraOutputTarget* outputTarget = nullptr; ret = ACameraOutputTarget_create(physicalStream.anw, &outputTarget); if (ret != AMEDIA_OK) { @@ -168,11 +182,11 @@ class CameraHelper { ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret); return ret; } - mReqExtraOutputs.push_back(outputTarget); + mReqPhysicalOutputs.push_back(outputTarget); } mIsCameraReady = true; - return 0; + return configuredWindows; } @@ -184,10 +198,10 @@ class CameraHelper { ACameraOutputTarget_free(mReqImgReaderOutput); mReqImgReaderOutput = nullptr; } - for (auto& outputTarget : mReqExtraOutputs) { + for (auto& outputTarget : mReqPhysicalOutputs) { ACameraOutputTarget_free(outputTarget); } - mReqExtraOutputs.clear(); + mReqPhysicalOutputs.clear(); if (mStillRequest) { ACaptureRequest_free(mStillRequest); mStillRequest = nullptr; @@ -201,10 +215,10 @@ class CameraHelper { ACaptureSessionOutput_free(mImgReaderOutput); mImgReaderOutput = nullptr; } - for (auto& extraOutput : mExtraOutputs) { + for (auto& extraOutput : mSessionPhysicalOutputs) { ACaptureSessionOutput_free(extraOutput); } - mExtraOutputs.clear(); + mSessionPhysicalOutputs.clear(); if (mOutputs) { ACaptureSessionOutputContainer_free(mOutputs); mOutputs = nullptr; @@ -262,13 +276,13 @@ class CameraHelper { // Capture session ACaptureSessionOutputContainer* mOutputs = nullptr; ACaptureSessionOutput* mImgReaderOutput = nullptr; - std::vector mExtraOutputs; + std::vector mSessionPhysicalOutputs; ACameraCaptureSession* mSession = nullptr; // Capture request ACaptureRequest* mStillRequest = nullptr; ACameraOutputTarget* mReqImgReaderOutput = nullptr; - std::vector mReqExtraOutputs; + std::vector mReqPhysicalOutputs; bool mIsCameraReady = false; const char* mCameraId; @@ -581,9 +595,11 @@ class AImageReaderVendorTest : public ::testing::Test { } CameraHelper cameraHelper(id, mCameraManager); - ret = cameraHelper.initCamera(testCase.getNativeWindow(), - {}/*physicalImageReaders*/, false/*usePhysicalSettings*/); - if (ret < 0) { + std::variant retInit = + cameraHelper.initCamera(testCase.getNativeWindow(), {}/*physicalImageReaders*/, + false/*usePhysicalSettings*/); + int *retp = std::get_if(&retInit); + if (retp) { ALOGE("Unable to initialize camera helper"); return false; } @@ -751,10 +767,15 @@ class AImageReaderVendorTest : public ::testing::Test { physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()}); physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()}); - int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(), - physicalImgReaderInfo, usePhysicalSettings); - ASSERT_EQ(ret, 0); - + std::variant retInit = + cameraHelper.initCamera(testCases[0]->getNativeWindow(), physicalImgReaderInfo, + usePhysicalSettings); + int *retp = std::get_if(&retInit); + ASSERT_EQ(retp, nullptr); + ConfiguredWindows *configuredWindowsp = std::get_if(&retInit); + ASSERT_NE(configuredWindowsp, nullptr); + ASSERT_LE(configuredWindowsp->size(), testCases.size()); + int ret = 0; if (!cameraHelper.isCameraReady()) { ALOGW("Camera is not ready after successful initialization. It's either due to camera " "on board lacks BACKWARDS_COMPATIBLE capability or the device does not have " @@ -776,9 +797,15 @@ class AImageReaderVendorTest : public ::testing::Test { break; } } - ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount); - ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount); - ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount); + for(auto &testCase : testCases) { + auto it = configuredWindowsp->find(testCase->getNativeWindow()); + if (it == configuredWindowsp->end()) { + continue; + } + ALOGI("Testing window %p", testCase->getNativeWindow()); + ASSERT_EQ(testCase->getAcquiredImageCount(), pictureCount); + } + ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount)); ACameraMetadata_free(staticMetadata); From 1622326c3c5ee468cf67b769b13b3dbb3fe9b560 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Fri, 14 Jun 2019 14:40:57 -0700 Subject: [PATCH 06/44] codec2: add color formats for image component Bug: 134461870 Test: atest CtsMediaTestCases:MediaCodecTest#testPrependHeadersToSyncFrames Change-Id: I8233ec928e7c5700abc1bdd7f32e097892947949 --- media/codec2/sfplugin/Codec2InfoBuilder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp index c54c6019c7..6b75ebafbe 100644 --- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp +++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp @@ -194,7 +194,8 @@ void addSupportedColorFormats( // TODO: get this from intf() as well, but how do we map them to // MediaCodec color formats? bool encoder = trait.kind == C2Component::KIND_ENCODER; - if (mediaType.find("video") != std::string::npos) { + if (mediaType.find("video") != std::string::npos + || mediaType.find("image") != std::string::npos) { // vendor video codecs prefer opaque format if (trait.name.find("android") == std::string::npos) { caps->addColorFormat(COLOR_FormatSurface); From b233eaef6a0b9a0b38845de252322c5e7418cdcf Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Thu, 20 Jun 2019 20:30:07 -0700 Subject: [PATCH 07/44] libcamera2ndk_vendor: stop looper thread on ~ACameraDevice() Bug: 135641415 Test: enroll; while(1) auth; Change-Id: I59c522a0e8827c5990926f0cf7c7960e1cea2e5e Signed-off-by: Jayant Chowdhary --- camera/ndk/ndk_vendor/impl/ACameraDevice.cpp | 10 ++++++++++ camera/ndk/ndk_vendor/impl/ACameraDevice.h | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp index a43d707e8e..8a3bb46711 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp +++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp @@ -44,6 +44,16 @@ using namespace android; +ACameraDevice::~ACameraDevice() { + Mutex::Autolock _l(mDevice->mDeviceLock); + if (mDevice->mCbLooper != nullptr) { + mDevice->mCbLooper->unregisterHandler(mDevice->mHandler->id()); + mDevice->mCbLooper->stop(); + } + mDevice->mCbLooper.clear(); + mDevice->mHandler.clear(); +} + namespace android { namespace acam { diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h index 829b08452e..d8df5684a7 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h +++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h @@ -135,6 +135,7 @@ class CameraDevice final : public RefBase { private: friend ACameraCaptureSession; + friend ACameraDevice; camera_status_t checkCameraClosedOrErrorLocked() const; @@ -383,8 +384,7 @@ struct ACameraDevice { sp chars) : mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {} - ~ACameraDevice() {}; - + ~ACameraDevice(); /******************* * NDK public APIs * *******************/ From 174084011ca8b593a8cf35412928517b9e864be9 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Fri, 21 Jun 2019 12:45:34 -0700 Subject: [PATCH 08/44] camera2 ndk/vndk: cleanup->stop CameraDevice's looper in ~ACameraDevice() It's possible that the following sequence happens: 1) hwbinder / binder thread T1: onResultReceived() starts -> promotes wp to sp<>; 2) Some other app thread T2 : ACameraDevice_close() -> delete ACameraDevice -> doesn't result in CameraDevice's destructor running since mCameraDevice has another live reference, app destroys some object O1. 3) T3 (callback looper thread): callback is received since looper is still running which accesses dead app object O1 -> results in undefined behavior. 4) T1: onResultReceived completes and CameraDevice is destructed We need to stop CameraDevice's looper thread (that waits for all callbacks queued to complete) in ~ACameraDevice() so we receive no callbacks after ACameraDevice is closed. Bug: 135641415 Test: CTS native tests: no new failures Test: AImageReaderVendorTest; enroll; while(1) auth; Change-Id: Ia24de753f6ee409d941fff39616f09df2164880a Signed-off-by: Jayant Chowdhary --- camera/ndk/impl/ACameraDevice.cpp | 22 ++++++++++++----- camera/ndk/impl/ACameraDevice.h | 5 +++- camera/ndk/ndk_vendor/impl/ACameraDevice.cpp | 26 ++++++++++---------- camera/ndk/ndk_vendor/impl/ACameraDevice.h | 3 +++ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp index 25a81ebc28..d24cb814a3 100644 --- a/camera/ndk/impl/ACameraDevice.cpp +++ b/camera/ndk/impl/ACameraDevice.cpp @@ -28,6 +28,10 @@ #include "ACameraCaptureSession.inc" +ACameraDevice::~ACameraDevice() { + mDevice->stopLooper(); +} + namespace android { namespace acam { @@ -116,14 +120,10 @@ CameraDevice::~CameraDevice() { if (!isClosed()) { disconnectLocked(session); } + LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr, + "CameraDevice looper should've been stopped before ~CameraDevice"); mCurrentSession = nullptr; - if (mCbLooper != nullptr) { - mCbLooper->unregisterHandler(mHandler->id()); - mCbLooper->stop(); - } } - mCbLooper.clear(); - mHandler.clear(); } void @@ -892,6 +892,16 @@ CameraDevice::onCaptureErrorLocked( return; } +void CameraDevice::stopLooper() { + Mutex::Autolock _l(mDeviceLock); + if (mCbLooper != nullptr) { + mCbLooper->unregisterHandler(mHandler->id()); + mCbLooper->stop(); + } + mCbLooper.clear(); + mHandler.clear(); +} + CameraDevice::CallbackHandler::CallbackHandler(const char* id) : mId(id) { } diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h index c92a95f822..7a35bf0e81 100644 --- a/camera/ndk/impl/ACameraDevice.h +++ b/camera/ndk/impl/ACameraDevice.h @@ -109,6 +109,9 @@ class CameraDevice final : public RefBase { inline ACameraDevice* getWrapper() const { return mWrapper; }; + // Stop the looper thread and unregister the handler + void stopLooper(); + private: friend ACameraCaptureSession; camera_status_t checkCameraClosedOrErrorLocked() const; @@ -354,7 +357,7 @@ struct ACameraDevice { sp chars) : mDevice(new android::acam::CameraDevice(id, cb, chars, this)) {} - ~ACameraDevice() {}; + ~ACameraDevice(); /******************* * NDK public APIs * diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp index 8a3bb46711..35c83551c2 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp +++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp @@ -45,13 +45,7 @@ using namespace android; ACameraDevice::~ACameraDevice() { - Mutex::Autolock _l(mDevice->mDeviceLock); - if (mDevice->mCbLooper != nullptr) { - mDevice->mCbLooper->unregisterHandler(mDevice->mHandler->id()); - mDevice->mCbLooper->stop(); - } - mDevice->mCbLooper.clear(); - mDevice->mHandler.clear(); + mDevice->stopLooper(); } namespace android { @@ -140,13 +134,9 @@ CameraDevice::~CameraDevice() { disconnectLocked(session); } mCurrentSession = nullptr; - if (mCbLooper != nullptr) { - mCbLooper->unregisterHandler(mHandler->id()); - mCbLooper->stop(); - } + LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr, + "CameraDevice looper should've been stopped before ~CameraDevice"); } - mCbLooper.clear(); - mHandler.clear(); } void @@ -1410,6 +1400,16 @@ CameraDevice::checkAndFireSequenceCompleteLocked() { } } +void CameraDevice::stopLooper() { + Mutex::Autolock _l(mDeviceLock); + if (mCbLooper != nullptr) { + mCbLooper->unregisterHandler(mHandler->id()); + mCbLooper->stop(); + } + mCbLooper.clear(); + mHandler.clear(); +} + /** * Camera service callback implementation */ diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h index d8df5684a7..9e034c48e1 100644 --- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h +++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h @@ -133,6 +133,9 @@ class CameraDevice final : public RefBase { bool setDeviceMetadataQueues(); inline ACameraDevice* getWrapper() const { return mWrapper; }; + // Stop the looper thread and unregister the handler + void stopLooper(); + private: friend ACameraCaptureSession; friend ACameraDevice; From 5bf11bf8ffb548c87fe409b6859c390e335a118e Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Mon, 24 Jun 2019 19:42:56 -0700 Subject: [PATCH 09/44] cameraserver: Fix logging for vendor clients in connectDevice Bug: 135658628 Test: GCA; auth Change-Id: I57c60f36461534c66d0c6eaa5bbe04f76a976dcb Signed-off-by: Jayant Chowdhary --- .../camera/libcameraservice/CameraService.cpp | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 3e6210294b..048d0e6bce 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -1149,6 +1149,8 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien clientPid, states[states.size() - 1]); + resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority(); + // Find clients that would be evicted auto evicted = mActiveClientManager.wouldEvict(clientDescriptor); @@ -1166,8 +1168,7 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien String8 msg = String8::format("%s : DENIED connect device %s client for package %s " "(PID %d, score %d state %d) due to eviction policy", curTime.string(), cameraId.string(), packageName.string(), clientPid, - priorityScores[priorityScores.size() - 1], - states[states.size() - 1]); + clientPriority.getScore(), clientPriority.getState()); for (auto& i : incompatibleClients) { msg.appendFormat("\n - Blocked by existing device %s client for package %s" @@ -1212,9 +1213,8 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien i->getKey().string(), String8{clientSp->getPackageName()}.string(), i->getOwnerId(), i->getPriority().getScore(), i->getPriority().getState(), cameraId.string(), - packageName.string(), clientPid, - priorityScores[priorityScores.size() - 1], - states[states.size() - 1])); + packageName.string(), clientPid, clientPriority.getScore(), + clientPriority.getState())); // Notify the client of disconnection clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED, @@ -1348,14 +1348,19 @@ Status CameraService::connectDevice( Status ret = Status::ok(); String8 id = String8(cameraId); sp client = nullptr; - + String16 clientPackageNameAdj = clientPackageName; + if (hardware::IPCThreadState::self()->isServingCall()) { + std::string vendorClient = + StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid()); + clientPackageNameAdj = String16(vendorClient.c_str()); + } ret = connectHelper(cameraCb, id, /*api1CameraId*/-1, - CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, + CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj, clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client); if(!ret.isOk()) { - logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName), + logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj), ret.toString8()); return ret; } @@ -2368,11 +2373,7 @@ CameraService::BasicClient::BasicClient(const sp& cameraService, } mClientPackageName = packages[0]; } - if (hardware::IPCThreadState::self()->isServingCall()) { - std::string vendorClient = - StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid()); - mClientPackageName = String16(vendorClient.c_str()); - } else { + if (!hardware::IPCThreadState::self()->isServingCall()) { mAppOpsManager = std::make_unique(); } } From eab904559f8c248787898783e442e92ffc53b529 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 24 Jun 2019 15:17:46 -0700 Subject: [PATCH 10/44] audioflinger: fix VoIP volume for fast track Also use audio HAL volume APIs for fast tracks opened on a specific VoIP RX output. Previous implementation was only considering regular tracks. Fix regular track implementation to send volume before it is altered by effect volume controller if present. Also only reflect stream and master volume in volume sent to HAL: track and shaper volumes are still applied by mixer. Bug: 133829194 Test: VoIP call Change-Id: Id5025a1f67df0eab7391056715047a23429e0f02 --- services/audioflinger/Threads.cpp | 80 ++++++++++++++++++------------- services/audioflinger/Threads.h | 1 + 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index ce408be113..bcd351d86b 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -3956,6 +3956,32 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) return INVALID_OPERATION; } +// For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is +// still applied by the mixer. +// All tracks attached to a mixer with flag VOIP_RX are tied to the same +// stream type STREAM_VOICE_CALL so this will only change the HAL volume once even +// if more than one track are active +status_t AudioFlinger::PlaybackThread::handleVoipVolume_l(float *volume) +{ + status_t result = NO_ERROR; + if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) { + if (*volume != mLeftVolFloat) { + result = mOutput->stream->setVolume(*volume, *volume); + ALOGE_IF(result != OK, + "Error when setting output stream volume: %d", result); + if (result == NO_ERROR) { + mLeftVolFloat = *volume; + } + } + // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we + // remove stream volume contribution from software volume. + if (mLeftVolFloat == *volume) { + *volume = 1.0f; + } + } + return result; +} + status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch, audio_patch_handle_t *handle) { @@ -4758,22 +4784,25 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // no acknowledgement required for newly active tracks } sp proxy = track->mAudioTrackServerProxy; - // cache the combined master volume and stream type volume for fast mixer; this - // lacks any synchronization or barrier so VolumeProvider may read a stale value - const float vh = track->getVolumeHandler()->getVolume( - proxy->framesReleased()).first; float volume; - if (track->isPlaybackRestricted()) { + if (track->isPlaybackRestricted() || mStreamTypes[track->streamType()].mute) { volume = 0.f; } else { - volume = masterVolume - * mStreamTypes[track->streamType()].volume - * vh; + volume = masterVolume * mStreamTypes[track->streamType()].volume; } + + handleVoipVolume_l(&volume); + + // cache the combined master volume and stream type volume for fast mixer; this + // lacks any synchronization or barrier so VolumeProvider may read a stale value + const float vh = track->getVolumeHandler()->getVolume( + proxy->framesReleased()).first; + volume *= vh; track->mCachedVolume = volume; gain_minifloat_packed_t vlr = proxy->getVolumeLR(); float vlf = volume * float_from_gain(gain_minifloat_unpack_left(vlr)); float vrf = volume * float_from_gain(gain_minifloat_unpack_right(vlr)); + track->setFinalVolume((vlf + vrf) / 2.f); ++fastTracks; } else { @@ -4916,20 +4945,22 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac uint32_t vl, vr; // in U8.24 integer format float vlf, vrf, vaf; // in [0.0, 1.0] float format // read original volumes with volume control - float typeVolume = mStreamTypes[track->streamType()].volume; - float v = masterVolume * typeVolume; + float v = masterVolume * mStreamTypes[track->streamType()].volume; // Always fetch volumeshaper volume to ensure state is updated. const sp proxy = track->mAudioTrackServerProxy; const float vh = track->getVolumeHandler()->getVolume( track->mAudioTrackServerProxy->framesReleased()).first; - if (track->isPausing() || mStreamTypes[track->streamType()].mute - || track->isPlaybackRestricted()) { + if (mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) { + v = 0; + } + + handleVoipVolume_l(&v); + + if (track->isPausing()) { vl = vr = 0; vlf = vrf = vaf = 0.; - if (track->isPausing()) { - track->setPaused(); - } + track->setPaused(); } else { gain_minifloat_packed_t vlr = proxy->getVolumeLR(); vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); @@ -4981,25 +5012,6 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac track->mHasVolumeController = false; } - // For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is - // still applied by the mixer. - if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) { - v = mStreamTypes[track->streamType()].mute ? 0.0f : v; - if (v != mLeftVolFloat) { - status_t result = mOutput->stream->setVolume(v, v); - ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result); - if (result == OK) { - mLeftVolFloat = v; - } - } - // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we - // remove stream volume contribution from software volume. - if (v != 0.0f && mLeftVolFloat == v) { - vlf = min(1.0f, vlf / v); - vrf = min(1.0f, vrf / v); - vaf = min(1.0f, vaf / v); - } - } // XXX: these things DON'T need to be done each time mAudioMixer->setBufferProvider(trackId, track); mAudioMixer->enable(trackId); diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 336c2b40a9..fc8aa13cbb 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -747,6 +747,7 @@ protected: // is safe to do so. That will drop the final ref count and destroy the tracks. virtual mixer_state prepareTracks_l(Vector< sp > *tracksToRemove) = 0; void removeTracks_l(const Vector< sp >& tracksToRemove); + status_t handleVoipVolume_l(float *volume); // StreamOutHalInterfaceCallback implementation virtual void onWriteReady(); From 99fd097ae6b9542051917270e6d2a92ae707da4a Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Thu, 27 Jun 2019 14:22:44 -0700 Subject: [PATCH 11/44] Camera: reduce long inflight request list spam By checking the expected duration for all inflight requests to finish and only log when it takes more than a threshold (5 secs) to process all inflight requests and the list is long. Test: manual testing Bug: 135927862 Change-Id: Iaa2c593f1e69f63b1da7d35d73c696de3510cd2c --- .../device3/Camera3Device.cpp | 24 ++++++++++++------- .../libcameraservice/device3/Camera3Device.h | 1 + 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 9771f9ee29..a1a4958e26 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -29,6 +29,9 @@ #define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \ ##__VA_ARGS__) +#define CLOGW(fmt, ...) ALOGW("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \ + ##__VA_ARGS__) + // Convenience macros for transitioning to the error state #define SET_ERR(fmt, ...) setErrorState( \ "%s: " fmt, __FUNCTION__, \ @@ -3267,14 +3270,19 @@ void Camera3Device::removeInFlightRequestIfReadyLocked(int idx) { ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber); } - // Sanity check - if we have too many in-flight frames, something has - // likely gone wrong - if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) { - CLOGE("In-flight list too large: %zu", mInFlightMap.size()); - } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > - kInFlightWarnLimitHighSpeed) { - CLOGE("In-flight list too large for high speed configuration: %zu", - mInFlightMap.size()); + // Sanity check - if we have too many in-flight frames with long total inflight duration, + // something has likely gone wrong. This might still be legit only if application send in + // a long burst of long exposure requests. + if (mExpectedInflightDuration > kMinWarnInflightDuration) { + if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) { + CLOGW("In-flight list too large: %zu, total inflight duration %" PRIu64, + mInFlightMap.size(), mExpectedInflightDuration); + } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > + kInFlightWarnLimitHighSpeed) { + CLOGW("In-flight list too large for high speed configuration: %zu," + "total inflight duration %" PRIu64, + mInFlightMap.size(), mExpectedInflightDuration); + } } } diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index 6e8ac849c0..cae34ce5c4 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -227,6 +227,7 @@ class Camera3Device : static const size_t kDumpLockAttempts = 10; static const size_t kDumpSleepDuration = 100000; // 0.10 sec static const nsecs_t kActiveTimeout = 500000000; // 500 ms + static const nsecs_t kMinWarnInflightDuration = 5000000000; // 5 s static const size_t kInFlightWarnLimit = 30; static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8 static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms From fceeee75b8a0cc4bdb22bc4c818ee8d42bf6db4f Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Fri, 14 Jun 2019 11:18:45 -0700 Subject: [PATCH 12/44] aaudio: account for hardware jitter in clock model This will allow AAudio to track the DSP better when the DSP has variable timing, such as when resampling. Keep track of the maximum lateness. Do not assume it is only one burst. Account for the lateness on the input streams so we don't try to read the data before the DSP has written it. Bug: 123643363 Test: record through iRig UA using Oboe Tester Test: see bug for details Change-Id: I49eb852c6d0324e8a26ee912da5108021ec113fe --- .../src/client/AudioStreamInternalCapture.cpp | 8 +- .../src/client/IsochronousClockModel.cpp | 102 +++++++++++++----- .../src/client/IsochronousClockModel.h | 37 ++++++- 3 files changed, 118 insertions(+), 29 deletions(-) diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp index a6cc45b464..366cc87209 100644 --- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp +++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp @@ -89,7 +89,11 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t if (mAudioEndpoint.isFreeRunning()) { //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter"); // Update data queue based on the timing model. - int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime); + // Jitter in the DSP can cause late writes to the FIFO. + // This might be caused by resampling. + // We want to read the FIFO after the latest possible time + // that the DSP could have written the data. + int64_t estimatedRemoteCounter = mClockModel.convertLatestTimeToPosition(currentNanoTime); // TODO refactor, maybe use setRemoteCounter() mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter); } @@ -139,7 +143,7 @@ aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t // the writeCounter might have just advanced in the background, // causing us to sleep until a later burst. int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst; - wakeTime = mClockModel.convertPositionToTime(nextPosition); + wakeTime = mClockModel.convertPositionToLatestTime(nextPosition); } break; default: diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp index d26b3523ac..9abdf53020 100644 --- a/media/libaaudio/src/client/IsochronousClockModel.cpp +++ b/media/libaaudio/src/client/IsochronousClockModel.cpp @@ -19,12 +19,11 @@ #include #include +#include #include "utility/AudioClock.h" #include "IsochronousClockModel.h" -#define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND) - using namespace aaudio; IsochronousClockModel::IsochronousClockModel() @@ -32,7 +31,7 @@ IsochronousClockModel::IsochronousClockModel() , mMarkerNanoTime(0) , mSampleRate(48000) , mFramesPerBurst(64) - , mMaxLatenessInNanos(0) + , mMaxMeasuredLatenessNanos(0) , mState(STATE_STOPPED) { } @@ -41,8 +40,7 @@ IsochronousClockModel::~IsochronousClockModel() { } void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) { - ALOGV("setPositionAndTime(%lld, %lld)", - (long long) framePosition, (long long) nanoTime); + ALOGV("setPositionAndTime, %lld, %lld", (long long) framePosition, (long long) nanoTime); mMarkerFramePosition = framePosition; mMarkerNanoTime = nanoTime; } @@ -54,7 +52,9 @@ void IsochronousClockModel::start(int64_t nanoTime) { } void IsochronousClockModel::stop(int64_t nanoTime) { - ALOGV("stop(nanos = %lld)\n", (long long) nanoTime); + ALOGD("stop(nanos = %lld) max lateness = %d micros\n", + (long long) nanoTime, + (int) (mMaxMeasuredLatenessNanos / 1000)); setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime); // TODO should we set position? mState = STATE_STOPPED; @@ -69,9 +69,10 @@ bool IsochronousClockModel::isRunning() const { } void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) { -// ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu", -// (long long)framePosition, -// (long long)nanoTime); + mTimestampCount++; +// Log position and time in CSV format so we can import it easily into spreadsheets. + //ALOGD("%s() CSV, %d, %lld, %lld", __func__, + //mTimestampCount, (long long)framePosition, (long long)nanoTime); int64_t framesDelta = framePosition - mMarkerFramePosition; int64_t nanosDelta = nanoTime - mMarkerNanoTime; if (nanosDelta < 1000) { @@ -110,22 +111,54 @@ void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nano // Earlier than expected timestamp. // This data is probably more accurate, so use it. // Or we may be drifting due to a fast HW clock. -// int microsDelta = (int) (nanosDelta / 1000); -// int expectedMicrosDelta = (int) (expectedNanosDelta / 1000); -// ALOGD("processTimestamp() - STATE_RUNNING - %7d < %7d so %4d micros EARLY", -// microsDelta, expectedMicrosDelta, (expectedMicrosDelta - microsDelta)); + //int microsDelta = (int) (nanosDelta / 1000); + //int expectedMicrosDelta = (int) (expectedNanosDelta / 1000); + //ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY", + //__func__, mTimestampCount, expectedMicrosDelta - microsDelta); setPositionAndTime(framePosition, nanoTime); - } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) { - // Later than expected timestamp. -// int microsDelta = (int) (nanosDelta / 1000); -// int expectedMicrosDeadline = (int) ((expectedNanosDelta + mMaxLatenessInNanos) / 1000); -// ALOGD("processTimestamp() - STATE_RUNNING - %7d > %7d so %4d micros LATE", -// microsDelta, expectedMicrosDeadline, (microsDelta - expectedMicrosDeadline)); - - // When we are late it may be because of preemption in the kernel or - // we may be drifting due to a slow HW clock. - setPositionAndTime(framePosition, nanoTime - mMaxLatenessInNanos); + } else if (nanosDelta > (expectedNanosDelta + (2 * mBurstPeriodNanos))) { + // In this case we do not update mMaxMeasuredLatenessNanos because it + // would force it too high. + // mMaxMeasuredLatenessNanos should range from 1 to 2 * mBurstPeriodNanos + //int32_t measuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta); + //ALOGD("%s() - STATE_RUNNING - #%d, lateness %d - max %d = %4d micros VERY LATE", + //__func__, + //mTimestampCount, + //measuredLatenessNanos / 1000, + //mMaxMeasuredLatenessNanos / 1000, + //(measuredLatenessNanos - mMaxMeasuredLatenessNanos) / 1000 + //); + + // This typically happens when we are modelling a service instead of a DSP. + setPositionAndTime(framePosition, nanoTime - (2 * mBurstPeriodNanos)); + } else if (nanosDelta > (expectedNanosDelta + mMaxMeasuredLatenessNanos)) { + //int32_t previousLatenessNanos = mMaxMeasuredLatenessNanos; + mMaxMeasuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta); + + //ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE", + //__func__, + //mTimestampCount, + //mMaxMeasuredLatenessNanos / 1000, + //previousLatenessNanos / 1000, + //(mMaxMeasuredLatenessNanos - previousLatenessNanos) / 1000 + //); + + // When we are late, it may be because of preemption in the kernel, + // or timing jitter caused by resampling in the DSP, + // or we may be drifting due to a slow HW clock. + // We add slight drift value just in case there is actual long term drift + // forward caused by a slower clock. + // If the clock is faster than the model will get pushed earlier + // by the code in the preceding branch. + // The two opposing forces should allow the model to track the real clock + // over a long time. + int64_t driftingTime = mMarkerNanoTime + expectedNanosDelta + kDriftNanos; + setPositionAndTime(framePosition, driftingTime); + //ALOGD("%s() - #%d, max lateness = %d micros", + //__func__, + //mTimestampCount, + //(int) (mMaxMeasuredLatenessNanos / 1000)); } break; default: @@ -145,9 +178,12 @@ void IsochronousClockModel::setFramesPerBurst(int32_t framesPerBurst) { update(); } +// Update expected lateness based on sampleRate and framesPerBurst void IsochronousClockModel::update() { - int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate - mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS; + mBurstPeriodNanos = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate + // Timestamps may be late by up to a burst because we are randomly sampling the time period + // after the DSP position is actually updated. + mMaxMeasuredLatenessNanos = mBurstPeriodNanos; } int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const { @@ -190,11 +226,25 @@ int64_t IsochronousClockModel::convertTimeToPosition(int64_t nanoTime) const { return position; } +int32_t IsochronousClockModel::getLateTimeOffsetNanos() const { + // This will never be < 0 because mMaxLatenessNanos starts at + // mBurstPeriodNanos and only gets bigger. + return (mMaxMeasuredLatenessNanos - mBurstPeriodNanos) + kExtraLatenessNanos; +} + +int64_t IsochronousClockModel::convertPositionToLatestTime(int64_t framePosition) const { + return convertPositionToTime(framePosition) + getLateTimeOffsetNanos(); +} + +int64_t IsochronousClockModel::convertLatestTimeToPosition(int64_t nanoTime) const { + return convertTimeToPosition(nanoTime - getLateTimeOffsetNanos()); +} + void IsochronousClockModel::dump() const { ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition); ALOGD("mMarkerNanoTime = %lld", (long long) mMarkerNanoTime); ALOGD("mSampleRate = %6d", mSampleRate); ALOGD("mFramesPerBurst = %6d", mFramesPerBurst); - ALOGD("mMaxLatenessInNanos = %6d", mMaxLatenessInNanos); + ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos); ALOGD("mState = %6d", mState); } diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h index 46ca48e7af..582bf4e34a 100644 --- a/media/libaaudio/src/client/IsochronousClockModel.h +++ b/media/libaaudio/src/client/IsochronousClockModel.h @@ -18,6 +18,7 @@ #define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H #include +#include "utility/AudioClock.h" namespace aaudio { @@ -78,6 +79,15 @@ public: */ int64_t convertPositionToTime(int64_t framePosition) const; + /** + * Calculate the latest estimated time that the stream will be at that position. + * The more jittery the clock is then the later this will be. + * + * @param framePosition + * @return time in nanoseconds + */ + int64_t convertPositionToLatestTime(int64_t framePosition) const; + /** * Calculate an estimated position where the stream will be at the specified time. * @@ -86,6 +96,18 @@ public: */ int64_t convertTimeToPosition(int64_t nanoTime) const; + /** + * Calculate the corresponding estimated position based on the specified time being + * the latest possible time. + * + * For the same nanoTime, this may return an earlier position than + * convertTimeToPosition(). + * + * @param nanoTime + * @return position in frames + */ + int64_t convertLatestTimeToPosition(int64_t nanoTime) const; + /** * @param framesDelta difference in frames * @return duration in nanoseconds @@ -101,6 +123,9 @@ public: void dump() const; private: + + int32_t getLateTimeOffsetNanos() const; + enum clock_model_state_t { STATE_STOPPED, STATE_STARTING, @@ -108,13 +133,23 @@ private: STATE_RUNNING }; + // Amount of time to drift forward when we get a late timestamp. + // This value was calculated to allow tracking of a clock with 50 ppm error. + static constexpr int32_t kDriftNanos = 10 * 1000; + // TODO review value of kExtraLatenessNanos + static constexpr int32_t kExtraLatenessNanos = 100 * 1000; + int64_t mMarkerFramePosition; int64_t mMarkerNanoTime; int32_t mSampleRate; int32_t mFramesPerBurst; - int32_t mMaxLatenessInNanos; + int32_t mBurstPeriodNanos; + // Includes mBurstPeriodNanos because we sample randomly over time. + int32_t mMaxMeasuredLatenessNanos; clock_model_state_t mState; + int32_t mTimestampCount = 0; + void update(); }; From bc84f5fa6b6f5c25b93e4f0fb4c1f6e5e339f752 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Thu, 27 Jun 2019 17:38:55 -0700 Subject: [PATCH 13/44] EffectBundle: Make effect draining more robust Enabling and disabling effects when offloaded may not drain software effects properly as the software effect process is not called. Make software effect draining more robust. Test: Play Music with offload effect enable and disable per bug. Bug: 130265457 Change-Id: Ibeeaca57359d6d82ddaa41d12caa9c03df225487 --- .../lvm/wrapper/Bundle/EffectBundle.cpp | 99 ++++++++++++++++--- .../lvm/wrapper/Bundle/EffectBundle.h | 8 ++ 2 files changed, 94 insertions(+), 13 deletions(-) diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 3fbbc096f5..10dda19181 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -302,6 +302,8 @@ extern "C" int EffectCreate(const effect_uuid_t *uuid, for (int i = 0; i < FIVEBAND_NUMBANDS; i++) { pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i]; } + pContext->pBundledContext->effectProcessCalled = 0; + pContext->pBundledContext->effectInDrain = 0; ALOGV("\tEffectCreate - Calling LvmBundle_init"); ret = LvmBundle_init(pContext); @@ -394,6 +396,8 @@ extern "C" int EffectRelease(effect_handle_t handle){ // Clear the instantiated flag for the effect // protect agains the case where an effect is un-instantiated without being disabled + + int &effectInDrain = pContext->pBundledContext->effectInDrain; if(pContext->EffectType == LVM_BASS_BOOST) { ALOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag"); pSessionContext->bBassInstantiated = LVM_FALSE; @@ -418,12 +422,16 @@ extern "C" int EffectRelease(effect_handle_t handle){ } else if(pContext->EffectType == LVM_VOLUME) { ALOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag"); pSessionContext->bVolumeInstantiated = LVM_FALSE; - if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){ + // There is no samplesToExitCount for volume so we also use the drain flag to check + // if we should decrement the effects enabled. + if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE + || (effectInDrain & 1 << LVM_VOLUME) != 0) { pContext->pBundledContext->NumberEffectsEnabled--; } } else { ALOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n"); } + effectInDrain &= ~(1 << pContext->EffectType); // no need to drain if released // Disable effect, in this case ignore errors (return codes) // if an effect has already been disabled @@ -3124,8 +3132,9 @@ LVM_INT16 LVC_ToDB_s32Tos16(LVM_INT32 Lin_fix) int Effect_setEnabled(EffectContext *pContext, bool enabled) { - ALOGV("\tEffect_setEnabled() type %d, enabled %d", pContext->EffectType, enabled); - + ALOGV("%s effectType %d, enabled %d, currently enabled %d", __func__, + pContext->EffectType, enabled, pContext->pBundledContext->NumberEffectsEnabled); + int &effectInDrain = pContext->pBundledContext->effectInDrain; if (enabled) { // Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due // to their nature. @@ -3139,6 +3148,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) if(pContext->pBundledContext->SamplesToExitCountBb <= 0){ pContext->pBundledContext->NumberEffectsEnabled++; } + effectInDrain &= ~(1 << LVM_BASS_BOOST); pContext->pBundledContext->SamplesToExitCountBb = (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); pContext->pBundledContext->bBassEnabled = LVM_TRUE; @@ -3152,6 +3162,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) if(pContext->pBundledContext->SamplesToExitCountEq <= 0){ pContext->pBundledContext->NumberEffectsEnabled++; } + effectInDrain &= ~(1 << LVM_EQUALIZER); pContext->pBundledContext->SamplesToExitCountEq = (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE; @@ -3164,6 +3175,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){ pContext->pBundledContext->NumberEffectsEnabled++; } + effectInDrain &= ~(1 << LVM_VIRTUALIZER); pContext->pBundledContext->SamplesToExitCountVirt = (LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1); pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE; @@ -3174,7 +3186,10 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) ALOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled"); return -EINVAL; } - pContext->pBundledContext->NumberEffectsEnabled++; + if ((effectInDrain & 1 << LVM_VOLUME) == 0) { + pContext->pBundledContext->NumberEffectsEnabled++; + } + effectInDrain &= ~(1 << LVM_VOLUME); pContext->pBundledContext->bVolumeEnabled = LVM_TRUE; break; default: @@ -3192,6 +3207,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) return -EINVAL; } pContext->pBundledContext->bBassEnabled = LVM_FALSE; + effectInDrain |= 1 << LVM_BASS_BOOST; break; case LVM_EQUALIZER: if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) { @@ -3199,6 +3215,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) return -EINVAL; } pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE; + effectInDrain |= 1 << LVM_EQUALIZER; break; case LVM_VIRTUALIZER: if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) { @@ -3206,6 +3223,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) return -EINVAL; } pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE; + effectInDrain |= 1 << LVM_VIRTUALIZER; break; case LVM_VOLUME: if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) { @@ -3213,6 +3231,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled) return -EINVAL; } pContext->pBundledContext->bVolumeEnabled = LVM_FALSE; + effectInDrain |= 1 << LVM_VOLUME; break; default: ALOGV("\tEffect_setEnabled() invalid effect type"); @@ -3283,6 +3302,38 @@ int Effect_process(effect_handle_t self, ALOGV("\tLVM_ERROR : Effect_process() ERROR NULL INPUT POINTER OR FRAME COUNT IS WRONG"); return -EINVAL; } + + int &effectProcessCalled = pContext->pBundledContext->effectProcessCalled; + int &effectInDrain = pContext->pBundledContext->effectInDrain; + if ((effectProcessCalled & 1 << pContext->EffectType) != 0) { + ALOGW("Effect %d already called", pContext->EffectType); + const int undrainedEffects = effectInDrain & ~effectProcessCalled; + if ((undrainedEffects & 1 << LVM_BASS_BOOST) != 0) { + ALOGW("Draining BASS_BOOST"); + pContext->pBundledContext->SamplesToExitCountBb = 0; + --pContext->pBundledContext->NumberEffectsEnabled; + effectInDrain &= ~(1 << LVM_BASS_BOOST); + } + if ((undrainedEffects & 1 << LVM_EQUALIZER) != 0) { + ALOGW("Draining EQUALIZER"); + pContext->pBundledContext->SamplesToExitCountEq = 0; + --pContext->pBundledContext->NumberEffectsEnabled; + effectInDrain &= ~(1 << LVM_EQUALIZER); + } + if ((undrainedEffects & 1 << LVM_VIRTUALIZER) != 0) { + ALOGW("Draining VIRTUALIZER"); + pContext->pBundledContext->SamplesToExitCountVirt = 0; + --pContext->pBundledContext->NumberEffectsEnabled; + effectInDrain &= ~(1 << LVM_VIRTUALIZER); + } + if ((undrainedEffects & 1 << LVM_VOLUME) != 0) { + ALOGW("Draining VOLUME"); + --pContext->pBundledContext->NumberEffectsEnabled; + effectInDrain &= ~(1 << LVM_VOLUME); + } + } + effectProcessCalled |= 1 << pContext->EffectType; + if ((pContext->pBundledContext->bBassEnabled == LVM_FALSE)&& (pContext->EffectType == LVM_BASS_BOOST)){ //ALOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled"); @@ -3291,9 +3342,12 @@ int Effect_process(effect_handle_t self, //ALOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left", // pContext->pBundledContext->SamplesToExitCountBb); } - if(pContext->pBundledContext->SamplesToExitCountBb <= 0) { + if (pContext->pBundledContext->SamplesToExitCountBb <= 0) { status = -ENODATA; - pContext->pBundledContext->NumberEffectsEnabled--; + if ((effectInDrain & 1 << LVM_BASS_BOOST) != 0) { + pContext->pBundledContext->NumberEffectsEnabled--; + effectInDrain &= ~(1 << LVM_BASS_BOOST); + } ALOGV("\tEffect_process() this is the last frame for LVM_BASS_BOOST"); } } @@ -3301,7 +3355,10 @@ int Effect_process(effect_handle_t self, (pContext->EffectType == LVM_VOLUME)){ //ALOGV("\tEffect_process() LVM_VOLUME Effect is not enabled"); status = -ENODATA; - pContext->pBundledContext->NumberEffectsEnabled--; + if ((effectInDrain & 1 << LVM_VOLUME) != 0) { + pContext->pBundledContext->NumberEffectsEnabled--; + effectInDrain &= ~(1 << LVM_VOLUME); + } } if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&& (pContext->EffectType == LVM_EQUALIZER)){ @@ -3311,9 +3368,12 @@ int Effect_process(effect_handle_t self, //ALOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left", // pContext->pBundledContext->SamplesToExitCountEq); } - if(pContext->pBundledContext->SamplesToExitCountEq <= 0) { + if (pContext->pBundledContext->SamplesToExitCountEq <= 0) { status = -ENODATA; - pContext->pBundledContext->NumberEffectsEnabled--; + if ((effectInDrain & 1 << LVM_EQUALIZER) != 0) { + pContext->pBundledContext->NumberEffectsEnabled--; + effectInDrain &= ~(1 << LVM_EQUALIZER); + } ALOGV("\tEffect_process() this is the last frame for LVM_EQUALIZER"); } } @@ -3326,9 +3386,12 @@ int Effect_process(effect_handle_t self, //ALOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left", // pContext->pBundledContext->SamplesToExitCountVirt); } - if(pContext->pBundledContext->SamplesToExitCountVirt <= 0) { + if (pContext->pBundledContext->SamplesToExitCountVirt <= 0) { status = -ENODATA; - pContext->pBundledContext->NumberEffectsEnabled--; + if ((effectInDrain & 1 << LVM_VIRTUALIZER) != 0) { + pContext->pBundledContext->NumberEffectsEnabled--; + effectInDrain &= ~(1 << LVM_VIRTUALIZER); + } ALOGV("\tEffect_process() this is the last frame for LVM_VIRTUALIZER"); } } @@ -3337,8 +3400,18 @@ int Effect_process(effect_handle_t self, pContext->pBundledContext->NumberEffectsCalled++; } - if(pContext->pBundledContext->NumberEffectsCalled == - pContext->pBundledContext->NumberEffectsEnabled){ + if (pContext->pBundledContext->NumberEffectsCalled >= + pContext->pBundledContext->NumberEffectsEnabled) { + + // We expect the # effects called to be equal to # effects enabled in sequence (including + // draining effects). Warn if this is not the case due to inconsistent calls. + ALOGW_IF(pContext->pBundledContext->NumberEffectsCalled > + pContext->pBundledContext->NumberEffectsEnabled, + "%s Number of effects called %d is greater than number of effects enabled %d", + __func__, pContext->pBundledContext->NumberEffectsCalled, + pContext->pBundledContext->NumberEffectsEnabled); + effectProcessCalled = 0; // reset our consistency check. + //ALOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d", //pContext->pBundledContext->NumberEffectsEnabled, //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType); diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h index 6af4554fc2..e4aacd0782 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h @@ -110,6 +110,14 @@ struct BundledEffectContext{ #ifdef SUPPORT_MC LVM_INT32 ChMask; #endif + + /* Bitmask whether drain is in progress due to disabling the effect. + The corresponding bit to an effect is set by 1 << lvm_effect_en. */ + int effectInDrain; + + /* Bitmask whether process() was called for a particular effect. + The corresponding bit to an effect is set by 1 << lvm_effect_en. */ + int effectProcessCalled; }; /* SessionContext : One session */ From ebca5b9862df0175b913f172384d80123a3865e3 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Mon, 1 Jul 2019 13:18:17 -0700 Subject: [PATCH 14/44] AImageReader: make sure ~AImageReader isn't called with FrameListener::mLock held. The following sequence of events is possible: t1: FrameListener::onFrameAvailable callback is called, mReader is promoted from wp<> to sp<>, t1 holds mLock. t2: AImageReader_delete is called, decStrong is called on AImageReader, but since its refcount isn't 0, ~AImageReader isn't called t1: onFrameAvailable completes, ~AImageReader is called with mLock held, ~AImageReader-> setImageListenerLocked->FrameListener::setImageListener->tries to lock mLock again, t1 deadlocks. We move the locking mLock to after the promotion of mReader to sp<> so that it gets destructed before ~AImageReader is called. The same is done for BufferRemovedListener. Bug: 136193631 Test: Auth; unlock Change-Id: I8bb8c7d59f3711fd9fe434159095938eb5db9153 Signed-off-by: Jayant Chowdhary --- media/ndk/NdkImageReader.cpp | 4 ++-- media/ndk/NdkImageReaderPriv.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp index baa4fc77ab..830f752a39 100644 --- a/media/ndk/NdkImageReader.cpp +++ b/media/ndk/NdkImageReader.cpp @@ -113,12 +113,12 @@ AImageReader::getNumPlanesForFormat(int32_t format) { void AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) { - Mutex::Autolock _l(mLock); sp reader = mReader.promote(); if (reader == nullptr) { ALOGW("A frame is available after AImageReader closed!"); return; // reader has been closed } + Mutex::Autolock _l(mLock); if (mListener.onImageAvailable == nullptr) { return; // No callback registered } @@ -143,12 +143,12 @@ AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listen void AImageReader::BufferRemovedListener::onBufferFreed(const wp& graphicBuffer) { - Mutex::Autolock _l(mLock); sp reader = mReader.promote(); if (reader == nullptr) { ALOGW("A frame is available after AImageReader closed!"); return; // reader has been closed } + Mutex::Autolock _l(mLock); if (mListener.onBufferRemoved == nullptr) { return; // No callback registered } diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h index e328cb1429..19bd704d9c 100644 --- a/media/ndk/NdkImageReaderPriv.h +++ b/media/ndk/NdkImageReaderPriv.h @@ -134,7 +134,7 @@ struct AImageReader : public RefBase { private: AImageReader_ImageListener mListener = {nullptr, nullptr}; - wp mReader; + const wp mReader; Mutex mLock; }; sp mFrameListener; @@ -149,7 +149,7 @@ struct AImageReader : public RefBase { private: AImageReader_BufferRemovedListener mListener = {nullptr, nullptr}; - wp mReader; + const wp mReader; Mutex mLock; }; sp mBufferRemovedListener; From 947c0f18f5f0836f745ac97e19ae1e9d1e29b6be Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Tue, 2 Jul 2019 09:28:16 -0700 Subject: [PATCH 15/44] Audio policy: fix HwModuleCollection::getDeviceDescriptor The deprecated method AudioManager.isBluetoothA2dpOn() calls getDeviceConnectionState on APM with an empty address, which caused HwModuleCollection::getDeviceDescriptor to set an empty address on the DeviceDescriptor for the currently connected A2DP device. This method is called by MediaRouter. When the address was reset, the java listener for audio device connection monitoring was reporting the connection of an A2DP device with an empty address, which in turn caused AvrcpManager to behave as if the audio device connection failed. If MediaRouter called isBluetoothA2dpOn() before AvrcpManager received its called for device connection, the error would occur. Bug: 132416679 Test: call isBluetoothA2dpOn() and check for valid address in dumpsys media.audio_policy Test: atest AudioServiceHostTest#testInjectForRecord ; atest AudioHostTest ; atest AudioPlaybackCaptureTest Change-Id: I1370edbbca46657506a990855d06a176f07c54d3 --- .../audiopolicy/common/managerdefinitions/src/HwModule.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp index 96a83377e1..1f9b725a24 100644 --- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp @@ -333,9 +333,10 @@ sp HwModuleCollection::getDeviceDescriptor(const audio_devices if (encodedFormat != AUDIO_FORMAT_DEFAULT) { moduleDevice->setEncodedFormat(encodedFormat); } - moduleDevice->setAddress(devAddress); if (allowToCreate) { moduleDevice->attach(hwModule); + moduleDevice->setAddress(devAddress); + moduleDevice->setName(String8(name)); } return moduleDevice; } From bd557938a1e201cd8246d2e638bb313917ced35c Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Tue, 2 Jul 2019 15:51:20 -0700 Subject: [PATCH 16/44] codec2: trim log Bug: 132461433 Test: bug repro steps Change-Id: Ie79b8948dc2eae773a433d90c23e7b6924bd503e --- media/codec2/sfplugin/CCodec.cpp | 6 +++++- media/codec2/sfplugin/CCodecConfig.cpp | 26 ++++++++++++++++++++++++-- media/codec2/sfplugin/CCodecConfig.h | 2 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp index aa7189cd17..895be1a6fb 100644 --- a/media/codec2/sfplugin/CCodec.cpp +++ b/media/codec2/sfplugin/CCodec.cpp @@ -374,7 +374,11 @@ public: // consumer usage is queried earlier. - ALOGD("ISConfig%s", status.str().c_str()); + if (status.str().empty()) { + ALOGD("ISConfig not changed"); + } else { + ALOGD("ISConfig%s", status.str().c_str()); + } return err; } diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp index 1cfdc19dad..104b10bdf2 100644 --- a/media/codec2/sfplugin/CCodecConfig.cpp +++ b/media/codec2/sfplugin/CCodecConfig.cpp @@ -235,7 +235,10 @@ struct StandardParams { const std::vector &getConfigMappersForSdkKey(std::string key) const { auto it = mConfigMappers.find(key); if (it == mConfigMappers.end()) { - ALOGD("no c2 equivalents for %s", key.c_str()); + if (mComplained.count(key) == 0) { + ALOGD("no c2 equivalents for %s", key.c_str()); + mComplained.insert(key); + } return NO_MAPPERS; } ALOGV("found %zu eqs for %s", it->second.size(), key.c_str()); @@ -304,6 +307,7 @@ struct StandardParams { private: std::map> mConfigMappers; + mutable std::set mComplained; }; const std::vector StandardParams::NO_MAPPERS; @@ -1033,7 +1037,25 @@ bool CCodecConfig::updateFormats(Domain domain) { } ReflectedParamUpdater::Dict reflected = mParamUpdater->getParams(paramPointers); - ALOGD("c2 config is %s", reflected.debugString().c_str()); + std::string config = reflected.debugString(); + std::set configLines; + std::string diff; + for (size_t start = 0; start != std::string::npos; ) { + size_t end = config.find('\n', start); + size_t count = (end == std::string::npos) + ? std::string::npos + : end - start + 1; + std::string line = config.substr(start, count); + configLines.insert(line); + if (mLastConfig.count(line) == 0) { + diff.append(line); + } + start = (end == std::string::npos) ? std::string::npos : end + 1; + } + if (!diff.empty()) { + ALOGD("c2 config diff is %s", diff.c_str()); + } + mLastConfig.swap(configLines); bool changed = false; if (domain & mInputDomain) { diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h index 3bafe3faf0..a61c8b7ddc 100644 --- a/media/codec2/sfplugin/CCodecConfig.h +++ b/media/codec2/sfplugin/CCodecConfig.h @@ -134,6 +134,8 @@ struct CCodecConfig { /// For now support a validation function. std::map mLocalParams; + std::set mLastConfig; + CCodecConfig(); /// initializes the members required to manage the format: descriptors, reflector, From e8e1c69626f56db48219d174240de0a1550a93c3 Mon Sep 17 00:00:00 2001 From: Aniket Kumar Lata Date: Wed, 3 Jul 2019 10:44:47 -0700 Subject: [PATCH 17/44] Visualizer: Fix deadlock on close Visualizer gets stuck in mCaptureThread::requestExitAndWait due to a deadlock between mCaptureThread::mRunning and mCaptureLock. Temporarily release mCaptureLock upon mCaptureThread::requestExitAndWait. Test: Clarity -> Response, rapidly toggle visualizer enable, disable Bug: 135326776 authored-by: Weiyin Jiang Change-Id: If32431c4d7b271b7ea61168cb1a5a42f3a1cd66e --- media/libmedia/Visualizer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index cb8d3750b7..2bf08020b3 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -77,10 +77,13 @@ status_t Visualizer::setEnabled(bool enabled) if (t != 0) { if (enabled) { if (t->exitPending()) { + mCaptureLock.unlock(); if (t->requestExitAndWait() == WOULD_BLOCK) { + mCaptureLock.lock(); ALOGE("Visualizer::enable() called from thread"); return INVALID_OPERATION; } + mCaptureLock.lock(); } } t->mLock.lock(); From 7a7e63456bcdba32ea41180d53fc9ecafba9c484 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Fri, 31 May 2019 16:28:21 -0700 Subject: [PATCH 18/44] Camera: Filter out NIR cameras for camera1 API This is to reduce application confusion when switching between back and front cameras. Test: Observe dumpsys on a phone with NIR camera device Bug: 133141567 Change-Id: I0c11b99fc3a0304d54562548d109df8c56ba1db1 --- .../libcameraservice/common/CameraProviderManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp index 09638d0289..98f93286a6 100644 --- a/services/camera/libcameraservice/common/CameraProviderManager.cpp +++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp @@ -2058,6 +2058,13 @@ status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraInfo( return OK; } bool CameraProviderManager::ProviderInfo::DeviceInfo3::isAPI1Compatible() const { + // Do not advertise NIR cameras to API1 camera app. + camera_metadata_ro_entry cfa = mCameraCharacteristics.find( + ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); + if (cfa.count == 1 && cfa.data.u8[0] == ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR) { + return false; + } + bool isBackwardCompatible = false; camera_metadata_ro_entry_t caps = mCameraCharacteristics.find( ANDROID_REQUEST_AVAILABLE_CAPABILITIES); From 1858832f4708285eb5b2ace02d2a580125087d3c Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Sat, 18 May 2019 01:52:13 -0700 Subject: [PATCH 19/44] Allow creation of input surface in CCodec Currently, an input surface to an encoder is created in the codec process, but the queue operation has to be issued from the application process. This CL allows an input surface to be created in the application process, hence reducing the number of IPCs issued per frame. This option can be chosen by setting "debug.stagefright.c2inputsurface" to -1. (If the property is not set, it defaults to 0, which picks the current behavior.) Test: adb shell setprop debug.stagefright.c2inputsurface -1 Then, record a video. Bug: 131800183 Bug: 134017277 Change-Id: Idbf2ba87689e1e876a215850aa0260539183a4ee --- media/codec2/hidl/client/client.cpp | 6 +- media/codec2/sfplugin/Android.bp | 3 + media/codec2/sfplugin/CCodec.cpp | 27 ++- .../sfplugin/Omx2IGraphicBufferSource.cpp | 185 ++++++++++++++++++ .../sfplugin/Omx2IGraphicBufferSource.h | 47 +++++ media/libstagefright/omx/Android.bp | 1 - 6 files changed, 260 insertions(+), 9 deletions(-) create mode 100644 media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp create mode 100644 media/codec2/sfplugin/Omx2IGraphicBufferSource.h diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp index 2b417a648e..5ed54f1a24 100644 --- a/media/codec2/hidl/client/client.cpp +++ b/media/codec2/hidl/client/client.cpp @@ -959,9 +959,9 @@ std::vector const& Codec2Client::ListComponents() { std::shared_ptr Codec2Client::CreateInputSurface( char const* serviceName) { - uint32_t inputSurfaceSetting = ::android::base::GetUintProperty( - "debug.stagefright.c2inputsurface", uint32_t(0)); - if (inputSurfaceSetting == 0) { + int32_t inputSurfaceSetting = ::android::base::GetIntProperty( + "debug.stagefright.c2inputsurface", int32_t(0)); + if (inputSurfaceSetting <= 0) { return nullptr; } size_t index = GetServiceNames().size(); diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp index 8ae80eeb9d..9c84c711e2 100644 --- a/media/codec2/sfplugin/Android.bp +++ b/media/codec2/sfplugin/Android.bp @@ -9,6 +9,7 @@ cc_library_shared { "CCodecConfig.cpp", "Codec2Buffer.cpp", "Codec2InfoBuilder.cpp", + "Omx2IGraphicBufferSource.cpp", "PipelineWatcher.cpp", "ReflectedParamUpdater.cpp", "SkipCutBuffer.cpp", @@ -41,8 +42,10 @@ cc_library_shared { "libmedia", "libmedia_omx", "libsfplugin_ccodec_utils", + "libstagefright_bufferqueue_helper", "libstagefright_codecbase", "libstagefright_foundation", + "libstagefright_omx", "libstagefright_omx_utils", "libstagefright_xmlparser", "libui", diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp index aa7189cd17..9d1cc60419 100644 --- a/media/codec2/sfplugin/CCodec.cpp +++ b/media/codec2/sfplugin/CCodec.cpp @@ -45,6 +45,7 @@ #include "CCodec.h" #include "CCodecBufferChannel.h" #include "InputSurfaceWrapper.h" +#include "Omx2IGraphicBufferSource.h" extern "C" android::PersistentSurface *CreateInputSurface(); @@ -1067,6 +1068,7 @@ sp CCodec::CreateOmxInputSurface() { OmxStatus s; android::sp gbp; android::sp gbs; + using ::android::hardware::Return; Return transStatus = omx->createInputSurface( [&s, &gbp, &gbs]( @@ -1852,15 +1854,30 @@ extern "C" android::CodecBase *CreateCodec() { // Create Codec 2.0 input surface extern "C" android::PersistentSurface *CreateInputSurface() { + using namespace android; // Attempt to create a Codec2's input surface. - std::shared_ptr inputSurface = - android::Codec2Client::CreateInputSurface(); + std::shared_ptr inputSurface = + Codec2Client::CreateInputSurface(); if (!inputSurface) { - return nullptr; + if (property_get_int32("debug.stagefright.c2inputsurface", 0) == -1) { + sp gbp; + sp gbs = new OmxGraphicBufferSource(); + status_t err = gbs->initCheck(); + if (err != OK) { + ALOGE("Failed to create persistent input surface: error %d", err); + return nullptr; + } + return new PersistentSurface( + gbs->getIGraphicBufferProducer(), + sp( + new Omx2IGraphicBufferSource(gbs))); + } else { + return nullptr; + } } - return new android::PersistentSurface( + return new PersistentSurface( inputSurface->getGraphicBufferProducer(), - static_cast>( + static_cast>( inputSurface->getHalInterface())); } diff --git a/media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp b/media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp new file mode 100644 index 0000000000..764fa001ec --- /dev/null +++ b/media/codec2/sfplugin/Omx2IGraphicBufferSource.cpp @@ -0,0 +1,185 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef __LP64__ +#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS +#endif + +//#define LOG_NDEBUG 0 +#define LOG_TAG "Omx2IGraphicBufferSource" +#include + +#include "Omx2IGraphicBufferSource.h" + +#include +#include +#include + +#include +#include +#include + +namespace android { + +namespace /* unnamed */ { + +// OmxGraphicBufferSource -> IOMXBufferSource + +struct OmxGbs2IOmxBs : public BnOMXBufferSource { + sp mBase; + OmxGbs2IOmxBs(sp const& base) : mBase{base} {} + BnStatus onOmxExecuting() override { + return mBase->onOmxExecuting(); + } + BnStatus onOmxIdle() override { + return mBase->onOmxIdle(); + } + BnStatus onOmxLoaded() override { + return mBase->onOmxLoaded(); + } + BnStatus onInputBufferAdded(int32_t bufferId) override { + return mBase->onInputBufferAdded(bufferId); + } + BnStatus onInputBufferEmptied( + int32_t bufferId, + OMXFenceParcelable const& fenceParcel) override { + return mBase->onInputBufferEmptied(bufferId, fenceParcel.get()); + } +}; + +struct OmxNodeWrapper : public IOmxNodeWrapper { + sp mBase; + OmxNodeWrapper(sp const& base) : mBase{base} {} + status_t emptyBuffer( + int32_t bufferId, uint32_t flags, + const sp &buffer, + int64_t timestamp, int fenceFd) override { + return mBase->emptyBuffer(bufferId, buffer, flags, timestamp, fenceFd); + } + void dispatchDataSpaceChanged( + int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override { + omx_message msg{}; + msg.type = omx_message::EVENT; + msg.fenceFd = -1; + msg.u.event_data.event = OMX_EventDataSpaceChanged; + msg.u.event_data.data1 = dataSpace; + msg.u.event_data.data2 = aspects; + msg.u.event_data.data3 = pixelFormat; + mBase->dispatchMessage(msg); + } +}; + +} // unnamed namespace + +// Omx2IGraphicBufferSource +Omx2IGraphicBufferSource::Omx2IGraphicBufferSource( + sp const& base) + : mBase{base}, + mOMXBufferSource{new OmxGbs2IOmxBs(base)} { +} + +BnStatus Omx2IGraphicBufferSource::setSuspend( + bool suspend, int64_t timeUs) { + return BnStatus::fromStatusT(mBase->setSuspend(suspend, timeUs)); +} + +BnStatus Omx2IGraphicBufferSource::setRepeatPreviousFrameDelayUs( + int64_t repeatAfterUs) { + return BnStatus::fromStatusT(mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs)); +} + +BnStatus Omx2IGraphicBufferSource::setMaxFps(float maxFps) { + return BnStatus::fromStatusT(mBase->setMaxFps(maxFps)); +} + +BnStatus Omx2IGraphicBufferSource::setTimeLapseConfig( + double fps, double captureFps) { + return BnStatus::fromStatusT(mBase->setTimeLapseConfig(fps, captureFps)); +} + +BnStatus Omx2IGraphicBufferSource::setStartTimeUs( + int64_t startTimeUs) { + return BnStatus::fromStatusT(mBase->setStartTimeUs(startTimeUs)); +} + +BnStatus Omx2IGraphicBufferSource::setStopTimeUs( + int64_t stopTimeUs) { + return BnStatus::fromStatusT(mBase->setStopTimeUs(stopTimeUs)); +} + +BnStatus Omx2IGraphicBufferSource::getStopTimeOffsetUs( + int64_t *stopTimeOffsetUs) { + return BnStatus::fromStatusT(mBase->getStopTimeOffsetUs(stopTimeOffsetUs)); +} + +BnStatus Omx2IGraphicBufferSource::setColorAspects( + int32_t aspects) { + return BnStatus::fromStatusT(mBase->setColorAspects(aspects)); +} + +BnStatus Omx2IGraphicBufferSource::setTimeOffsetUs( + int64_t timeOffsetsUs) { + return BnStatus::fromStatusT(mBase->setTimeOffsetUs(timeOffsetsUs)); +} + +BnStatus Omx2IGraphicBufferSource::signalEndOfInputStream() { + return BnStatus::fromStatusT(mBase->signalEndOfInputStream()); +} + +BnStatus Omx2IGraphicBufferSource::configure( + const sp& omxNode, int32_t dataSpace) { + if (omxNode == NULL) { + return BnStatus::fromServiceSpecificError(BAD_VALUE); + } + + // Do setInputSurface() first, the node will try to enable metadata + // mode on input, and does necessary error checking. If this fails, + // we can't use this input surface on the node. + status_t err = omxNode->setInputSurface(mOMXBufferSource); + if (err != NO_ERROR) { + ALOGE("Unable to set input surface: %d", err); + return BnStatus::fromServiceSpecificError(err); + } + + uint32_t consumerUsage; + if (omxNode->getParameter( + (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, + &consumerUsage, sizeof(consumerUsage)) != OK) { + consumerUsage = 0; + } + + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = 0; // kPortIndexInput + + err = omxNode->getParameter( + OMX_IndexParamPortDefinition, &def, sizeof(def)); + if (err != NO_ERROR) { + ALOGE("Failed to get port definition: %d", err); + return BnStatus::fromServiceSpecificError(UNKNOWN_ERROR); + } + + return BnStatus::fromStatusT(mBase->configure( + new OmxNodeWrapper(omxNode), + dataSpace, + def.nBufferCountActual, + def.format.video.nFrameWidth, + def.format.video.nFrameHeight, + consumerUsage)); +} + +} // namespace android + diff --git a/media/codec2/sfplugin/Omx2IGraphicBufferSource.h b/media/codec2/sfplugin/Omx2IGraphicBufferSource.h new file mode 100644 index 0000000000..20fd1ecb4b --- /dev/null +++ b/media/codec2/sfplugin/Omx2IGraphicBufferSource.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OMX_2_IGRAPHICBUFFERSOURCE_H_ +#define OMX_2_IGRAPHICBUFFERSOURCE_H_ + +#include +#include + +namespace android { + +using BnStatus = ::android::binder::Status; + +struct Omx2IGraphicBufferSource : public BnGraphicBufferSource { + sp mBase; + sp mOMXBufferSource; + Omx2IGraphicBufferSource(sp const& base); + BnStatus configure(const sp& omxNode, int32_t dataSpace) override; + BnStatus setSuspend(bool suspend, int64_t timeUs) override; + BnStatus setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override; + BnStatus setMaxFps(float maxFps) override; + BnStatus setTimeLapseConfig(double fps, double captureFps) override; + BnStatus setStartTimeUs(int64_t startTimeUs) override; + BnStatus setStopTimeUs(int64_t stopTimeUs) override; + BnStatus getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) override; + BnStatus setColorAspects(int32_t aspects) override; + BnStatus setTimeOffsetUs(int64_t timeOffsetsUs) override; + BnStatus signalEndOfInputStream() override; +}; + +} // namespace android + +#endif // OMX_2_IGRAPHICBUFFERSOURCE_H_ + diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp index e260cae115..7d03d98ccf 100644 --- a/media/libstagefright/omx/Android.bp +++ b/media/libstagefright/omx/Android.bp @@ -72,7 +72,6 @@ cc_library_shared { cfi: true, }, - compile_multilib: "32", } cc_library_shared { From 20b29ddacc0acc04706882e1b006ad8589c52698 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Fri, 14 Jun 2019 14:40:57 -0700 Subject: [PATCH 20/44] codec2: add color formats for image component Bug: 136731683 Test: atest CtsMediaTestCases:MediaCodecTest#testPrependHeadersToSyncFrames Merged-In: I8233ec928e7c5700abc1bdd7f32e097892947949 Change-Id: I8233ec928e7c5700abc1bdd7f32e097892947949 (cherry picked from commit 1622326c3c5ee468cf67b769b13b3dbb3fe9b560) --- media/codec2/sfplugin/Codec2InfoBuilder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp index c54c6019c7..6b75ebafbe 100644 --- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp +++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp @@ -194,7 +194,8 @@ void addSupportedColorFormats( // TODO: get this from intf() as well, but how do we map them to // MediaCodec color formats? bool encoder = trait.kind == C2Component::KIND_ENCODER; - if (mediaType.find("video") != std::string::npos) { + if (mediaType.find("video") != std::string::npos + || mediaType.find("image") != std::string::npos) { // vendor video codecs prefer opaque format if (trait.name.find("android") == std::string::npos) { caps->addColorFormat(COLOR_FormatSurface); From 2cd83c9fbbd286768999ade97f7fce4b409b06c4 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Wed, 10 Jul 2019 17:50:49 -0700 Subject: [PATCH 21/44] Skip secure decoders in C2 VTS Test: vts-tradefed run vts -m VtsHalMediaC2V1_0Host Bug: 136725027 Change-Id: I78e141c04890ab153135a7cc948e2b7dc4897787 --- .../video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp index 0e20b4706d..5e28750014 100644 --- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp +++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp @@ -124,6 +124,13 @@ class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase { mTimestampUs = 0u; mTimestampDevTest = false; if (mCompName == unknown_comp) mDisableTest = true; + + C2SecureModeTuning secureModeTuning{}; + mComponent->query({ &secureModeTuning }, {}, C2_MAY_BLOCK, nullptr); + if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) { + mDisableTest = true; + } + if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n"; } From 2142c72cd74f0b303a676192f2d9d1285dbc2bda Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Thu, 11 Jul 2019 15:14:50 +0100 Subject: [PATCH 22/44] Remove unnecessary use of external/icu/icu4c/source/common This is no longer necessary because the headers are exported by the libicuuc library which is a dependency of libxml2. Bug: 134379140 Change-Id: I01dfe41c6584d71de47a5a76e1f7cc718083ca8c Test: m libaudiopolicyengine_config --- services/audiopolicy/engine/config/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp index 6e72f2a5e4..885b5fa2c9 100644 --- a/services/audiopolicy/engine/config/Android.bp +++ b/services/audiopolicy/engine/config/Android.bp @@ -3,7 +3,6 @@ cc_library_static { export_include_dirs: ["include"], include_dirs: [ "external/libxml2/include", - "external/icu/icu4c/source/common", ], srcs: [ "src/EngineConfig.cpp", From ec58800670ec93ebac13c5861e97c7e9c138ead9 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Thu, 11 Jul 2019 13:43:38 -0700 Subject: [PATCH 23/44] codec2: make i-frame-interval write-only Bug: 134533155 Test: bug repro steps Change-Id: I8ef4fd3c5035f0719cf43b727b641f3f94f08c58 --- media/codec2/sfplugin/CCodecConfig.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp index 1cfdc19dad..3dbd666638 100644 --- a/media/codec2/sfplugin/CCodecConfig.cpp +++ b/media/codec2/sfplugin/CCodecConfig.cpp @@ -508,7 +508,8 @@ void CCodecConfig::initializeStandardParams() { .limitTo(D::ENCODER & D::VIDEO)); // convert to timestamp base add(ConfigMapper(KEY_I_FRAME_INTERVAL, C2_PARAMKEY_SYNC_FRAME_INTERVAL, "value") - .withMappers([](C2Value v) -> C2Value { + .limitTo(D::VIDEO & D::ENCODER & D::CONFIG) + .withMapper([](C2Value v) -> C2Value { // convert from i32 to float int32_t i32Value; float fpValue; @@ -518,12 +519,6 @@ void CCodecConfig::initializeStandardParams() { return int64_t(c2_min(1000000 * fpValue + 0.5, (double)INT64_MAX)); } return C2Value(); - }, [](C2Value v) -> C2Value { - int64_t i64; - if (v.get(&i64)) { - return float(i64) / 1000000; - } - return C2Value(); })); // remove when codecs switch to proper coding.gop (add support for calculating gop) deprecated(ConfigMapper("i-frame-period", "coding.gop", "intra-period") From 441ed65bc852b3a27f9265e56d2411da62a780e5 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Thu, 11 Jul 2019 14:55:16 -0700 Subject: [PATCH 24/44] AudioPolicy: do not cap a11y volume during call screening Add accessibility playback as exemption for volume capping during call screening. Bug: 133879660 Test: enable Talkback, receive a call, screen it, touch responses icons, verify labels are read Change-Id: I661a544261ef57e439b3eb8cf3d1dde1c31ac303 --- .../audiopolicy/managerdefault/AudioPolicyManager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index a6730fc4be..c42f1f33da 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -5689,8 +5689,9 @@ float AudioPolicyManager::computeVolume(IVolumeCurves &curves, const auto ringVolumeSrc = toVolumeSource(AUDIO_STREAM_RING); const auto musicVolumeSrc = toVolumeSource(AUDIO_STREAM_MUSIC); const auto alarmVolumeSrc = toVolumeSource(AUDIO_STREAM_ALARM); + const auto a11yVolumeSrc = toVolumeSource(AUDIO_STREAM_ACCESSIBILITY); - if (volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY) + if (volumeSource == a11yVolumeSrc && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) && mOutputs.isActive(ringVolumeSrc, 0)) { auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING); @@ -5707,7 +5708,7 @@ float AudioPolicyManager::computeVolume(IVolumeCurves &curves, volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION) || volumeSource == toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) || volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) || - volumeSource == toVolumeSource(AUDIO_STREAM_ACCESSIBILITY))) { + volumeSource == a11yVolumeSrc)) { auto &voiceCurves = getVolumeCurves(callVolumeSrc); int voiceVolumeIndex = voiceCurves.getVolumeIndex(device); const float maxVoiceVolDb = @@ -5719,7 +5720,9 @@ float AudioPolicyManager::computeVolume(IVolumeCurves &curves, // VOICE_CALL stream has minVolumeIndex > 0 : Users cannot set the volume of voice calls to // 0. We don't want to cap volume when the system has programmatically muted the voice call // stream. See setVolumeCurveIndex() for more information. - bool exemptFromCapping = (volumeSource == ringVolumeSrc) && (voiceVolumeIndex == 0); + bool exemptFromCapping = + ((volumeSource == ringVolumeSrc) || (volumeSource == a11yVolumeSrc)) + && (voiceVolumeIndex == 0); ALOGV_IF(exemptFromCapping, "%s volume source %d at vol=%f not capped", __func__, volumeSource, volumeDb); if ((volumeDb > maxVoiceVolDb) && !exemptFromCapping) { From 1221fd1704150c76f175afe5bf46436236bdf48b Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Fri, 12 Jul 2019 12:52:05 -0700 Subject: [PATCH 25/44] codec2: force array mode for graphic metadata buffers Bug: 133291455 Test: bug repro steps (10 times) Change-Id: I7513a97dcfa50df880539a4a121c697952aae36a --- media/codec2/sfplugin/CCodecBufferChannel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp index 09049b9e84..8308292512 100644 --- a/media/codec2/sfplugin/CCodecBufferChannel.cpp +++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp @@ -896,6 +896,9 @@ status_t CCodecBufferChannel::start( input->buffers.reset(new DummyInputBuffers(mName)); } else if (mMetaMode == MODE_ANW) { input->buffers.reset(new GraphicMetadataInputBuffers(mName)); + // This is to ensure buffers do not get released prematurely. + // TODO: handle this without going into array mode + forceArrayMode = true; } else { input->buffers.reset(new GraphicInputBuffers(numInputSlots, mName)); } From 7bd2939d6ce0574f01771b8569b1d76faf2b09b7 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Sat, 13 Jul 2019 09:32:47 -0700 Subject: [PATCH 26/44] audio policy: fix mmap capture disconnect Force close mmap input streams when a capture device is connected to force disconnect callback to client. Bug: 137311579 Test: capture with oboetester and connect headset Change-Id: Iafe939247fa565e2424b40afacdb79a31b8955b7 --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index a6730fc4be..1d4dacd4e9 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -2396,7 +2396,8 @@ void AudioPolicyManager::checkCloseInputs() { for (size_t i = 0; i < mInputs.size(); i++) { const sp input = mInputs.valueAt(i); if (input->clientsList().size() == 0 - || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) { + || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices()) + || (input->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) { inputsToClose.push_back(mInputs.keyAt(i)); } else { bool close = false; From c833ccc86b8af68cfb80de182309be6d4eaac860 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Sat, 13 Jul 2019 09:32:47 -0700 Subject: [PATCH 27/44] audio policy: fix mmap capture disconnect Force close mmap input streams when a capture device is connected to force disconnect callback to client. Bug: 137311579 Test: capture with oboetester and connect headset Change-Id: Iafe939247fa565e2424b40afacdb79a31b8955b7 (cherry picked from commit 7bd2939d6ce0574f01771b8569b1d76faf2b09b7) --- services/audiopolicy/managerdefault/AudioPolicyManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index a6730fc4be..1d4dacd4e9 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -2396,7 +2396,8 @@ void AudioPolicyManager::checkCloseInputs() { for (size_t i = 0; i < mInputs.size(); i++) { const sp input = mInputs.valueAt(i); if (input->clientsList().size() == 0 - || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) { + || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices()) + || (input->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) { inputsToClose.push_back(mInputs.keyAt(i)); } else { bool close = false; From 9e0302fcc104bbeddc4c9c0f913b9f633de84dc1 Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Tue, 16 Jul 2019 11:04:06 -0700 Subject: [PATCH 28/44] AImage: don't allow ~AImageReader to run before AImages are deleted. We can never be sure whether ~AImageReader() has run to completion or not in AImage::close(). So we move clean up to another AImageReader method and make sure that's called when in AImageReader_delete. AImage now contains an sp<> to AImageReader so we can be sure that its members wouldn't have been destroyed by ~AImageReader and we can check whether AImageReader_delete has been called on it. This also prevents us from deadlocking since AImage_delete could also cause ~AImageReader to run with AImageReader::mLock held in AImage::close(). Bug: 137571625 Bug: 137694217 Test: enroll; auth Test: cts native AImageReader, camera, graphics tests Change-Id: If5803cb6fcb6f4800032069872daaeac1cd36ed2 Signed-off-by: Jayant Chowdhary --- media/ndk/NdkImage.cpp | 24 +++++------------------- media/ndk/NdkImagePriv.h | 2 +- media/ndk/NdkImageReader.cpp | 12 +++++++++++- media/ndk/NdkImageReaderPriv.h | 2 ++ 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp index 1883f6356d..1145b7b79f 100644 --- a/media/ndk/NdkImage.cpp +++ b/media/ndk/NdkImage.cpp @@ -35,6 +35,7 @@ AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage, BufferItem* int64_t timestamp, int32_t width, int32_t height, int32_t numPlanes) : mReader(reader), mFormat(format), mUsage(usage), mBuffer(buffer), mLockedBuffer(nullptr), mTimestamp(timestamp), mWidth(width), mHeight(height), mNumPlanes(numPlanes) { + LOG_FATAL_IF(reader == nullptr, "AImageReader shouldn't be null while creating AImage"); } AImage::~AImage() { @@ -57,14 +58,9 @@ AImage::close(int releaseFenceFd) { if (mIsClosed) { return; } - sp reader = mReader.promote(); - if (reader != nullptr) { - reader->releaseImageLocked(this, releaseFenceFd); - } else if (mBuffer != nullptr) { - LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p", - __FUNCTION__, this); + if (!mReader->mIsClosed) { + mReader->releaseImageLocked(this, releaseFenceFd); } - // Should have been set to nullptr in releaseImageLocked // Set to nullptr here for extra safety only mBuffer = nullptr; @@ -83,22 +79,12 @@ AImage::free() { void AImage::lockReader() const { - sp reader = mReader.promote(); - if (reader == nullptr) { - // Reader has been closed - return; - } - reader->mLock.lock(); + mReader->mLock.lock(); } void AImage::unlockReader() const { - sp reader = mReader.promote(); - if (reader == nullptr) { - // Reader has been closed - return; - } - reader->mLock.unlock(); + mReader->mLock.unlock(); } media_status_t diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h index e0f16dadf9..0e8cbcbf78 100644 --- a/media/ndk/NdkImagePriv.h +++ b/media/ndk/NdkImagePriv.h @@ -72,7 +72,7 @@ struct AImage { uint32_t getJpegSize() const; // When reader is close, AImage will only accept close API call - wp mReader; + const sp mReader; const int32_t mFormat; const uint64_t mUsage; // AHARDWAREBUFFER_USAGE_* flags. BufferItem* mBuffer; diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp index 830f752a39..c0ceb3d70b 100644 --- a/media/ndk/NdkImageReader.cpp +++ b/media/ndk/NdkImageReader.cpp @@ -272,6 +272,11 @@ AImageReader::AImageReader(int32_t width, mFrameListener(new FrameListener(this)), mBufferRemovedListener(new BufferRemovedListener(this)) {} +AImageReader::~AImageReader() { + Mutex::Autolock _l(mLock); + LOG_FATAL_IF("AImageReader not closed before destruction", mIsClosed != true); +} + media_status_t AImageReader::init() { PublicFormat publicFormat = static_cast(mFormat); @@ -347,8 +352,12 @@ AImageReader::init() { return AMEDIA_OK; } -AImageReader::~AImageReader() { +void AImageReader::close() { Mutex::Autolock _l(mLock); + if (mIsClosed) { + return; + } + mIsClosed = true; AImageReader_ImageListener nullListener = {nullptr, nullptr}; setImageListenerLocked(&nullListener); @@ -741,6 +750,7 @@ EXPORT void AImageReader_delete(AImageReader* reader) { ALOGV("%s", __FUNCTION__); if (reader != nullptr) { + reader->close(); reader->decStrong((void*) AImageReader_delete); } return; diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h index 19bd704d9c..0779a716bf 100644 --- a/media/ndk/NdkImageReaderPriv.h +++ b/media/ndk/NdkImageReaderPriv.h @@ -76,6 +76,7 @@ struct AImageReader : public RefBase { int32_t getHeight() const { return mHeight; }; int32_t getFormat() const { return mFormat; }; int32_t getMaxImages() const { return mMaxImages; }; + void close(); private: @@ -165,6 +166,7 @@ struct AImageReader : public RefBase { native_handle_t* mWindowHandle = nullptr; List mAcquiredImages; + bool mIsClosed = false; Mutex mLock; }; From 86fdb97cbb82464b0d021f16d7ad8752bf4b2767 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 12 Jul 2019 10:27:45 -0700 Subject: [PATCH 29/44] Renderscript: rename .rs extension to .rscript Reserve .rs extension for Rust. Bug: 137365032 Test: make checkbuild Test: cd frameworks/compile/slang/tests ./slang_tests.py Test: atest CtsRenderscriptTestCases Test: CtsRsCppTestCases Exempt-From-Owner-Approval: Clean CP Change-Id: I33010b5604d8140f3a50845c16daff743504c8d0 Merged-In: I33010b5604d8140f3a50845c16daff743504c8d0 (cherry picked from commit fafc72bd8ba6602c609c5109d2ec0ea318f14131) --- cmds/stagefright/Android.mk | 6 +++--- .../filters/{argbtorgba.rs => argbtorgba.rscript} | 0 .../filters/{nightvision.rs => nightvision.rscript} | 0 .../filters/{saturation.rs => saturation.rscript} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename cmds/stagefright/filters/{argbtorgba.rs => argbtorgba.rscript} (100%) rename cmds/stagefright/filters/{nightvision.rs => nightvision.rscript} (100%) rename cmds/stagefright/filters/{saturation.rs => saturation.rscript} (100%) diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index 38fd34abc5..0c8d44a7b3 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -153,9 +153,9 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - filters/argbtorgba.rs \ - filters/nightvision.rs \ - filters/saturation.rs \ + filters/argbtorgba.rscript \ + filters/nightvision.rscript \ + filters/saturation.rscript \ mediafilter.cpp \ LOCAL_SHARED_LIBRARIES := \ diff --git a/cmds/stagefright/filters/argbtorgba.rs b/cmds/stagefright/filters/argbtorgba.rscript similarity index 100% rename from cmds/stagefright/filters/argbtorgba.rs rename to cmds/stagefright/filters/argbtorgba.rscript diff --git a/cmds/stagefright/filters/nightvision.rs b/cmds/stagefright/filters/nightvision.rscript similarity index 100% rename from cmds/stagefright/filters/nightvision.rs rename to cmds/stagefright/filters/nightvision.rscript diff --git a/cmds/stagefright/filters/saturation.rs b/cmds/stagefright/filters/saturation.rscript similarity index 100% rename from cmds/stagefright/filters/saturation.rs rename to cmds/stagefright/filters/saturation.rscript From 3a6b92a98e6e7b0c3876c8ff56c1b4b7f0403894 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Mon, 15 Jul 2019 19:59:50 -0700 Subject: [PATCH 30/44] Renderscript: rename .rs extension to .rscript As far as I can tell, this is the only place where soong is used to build renderscript. Bug: 137365032 Test: make checkbuild Test: cd frameworks/compile/slang/tests ./slang_tests.py Test: atest CtsRenderscriptTestCases Test: CtsRsCppTestCases Exempt-From-Owner-Approval: Clean CP Change-Id: I10a23ceee696df7fe363cc5d825e45100565cbdf Merged-In: I10a23ceee696df7fe363cc5d825e45100565cbdf (cherry picked from commit cf75a0b013a1e7238a2aad96f496645b57a424d3) --- media/libstagefright/filters/Android.bp | 2 +- .../filters/{saturation.rs => saturation.rscript} | 0 .../filters/{saturationARGB.rs => saturationARGB.rscript} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename media/libstagefright/filters/{saturation.rs => saturation.rscript} (100%) rename media/libstagefright/filters/{saturationARGB.rs => saturationARGB.rscript} (100%) diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp index 7a67e55bca..b1f62c7c1f 100644 --- a/media/libstagefright/filters/Android.bp +++ b/media/libstagefright/filters/Android.bp @@ -8,7 +8,7 @@ cc_library_static { "MediaFilter.cpp", "RSFilter.cpp", "SaturationFilter.cpp", - "saturationARGB.rs", + "saturationARGB.rscript", "SimpleFilter.cpp", "ZeroFilter.cpp", ], diff --git a/media/libstagefright/filters/saturation.rs b/media/libstagefright/filters/saturation.rscript similarity index 100% rename from media/libstagefright/filters/saturation.rs rename to media/libstagefright/filters/saturation.rscript diff --git a/media/libstagefright/filters/saturationARGB.rs b/media/libstagefright/filters/saturationARGB.rscript similarity index 100% rename from media/libstagefright/filters/saturationARGB.rs rename to media/libstagefright/filters/saturationARGB.rscript From c2a3a82419327c6ffbad9711ed07415341eca00d Mon Sep 17 00:00:00 2001 From: Ricardo Garcia Date: Wed, 17 Jul 2019 14:29:12 -0700 Subject: [PATCH 31/44] Fix for untimely suspension of Dynamics Processing Added exception to avoid suspending Dynamics Processing Effect. Test: Manual testing with popular apps Bug: 134852575 Change-Id: I1ffee570984897304169b30b7af417f61f762ffa --- services/audioflinger/Effects.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp index 3c4fbba156..13152d0b84 100644 --- a/services/audioflinger/Effects.cpp +++ b/services/audioflinger/Effects.cpp @@ -24,6 +24,7 @@ #include "Configuration.h" #include #include +#include #include #include #include @@ -2569,7 +2570,8 @@ bool AudioFlinger::EffectChain::isEffectEligibleForSuspend(const effect_descript if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) && (((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) || (memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) || - (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0))) { + (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0) || + (memcmp(&desc.type, SL_IID_DYNAMICSPROCESSING, sizeof(effect_uuid_t)) == 0))) { return false; } return true; From 76ee1ffe600499099bdf6f10a2bb2a50deaad315 Mon Sep 17 00:00:00 2001 From: dimitry Date: Wed, 17 Jul 2019 13:55:16 +0200 Subject: [PATCH 32/44] Split libaaudio.so to internal and NDK part This change moves almost everything from libaadio.so to separate libaaudio_internal.so library. This is done to avoid exporting symbols which apps are not allowed to use but have them available for platform libraries by exporting them from libaaudio_internal.so Bug: http://b/69603741 Test: make Merged-In: If93118ed2c266faf2964abf21e17b0b13df493d2 Change-Id: If93118ed2c266faf2964abf21e17b0b13df493d2 --- media/libaaudio/src/Android.bp | 78 +++++++++++---- .../src/client/AudioStreamInternal.cpp | 1 + media/libaaudio/src/core/AAudioAudio.cpp | 70 +------------ media/libaaudio/src/core/AudioGlobal.cpp | 99 +++++++++++++++++++ media/libaaudio/src/core/AudioGlobal.h | 34 +++++++ media/libaaudio/src/core/AudioStream.cpp | 11 ++- .../libaaudio/src/core/AudioStreamBuilder.cpp | 3 +- .../libaaudio/src/utility/AAudioUtilities.cpp | 3 +- media/libaaudio/tests/Android.bp | 9 +- services/oboeservice/Android.mk | 2 +- 10 files changed, 213 insertions(+), 97 deletions(-) create mode 100644 media/libaaudio/src/core/AudioGlobal.cpp create mode 100644 media/libaaudio/src/core/AudioGlobal.h diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp index 1eedb12b5a..86cdb9a14e 100644 --- a/media/libaaudio/src/Android.bp +++ b/media/libaaudio/src/Android.bp @@ -10,14 +10,70 @@ cc_library { "legacy", "utility", ], + header_libs: ["libaaudio_headers"], + export_header_lib_headers: ["libaaudio_headers"], + + srcs: [ + "core/AAudioAudio.cpp", + ], + + cflags: [ + "-Wno-unused-parameter", + "-Wall", + "-Werror", + + // By default, all symbols are hidden. + // "-fvisibility=hidden", + // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol. + "-DAAUDIO_API=__attribute__((visibility(\"default\")))", + ], + + shared_libs: [ + "libaaudio_internal", + "libaudioclient", + "libaudioutils", + "liblog", + "libcutils", + "libutils", + "libbinder", + ], +} + +cc_library { + name: "libaaudio_internal", + + local_include_dirs: [ + "binding", + "client", + "core", + "fifo", + "legacy", + "utility", + ], + export_include_dirs: ["."], header_libs: ["libaaudio_headers"], export_header_lib_headers: ["libaaudio_headers"], + shared_libs: [ + "libaudioclient", + "libaudioutils", + "liblog", + "libcutils", + "libutils", + "libbinder", + ], + + cflags: [ + "-Wno-unused-parameter", + "-Wall", + "-Werror", + ], + srcs: [ + "core/AudioGlobal.cpp", "core/AudioStream.cpp", "core/AudioStreamBuilder.cpp", - "core/AAudioAudio.cpp", "core/AAudioStreamParameters.cpp", "legacy/AudioStreamLegacy.cpp", "legacy/AudioStreamRecord.cpp", @@ -54,24 +110,4 @@ cc_library { "flowgraph/SourceI16.cpp", "flowgraph/SourceI24.cpp", ], - - cflags: [ - "-Wno-unused-parameter", - "-Wall", - "-Werror", - - // By default, all symbols are hidden. - // "-fvisibility=hidden", - // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol. - "-DAAUDIO_API=__attribute__((visibility(\"default\")))", - ], - - shared_libs: [ - "libaudioclient", - "libaudioutils", - "liblog", - "libcutils", - "libutils", - "libbinder", - ], } diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp index 52eadd43d0..fb276c2ae7 100644 --- a/media/libaaudio/src/client/AudioStreamInternal.cpp +++ b/media/libaaudio/src/client/AudioStreamInternal.cpp @@ -36,6 +36,7 @@ #include "binding/AAudioStreamConfiguration.h" #include "binding/IAAudioService.h" #include "binding/AAudioServiceMessage.h" +#include "core/AudioGlobal.h" #include "core/AudioStreamBuilder.h" #include "fifo/FifoBuffer.h" #include "utility/AudioClock.h" diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp index 44d5122db6..8040e6a40e 100644 --- a/media/libaaudio/src/core/AAudioAudio.cpp +++ b/media/libaaudio/src/core/AAudioAudio.cpp @@ -27,6 +27,7 @@ #include #include "AudioClock.h" +#include "AudioGlobal.h" #include "AudioStreamBuilder.h" #include "AudioStream.h" #include "binding/AAudioCommon.h" @@ -45,63 +46,14 @@ using namespace aaudio; return AAUDIO_ERROR_NULL; \ } -#define AAUDIO_CASE_ENUM(name) case name: return #name - AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) { - switch (returnCode) { - AAUDIO_CASE_ENUM(AAUDIO_OK); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_DISCONNECTED); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT); - // reserved - AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE); - // reserved - // reserved - AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE); - // reserved - AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_FORMAT); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE); - AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE); - } - return "Unrecognized AAudio error."; + return AudioGlobal_convertResultToText(returnCode); } AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state) { - switch (state) { - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNKNOWN); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING); - AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED); - } - return "Unrecognized AAudio state."; + return AudioGlobal_convertStreamStateToText(state); } -#undef AAUDIO_CASE_ENUM - - -/****************************************** - * Static globals. - */ -static aaudio_policy_t s_MMapPolicy = AAUDIO_UNSPECIFIED; - static AudioStream *convertAAudioStreamToAudioStream(AAudioStream* stream) { return (AudioStream*) stream; @@ -543,23 +495,11 @@ AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* stream, } AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy() { - return s_MMapPolicy; + return AudioGlobal_getMMapPolicy(); } AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) { - aaudio_result_t result = AAUDIO_OK; - switch(policy) { - case AAUDIO_UNSPECIFIED: - case AAUDIO_POLICY_NEVER: - case AAUDIO_POLICY_AUTO: - case AAUDIO_POLICY_ALWAYS: - s_MMapPolicy = policy; - break; - default: - result = AAUDIO_ERROR_ILLEGAL_ARGUMENT; - break; - } - return result; + return AudioGlobal_setMMapPolicy(policy); } AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* stream) diff --git a/media/libaaudio/src/core/AudioGlobal.cpp b/media/libaaudio/src/core/AudioGlobal.cpp new file mode 100644 index 0000000000..e6d9a0dbb9 --- /dev/null +++ b/media/libaaudio/src/core/AudioGlobal.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "AudioGlobal.h" + +/****************************************** + * Static globals. + */ +namespace aaudio { + +static aaudio_policy_t g_MMapPolicy = AAUDIO_UNSPECIFIED; + +aaudio_policy_t AudioGlobal_getMMapPolicy() { + return g_MMapPolicy; +} + +aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy) { + aaudio_result_t result = AAUDIO_OK; + switch(policy) { + case AAUDIO_UNSPECIFIED: + case AAUDIO_POLICY_NEVER: + case AAUDIO_POLICY_AUTO: + case AAUDIO_POLICY_ALWAYS: + g_MMapPolicy = policy; + break; + default: + result = AAUDIO_ERROR_ILLEGAL_ARGUMENT; + break; + } + return result; +} + +#define AAUDIO_CASE_ENUM(name) case name: return #name + +const char* AudioGlobal_convertResultToText(aaudio_result_t returnCode) { + switch (returnCode) { + AAUDIO_CASE_ENUM(AAUDIO_OK); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_DISCONNECTED); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT); + // reserved + AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE); + // reserved + // reserved + AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE); + // reserved + AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_FORMAT); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE); + AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE); + } + return "Unrecognized AAudio error."; +} + +const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state) { + switch (state) { + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNKNOWN); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING); + AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED); + } + return "Unrecognized AAudio state."; +} + +#undef AAUDIO_CASE_ENUM + +} // namespace aaudio diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h new file mode 100644 index 0000000000..312cef2267 --- /dev/null +++ b/media/libaaudio/src/core/AudioGlobal.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AAUDIO_AUDIOGLOBAL_H +#define AAUDIO_AUDIOGLOBAL_H + +#include +#include + + +namespace aaudio { + +aaudio_policy_t AudioGlobal_getMMapPolicy(); +aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy); + +const char* AudioGlobal_convertResultToText(aaudio_result_t returnCode); +const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state); + +} + +#endif // AAUDIO_AUDIOGLOBAL_H + diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp index 9b772237e0..5303631126 100644 --- a/media/libaaudio/src/core/AudioStream.cpp +++ b/media/libaaudio/src/core/AudioStream.cpp @@ -25,8 +25,9 @@ #include "AudioStreamBuilder.h" #include "AudioStream.h" #include "AudioClock.h" +#include "AudioGlobal.h" -using namespace aaudio; +namespace aaudio { // Sequential number assigned to streams solely for debugging purposes. @@ -51,7 +52,7 @@ AudioStream::~AudioStream() { || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED || getState() == AAUDIO_STREAM_STATE_DISCONNECTED), "~AudioStream() - still in use, state = %s", - AAudio_convertStreamStateToText(getState())); + AudioGlobal_convertStreamStateToText(getState())); mPlayerBase->clearParentReference(); // remove reference to this AudioStream } @@ -155,7 +156,7 @@ aaudio_result_t AudioStream::systemPause() { case AAUDIO_STREAM_STATE_CLOSED: default: ALOGW("safePause() stream not running, state = %s", - AAudio_convertStreamStateToText(getState())); + AudioGlobal_convertStreamStateToText(getState())); return AAUDIO_ERROR_INVALID_STATE; } @@ -240,7 +241,7 @@ aaudio_result_t AudioStream::safeStop() { case AAUDIO_STREAM_STATE_CLOSED: default: ALOGW("%s() stream not running, state = %s", __func__, - AAudio_convertStreamStateToText(getState())); + AudioGlobal_convertStreamStateToText(getState())); return AAUDIO_ERROR_INVALID_STATE; } @@ -488,3 +489,5 @@ void AudioStream::MyPlayerBase::unregisterWithAudioManager() { void AudioStream::MyPlayerBase::destroy() { unregisterWithAudioManager(); } + +} // namespace aaudio diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp index 08f4958c0a..44f45b36a1 100644 --- a/media/libaaudio/src/core/AudioStreamBuilder.cpp +++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp @@ -27,6 +27,7 @@ #include "binding/AAudioBinderClient.h" #include "client/AudioStreamInternalCapture.h" #include "client/AudioStreamInternalPlay.h" +#include "core/AudioGlobal.h" #include "core/AudioStream.h" #include "core/AudioStreamBuilder.h" #include "legacy/AudioStreamRecord.h" @@ -112,7 +113,7 @@ aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) { } // The API setting is the highest priority. - aaudio_policy_t mmapPolicy = AAudio_getMMapPolicy(); + aaudio_policy_t mmapPolicy = AudioGlobal_getMMapPolicy(); // If not specified then get from a system property. if (mmapPolicy == AAUDIO_UNSPECIFIED) { mmapPolicy = AAudioProperty_getMMapPolicy(); diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp index 96ed56a284..cdd02c0360 100644 --- a/media/libaaudio/src/utility/AAudioUtilities.cpp +++ b/media/libaaudio/src/utility/AAudioUtilities.cpp @@ -24,6 +24,7 @@ #include #include "aaudio/AAudio.h" +#include "core/AudioGlobal.h" #include #include #include @@ -355,7 +356,7 @@ aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state) { case AAUDIO_STREAM_STATE_DISCONNECTED: default: ALOGE("can only flush stream when PAUSED, OPEN or STOPPED, state = %s", - AAudio_convertStreamStateToText(state)); + aaudio::AudioGlobal_convertStreamStateToText(state)); result = AAUDIO_ERROR_INVALID_STATE; break; } diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp index 6101e99aba..2745f41e21 100644 --- a/media/libaaudio/tests/Android.bp +++ b/media/libaaudio/tests/Android.bp @@ -12,6 +12,7 @@ cc_test { srcs: ["test_marshalling.cpp"], shared_libs: [ "libaaudio", + "libaaudio_internal", "libbinder", "libcutils", "libutils", @@ -23,7 +24,7 @@ cc_test { defaults: ["libaaudio_tests_defaults"], srcs: ["test_clock_model.cpp"], shared_libs: [ - "libaaudio", + "libaaudio_internal", "libaudioutils", "libcutils", "libutils", @@ -34,7 +35,7 @@ cc_test { name: "test_block_adapter", defaults: ["libaaudio_tests_defaults"], srcs: ["test_block_adapter.cpp"], - shared_libs: ["libaaudio"], + shared_libs: ["libaaudio_internal"], } cc_test { @@ -170,7 +171,7 @@ cc_test { name: "test_atomic_fifo", defaults: ["libaaudio_tests_defaults"], srcs: ["test_atomic_fifo.cpp"], - shared_libs: ["libaaudio"], + shared_libs: ["libaaudio_internal"], } cc_test { @@ -178,7 +179,7 @@ cc_test { defaults: ["libaaudio_tests_defaults"], srcs: ["test_flowgraph.cpp"], shared_libs: [ - "libaaudio", + "libaaudio_internal", "libbinder", "libcutils", "libutils", diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk index cfd662f64c..5e4cd3935f 100644 --- a/services/oboeservice/Android.mk +++ b/services/oboeservice/Android.mk @@ -46,7 +46,7 @@ LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_CFLAGS += -Wall -Werror LOCAL_SHARED_LIBRARIES := \ - libaaudio \ + libaaudio_internal \ libaudioflinger \ libaudioclient \ libbinder \ From c6af90d5efad45b652bbd40d63324efe01da4341 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 19 Jul 2019 10:31:39 -0700 Subject: [PATCH 33/44] audio policy: fix capture policy for HOTWORD source Do not consider Assistant capturing with HOTWORD source when determining lastest active capture client. As assistant capturing for HOTWORD does not silence other captures, it should not prevent another client from being selected as the latest active. Bug: 135806801 Test: Start capture with Recorder app, place in background and trigger false OK G detection Change-Id: Ic17bfd70675ef749d6a678d067112b1dbd205746 --- services/audiopolicy/service/AudioPolicyService.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index 77f7997a2a..692f612bcf 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -459,16 +459,20 @@ void AudioPolicyService::updateUidStates_l() continue; } + bool isAssistant = mUidPolicy->isAssistantUid(current->uid); if (appState == APP_STATE_TOP) { if (current->startTimeNs > topStartNs) { topActive = current; topStartNs = current->startTimeNs; } - if (mUidPolicy->isAssistantUid(current->uid)) { + if (isAssistant) { isAssistantOnTop = true; } } - if (current->startTimeNs > latestStartNs) { + // Assistant capturing for HOTWORD not considered for latest active to avoid + // masking regular clients started before + if (current->startTimeNs > latestStartNs && + !(current->attributes.source == AUDIO_SOURCE_HOTWORD && isAssistant)) { latestActive = current; latestStartNs = current->startTimeNs; } From e151ed6e29fe353a26984a30077f8f30adf9cb86 Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Tue, 16 Jul 2019 17:40:40 -0700 Subject: [PATCH 34/44] codec2: increase max dequeue output buffer count Add # of input slots to max dequeue buffer count for output buffers. If pipeline is paused, # of output buffers could be whole pipeline depth including # of input slots. Bug: 137150765 Merged-In: I5fce613a383160ea8a49e77f67628f85408cdcfa Change-Id: I5fce613a383160ea8a49e77f67628f85408cdcfa (cherry picked from commit 7a7b742c7a708406ae0d468f03244e6a994ee9c9) --- media/codec2/sfplugin/CCodecBufferChannel.cpp | 14 +++++++++----- media/codec2/sfplugin/PipelineWatcher.cpp | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp index 8308292512..0cbf62bb1b 100644 --- a/media/codec2/sfplugin/CCodecBufferChannel.cpp +++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp @@ -224,7 +224,7 @@ CCodecBufferChannel::CCodecBufferChannel( mFirstValidFrameIndex(0u), mMetaMode(MODE_NONE), mInputMetEos(false) { - mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth; + mOutputSurface.lock()->maxDequeueBuffers = 2 * kSmoothnessFactor + kRenderingDepth; { Mutexed::Locked input(mInput); input->buffers.reset(new DummyInputBuffers("")); @@ -948,7 +948,8 @@ status_t CCodecBufferChannel::start( uint32_t outputGeneration; { Mutexed::Locked output(mOutputSurface); - output->maxDequeueBuffers = numOutputSlots + reorderDepth.value + kRenderingDepth; + output->maxDequeueBuffers = numOutputSlots + numInputSlots + + reorderDepth.value + kRenderingDepth; outputSurface = output->surface ? output->surface->getIGraphicBufferProducer() : nullptr; if (outputSurface) { @@ -1332,9 +1333,10 @@ bool CCodecBufferChannel::handleWork( ALOGV("[%s] onWorkDone: updated reorder depth to %u", mName, reorderDepth.value); size_t numOutputSlots = mOutput.lock()->numSlots; + size_t numInputSlots = mInput.lock()->numSlots; Mutexed::Locked output(mOutputSurface); - output->maxDequeueBuffers = - numOutputSlots + reorderDepth.value + kRenderingDepth; + output->maxDequeueBuffers = numOutputSlots + numInputSlots + + reorderDepth.value + kRenderingDepth; if (output->surface) { output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers); } @@ -1382,6 +1384,7 @@ bool CCodecBufferChannel::handleWork( bool outputBuffersChanged = false; size_t numOutputSlots = 0; + size_t numInputSlots = mInput.lock()->numSlots; { Mutexed::Locked output(mOutput); output->outputDelay = outputDelay.value; @@ -1406,7 +1409,8 @@ bool CCodecBufferChannel::handleWork( uint32_t depth = mReorderStash.lock()->depth(); Mutexed::Locked output(mOutputSurface); - output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth; + output->maxDequeueBuffers = numOutputSlots + numInputSlots + + depth + kRenderingDepth; if (output->surface) { output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers); } diff --git a/media/codec2/sfplugin/PipelineWatcher.cpp b/media/codec2/sfplugin/PipelineWatcher.cpp index 74d14e865e..0ee90569f5 100644 --- a/media/codec2/sfplugin/PipelineWatcher.cpp +++ b/media/codec2/sfplugin/PipelineWatcher.cpp @@ -146,7 +146,7 @@ PipelineWatcher::Clock::duration PipelineWatcher::elapsed( std::chrono::duration_cast(elapsed).count()); durations.push_back(elapsed); } - std::nth_element(durations.begin(), durations.end(), durations.begin() + n, + std::nth_element(durations.begin(), durations.begin() + n, durations.end(), std::greater()); return durations[n]; } From ef4ce157000b2b5bcbf2bcb36a228ec604803547 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Tue, 23 Jul 2019 08:27:46 -0700 Subject: [PATCH 35/44] Fix OOB access in mpeg4/h263 decoder The decoder does not support an increase in frame width, and would exceed its buffer if the width increased mid-stream. There was an existing check to prevent the total frame size (width*height) from increasing, but in fact the decoder also does not even support a width increase, even if the height decreases correspondingly. Bug: 136175447 Bug: 136173699 Test: manual Change-Id: Ic2d28bb0503635dadeb69ba3be9412d58684e910 --- media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp index f18f789b99..679b0911df 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp @@ -1355,6 +1355,14 @@ PV_STATUS DecodeShortHeader(VideoDecData *video, Vop *currVop) int tmpHeight = (tmpDisplayHeight + 15) & -16; int tmpWidth = (tmpDisplayWidth + 15) & -16; + if (tmpWidth > video->width) + { + // while allowed by the spec, this decoder does not actually + // support an increase in size. + ALOGE("width increase not supported"); + status = PV_FAIL; + goto return_point; + } if (tmpHeight * tmpWidth > video->size) { // This is just possibly "b/37079296". From 8c886ae968a80321f0269825f186c75853645d61 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Mon, 15 Jul 2019 12:36:22 -0700 Subject: [PATCH 36/44] aacenc: fix timestamp off by one frame Bug: 137245963 Test: manual Change-Id: I567890f3d04544c12adfe29a6a23c06f1db699e7 --- media/codec2/components/aac/C2SoftAacEnc.cpp | 68 ++++++++++++-------- media/codec2/components/aac/C2SoftAacEnc.h | 2 +- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp index 8e3852c110..1dc676bd04 100644 --- a/media/codec2/components/aac/C2SoftAacEnc.cpp +++ b/media/codec2/components/aac/C2SoftAacEnc.cpp @@ -157,7 +157,7 @@ C2SoftAacEnc::C2SoftAacEnc( mSentCodecSpecificData(false), mInputTimeSet(false), mInputSize(0), - mInputTimeUs(0), + mNextFrameTimestampUs(0), mSignalledError(false), mOutIndex(0u) { } @@ -183,7 +183,7 @@ c2_status_t C2SoftAacEnc::onStop() { mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mInputTimeUs = 0; + mNextFrameTimestampUs = 0; mSignalledError = false; return C2_OK; } @@ -201,7 +201,7 @@ c2_status_t C2SoftAacEnc::onFlush_sm() { mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mInputTimeUs = 0; + mNextFrameTimestampUs = 0; return C2_OK; } @@ -365,17 +365,18 @@ void C2SoftAacEnc::process( capacity = view.capacity(); } if (!mInputTimeSet && capacity > 0) { - mInputTimeUs = work->input.ordinal.timestamp; + mNextFrameTimestampUs = work->input.ordinal.timestamp; mInputTimeSet = true; } size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0)) / mNumBytesPerInputFrame; - ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u", - capacity, mInputSize, numFrames, mNumBytesPerInputFrame); + ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu " + "mNumBytesPerInputFrame = %u inputTS = %lld", + capacity, mInputSize, numFrames, + mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll()); std::shared_ptr block; - std::shared_ptr buffer; std::unique_ptr wView; uint8_t *outPtr = temp; size_t outAvailable = 0u; @@ -442,7 +443,11 @@ void C2SoftAacEnc::process( const std::shared_ptr mBuffer; }; - C2WorkOrdinalStruct outOrdinal = work->input.ordinal; + struct OutputBuffer { + std::shared_ptr buffer; + c2_cntr64_t timestampUs; + }; + std::list outputBuffers; while (encoderErr == AACENC_OK && inargs.numInSamples > 0) { if (numFrames && !block) { @@ -473,29 +478,22 @@ void C2SoftAacEnc::process( &outargs); if (encoderErr == AACENC_OK) { - if (buffer) { - outOrdinal.frameIndex = mOutIndex++; - outOrdinal.timestamp = mInputTimeUs; - cloneAndSend( - inputIndex, - work, - FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer)); - buffer.reset(); - } - if (outargs.numOutBytes > 0) { mInputSize = 0; int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples + outargs.numInSamples; - mInputTimeUs = work->input.ordinal.timestamp + c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs; + mNextFrameTimestampUs = work->input.ordinal.timestamp + (consumed * 1000000ll / channelCount / sampleRate); - buffer = createLinearBuffer(block, 0, outargs.numOutBytes); + std::shared_ptr buffer = createLinearBuffer(block, 0, outargs.numOutBytes); #if defined(LOG_NDEBUG) && !LOG_NDEBUG hexdump(outPtr, std::min(outargs.numOutBytes, 256)); #endif outPtr = temp; outAvailable = 0; block.reset(); + + outputBuffers.push_back({buffer, currentFrameTimestampUs}); } else { mInputSize += outargs.numInSamples * sizeof(int16_t); } @@ -506,8 +504,9 @@ void C2SoftAacEnc::process( inargs.numInSamples -= outargs.numInSamples; } } - ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld", - encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll()); + ALOGV("encoderErr = %d mInputSize = %zu " + "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld", + encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll()); } if (eos && inBufferSize[0] > 0) { @@ -542,10 +541,27 @@ void C2SoftAacEnc::process( &outargs); } - outOrdinal.frameIndex = mOutIndex++; - outOrdinal.timestamp = mInputTimeUs; + while (outputBuffers.size() > 1) { + const OutputBuffer& front = outputBuffers.front(); + C2WorkOrdinalStruct ordinal = work->input.ordinal; + ordinal.frameIndex = mOutIndex++; + ordinal.timestamp = front.timestampUs; + cloneAndSend( + inputIndex, + work, + FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer)); + outputBuffers.pop_front(); + } + std::shared_ptr buffer; + C2WorkOrdinalStruct ordinal = work->input.ordinal; + ordinal.frameIndex = mOutIndex++; + if (!outputBuffers.empty()) { + ordinal.timestamp = outputBuffers.front().timestampUs; + buffer = outputBuffers.front().buffer; + } + // Mark the end of frame FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0), - outOrdinal, buffer)(work); + ordinal, buffer)(work); } c2_status_t C2SoftAacEnc::drain( @@ -569,7 +585,7 @@ c2_status_t C2SoftAacEnc::drain( mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mInputTimeUs = 0; + mNextFrameTimestampUs = 0; // TODO: we don't have any pending work at this time to drain. return C2_OK; diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h index a38be190a1..26550397af 100644 --- a/media/codec2/components/aac/C2SoftAacEnc.h +++ b/media/codec2/components/aac/C2SoftAacEnc.h @@ -56,7 +56,7 @@ private: bool mSentCodecSpecificData; bool mInputTimeSet; size_t mInputSize; - c2_cntr64_t mInputTimeUs; + c2_cntr64_t mNextFrameTimestampUs; bool mSignalledError; std::atomic_uint64_t mOutIndex; From ea0bf32a189b3998880181118caf6016ed4b7d0f Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Thu, 25 Jul 2019 15:12:39 -0700 Subject: [PATCH 37/44] Camera: Update depth photo container item MIME type Replace the item MIME type with value supported by the dynamic depth specification. Bug: 138399780 Test: runtest -x cts/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java -m testDynamicDepth Change-Id: Ib51dd69e6de7da3269eccfa6b671fe95a269b4d6 --- services/camera/libcameraservice/common/DepthPhotoProcessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp index 3c90de0d6e..94541d87a9 100644 --- a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp +++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp @@ -419,7 +419,7 @@ extern "C" int processDepthPhotoFrame(DepthPhotoInputFrame inputFrame, size_t de std::vector> items; std::vector> cameraList; - auto image = Image::FromDataForPrimaryImage("android/mainimage", &items); + auto image = Image::FromDataForPrimaryImage("image/jpeg", &items); std::unique_ptr cameraParams(new CameraParams(std::move(image))); if (cameraParams == nullptr) { ALOGE("%s: Failed to initialize camera parameters", __FUNCTION__); From 589171c80afab0f515e99044aca15be9ee24d16b Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Thu, 25 Jul 2019 18:04:29 -0700 Subject: [PATCH 38/44] audio policy: fix capture policy for accessibility Do not consider Accessibility services when determining lastest active capture client. As an Accessibility service capturing does not silence other captures, it should not prevent another client from being selected as the latest active. Bug: 135806801 Test: Start capture with Recorder app, activate Voice Access Change-Id: I864be785752f27201d45ce24f95013de6391dbd6 --- .../service/AudioPolicyService.cpp | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index 692f612bcf..f8cecbf6fc 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -410,12 +410,17 @@ void AudioPolicyService::updateUidStates_l() // Another client in the same UID has already been allowed to capture // OR The client is the assistant // AND an accessibility service is on TOP or a RTT call is active -// AND the source is VOICE_RECOGNITION or HOTWORD -// OR uses VOICE_RECOGNITION AND is on TOP -// OR uses HOTWORD +// AND the source is VOICE_RECOGNITION or HOTWORD +// OR uses VOICE_RECOGNITION AND is on TOP +// OR uses HOTWORD // AND there is no active privacy sensitive capture or call // OR client has CAPTURE_AUDIO_OUTPUT privileged permission // OR The client is an accessibility service +// AND Is on TOP +// AND the source is VOICE_RECOGNITION or HOTWORD +// OR The assistant is not on TOP +// AND there is no active privacy sensitive capture or call +// OR client has CAPTURE_AUDIO_OUTPUT privileged permission // AND is on TOP // AND the source is VOICE_RECOGNITION or HOTWORD // OR the client source is virtual (remote submix, call audio TX or RX...) @@ -423,7 +428,7 @@ void AudioPolicyService::updateUidStates_l() // AND The assistant is not on TOP // AND is on TOP or latest started // AND there is no active privacy sensitive capture or call -// OR client has CAPTURE_AUDIO_OUTPUT privileged permission +// OR client has CAPTURE_AUDIO_OUTPUT privileged permission sp topActive; sp latestActive; @@ -460,7 +465,8 @@ void AudioPolicyService::updateUidStates_l() } bool isAssistant = mUidPolicy->isAssistantUid(current->uid); - if (appState == APP_STATE_TOP) { + bool isAccessibility = mUidPolicy->isA11yUid(current->uid); + if (appState == APP_STATE_TOP && !isAccessibility) { if (current->startTimeNs > topStartNs) { topActive = current; topStartNs = current->startTimeNs; @@ -469,10 +475,13 @@ void AudioPolicyService::updateUidStates_l() isAssistantOnTop = true; } } - // Assistant capturing for HOTWORD not considered for latest active to avoid - // masking regular clients started before - if (current->startTimeNs > latestStartNs && - !(current->attributes.source == AUDIO_SOURCE_HOTWORD && isAssistant)) { + // Assistant capturing for HOTWORD or Accessibility services not considered + // for latest active to avoid masking regular clients started before + if (current->startTimeNs > latestStartNs + && !((current->attributes.source == AUDIO_SOURCE_HOTWORD + || isA11yOnTop || rttCallActive) + && isAssistant) + && !isAccessibility) { latestActive = current; latestStartNs = current->startTimeNs; } @@ -545,10 +554,20 @@ void AudioPolicyService::updateUidStates_l() } else if (mUidPolicy->isA11yUid(current->uid)) { // For accessibility service allow capture if: // Is on TOP - // AND the source is VOICE_RECOGNITION or HOTWORD - if (isA11yOnTop && - (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD)) { - allowCapture = true; + // AND the source is VOICE_RECOGNITION or HOTWORD + // Or + // The assistant is not on TOP + // AND there is no active privacy sensitive capture or call + // OR client has CAPTURE_AUDIO_OUTPUT privileged permission + if (isA11yOnTop) { + if (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD) { + allowCapture = true; + } + } else { + if (!isAssistantOnTop + && (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) { + allowCapture = true; + } } } setAppState_l(current->uid, From 917bb01c6bb02060a01f804431dd503f9b256d30 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 30 Jul 2019 08:48:19 -0700 Subject: [PATCH 39/44] Remove product_is_iot. Test: treehugger Change-Id: I0a29825c8e9fe082c0dd2bee60cfc04665678fcd --- media/utils/Android.bp | 6 ------ media/utils/ServiceUtilities.cpp | 11 ----------- 2 files changed, 17 deletions(-) diff --git a/media/utils/Android.bp b/media/utils/Android.bp index d81cde8d62..0ed92f760b 100644 --- a/media/utils/Android.bp +++ b/media/utils/Android.bp @@ -45,12 +45,6 @@ cc_library { "-Werror", ], - product_variables: { - product_is_iot: { - cflags: ["-DTARGET_ANDROID_THINGS"], - }, - }, - include_dirs: [ // For android_mallopt definitions. "bionic/libc/private" diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp index b824212b51..db13903560 100644 --- a/media/utils/ServiceUtilities.cpp +++ b/media/utils/ServiceUtilities.cpp @@ -176,18 +176,7 @@ bool modifyDefaultAudioEffectsAllowed() { // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed); -#ifdef TARGET_ANDROID_THINGS - if (!ok) { - // Use a secondary permission on Android Things to allow a more lenient level of protection. - static const String16 sModifyDefaultAudioEffectsAndroidThingsAllowed( - "com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); - ok = PermissionCache::checkCallingPermission( - sModifyDefaultAudioEffectsAndroidThingsAllowed); - } - if (!ok) ALOGE("com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); -#else if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"); -#endif return ok; } From 10ceef9f3b96e5c7bc783432fe569333a2405cf0 Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Mon, 15 Jul 2019 12:36:22 -0700 Subject: [PATCH 40/44] aacenc: fix timestamp off by one frame Bug: 137245963 Test: manual Change-Id: I567890f3d04544c12adfe29a6a23c06f1db699e7 (cherry picked from commit 8c886ae968a80321f0269825f186c75853645d61) --- media/codec2/components/aac/C2SoftAacEnc.cpp | 68 ++++++++++++-------- media/codec2/components/aac/C2SoftAacEnc.h | 2 +- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp index 8e3852c110..1dc676bd04 100644 --- a/media/codec2/components/aac/C2SoftAacEnc.cpp +++ b/media/codec2/components/aac/C2SoftAacEnc.cpp @@ -157,7 +157,7 @@ C2SoftAacEnc::C2SoftAacEnc( mSentCodecSpecificData(false), mInputTimeSet(false), mInputSize(0), - mInputTimeUs(0), + mNextFrameTimestampUs(0), mSignalledError(false), mOutIndex(0u) { } @@ -183,7 +183,7 @@ c2_status_t C2SoftAacEnc::onStop() { mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mInputTimeUs = 0; + mNextFrameTimestampUs = 0; mSignalledError = false; return C2_OK; } @@ -201,7 +201,7 @@ c2_status_t C2SoftAacEnc::onFlush_sm() { mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mInputTimeUs = 0; + mNextFrameTimestampUs = 0; return C2_OK; } @@ -365,17 +365,18 @@ void C2SoftAacEnc::process( capacity = view.capacity(); } if (!mInputTimeSet && capacity > 0) { - mInputTimeUs = work->input.ordinal.timestamp; + mNextFrameTimestampUs = work->input.ordinal.timestamp; mInputTimeSet = true; } size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0)) / mNumBytesPerInputFrame; - ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u", - capacity, mInputSize, numFrames, mNumBytesPerInputFrame); + ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu " + "mNumBytesPerInputFrame = %u inputTS = %lld", + capacity, mInputSize, numFrames, + mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll()); std::shared_ptr block; - std::shared_ptr buffer; std::unique_ptr wView; uint8_t *outPtr = temp; size_t outAvailable = 0u; @@ -442,7 +443,11 @@ void C2SoftAacEnc::process( const std::shared_ptr mBuffer; }; - C2WorkOrdinalStruct outOrdinal = work->input.ordinal; + struct OutputBuffer { + std::shared_ptr buffer; + c2_cntr64_t timestampUs; + }; + std::list outputBuffers; while (encoderErr == AACENC_OK && inargs.numInSamples > 0) { if (numFrames && !block) { @@ -473,29 +478,22 @@ void C2SoftAacEnc::process( &outargs); if (encoderErr == AACENC_OK) { - if (buffer) { - outOrdinal.frameIndex = mOutIndex++; - outOrdinal.timestamp = mInputTimeUs; - cloneAndSend( - inputIndex, - work, - FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer)); - buffer.reset(); - } - if (outargs.numOutBytes > 0) { mInputSize = 0; int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples + outargs.numInSamples; - mInputTimeUs = work->input.ordinal.timestamp + c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs; + mNextFrameTimestampUs = work->input.ordinal.timestamp + (consumed * 1000000ll / channelCount / sampleRate); - buffer = createLinearBuffer(block, 0, outargs.numOutBytes); + std::shared_ptr buffer = createLinearBuffer(block, 0, outargs.numOutBytes); #if defined(LOG_NDEBUG) && !LOG_NDEBUG hexdump(outPtr, std::min(outargs.numOutBytes, 256)); #endif outPtr = temp; outAvailable = 0; block.reset(); + + outputBuffers.push_back({buffer, currentFrameTimestampUs}); } else { mInputSize += outargs.numInSamples * sizeof(int16_t); } @@ -506,8 +504,9 @@ void C2SoftAacEnc::process( inargs.numInSamples -= outargs.numInSamples; } } - ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld", - encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll()); + ALOGV("encoderErr = %d mInputSize = %zu " + "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld", + encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll()); } if (eos && inBufferSize[0] > 0) { @@ -542,10 +541,27 @@ void C2SoftAacEnc::process( &outargs); } - outOrdinal.frameIndex = mOutIndex++; - outOrdinal.timestamp = mInputTimeUs; + while (outputBuffers.size() > 1) { + const OutputBuffer& front = outputBuffers.front(); + C2WorkOrdinalStruct ordinal = work->input.ordinal; + ordinal.frameIndex = mOutIndex++; + ordinal.timestamp = front.timestampUs; + cloneAndSend( + inputIndex, + work, + FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer)); + outputBuffers.pop_front(); + } + std::shared_ptr buffer; + C2WorkOrdinalStruct ordinal = work->input.ordinal; + ordinal.frameIndex = mOutIndex++; + if (!outputBuffers.empty()) { + ordinal.timestamp = outputBuffers.front().timestampUs; + buffer = outputBuffers.front().buffer; + } + // Mark the end of frame FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0), - outOrdinal, buffer)(work); + ordinal, buffer)(work); } c2_status_t C2SoftAacEnc::drain( @@ -569,7 +585,7 @@ c2_status_t C2SoftAacEnc::drain( mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mInputTimeUs = 0; + mNextFrameTimestampUs = 0; // TODO: we don't have any pending work at this time to drain. return C2_OK; diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h index a38be190a1..26550397af 100644 --- a/media/codec2/components/aac/C2SoftAacEnc.h +++ b/media/codec2/components/aac/C2SoftAacEnc.h @@ -56,7 +56,7 @@ private: bool mSentCodecSpecificData; bool mInputTimeSet; size_t mInputSize; - c2_cntr64_t mInputTimeUs; + c2_cntr64_t mNextFrameTimestampUs; bool mSignalledError; std::atomic_uint64_t mOutIndex; From 732e5fab3dc2d06901b5f56163a01fda6f5364b8 Mon Sep 17 00:00:00 2001 From: Sundong Ahn Date: Tue, 30 Jul 2019 20:43:43 +0900 Subject: [PATCH 41/44] Check the media.settings.xml property The file name and path of the media profiles can be changed by media.settings.xml property. So befor test, we should check media.settings.xml property. Bug: 138413934 Test: vts-tradefed run vts -m VtsValidateMediaProfiles Change-Id: Ib7070cca94b9d637b9a1a175d09baf7b78ec0fd9 Merged-In: Ib7070cca94b9d637b9a1a175d09baf7b78ec0fd9 (cherry picked from commit ef8695ed8435b10bf9ae5f5e5b22f1d8a4d716d8) --- media/libmedia/xsd/vts/Android.bp | 1 + media/libmedia/xsd/vts/ValidateMediaProfiles.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/media/libmedia/xsd/vts/Android.bp b/media/libmedia/xsd/vts/Android.bp index b590a12882..4739504ede 100644 --- a/media/libmedia/xsd/vts/Android.bp +++ b/media/libmedia/xsd/vts/Android.bp @@ -24,6 +24,7 @@ cc_test { "libxml2", ], shared_libs: [ + "libbase", "liblog", ], cflags: [ diff --git a/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp b/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp index ff9b0605bf..7729d52fe1 100644 --- a/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp +++ b/media/libmedia/xsd/vts/ValidateMediaProfiles.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#include + +#include +#include #include "utility/ValidateXml.h" TEST(CheckConfig, mediaProfilesValidation) { @@ -21,8 +25,12 @@ TEST(CheckConfig, mediaProfilesValidation) { "Verify that the media profiles file " "is valid according to the schema"); - const char* location = "/vendor/etc"; + std::string mediaSettingsPath = android::base::GetProperty("media.settings.xml", ""); + if (mediaSettingsPath.empty()) { + mediaSettingsPath.assign("/vendor/etc/media_profiles_V1_0.xml"); + } - EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("media_profiles_V1_0.xml", {location}, + EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(android::base::Basename(mediaSettingsPath).c_str(), + {android::base::Dirname(mediaSettingsPath).c_str()}, "/data/local/tmp/media_profiles.xsd"); } From bc3245623c3d4408dcfb9c727d2b9b1935a36a7a Mon Sep 17 00:00:00 2001 From: Akshay Thakker Date: Mon, 12 Aug 2019 17:16:11 +0000 Subject: [PATCH 42/44] Revert "aacenc: fix timestamp off by one frame" This reverts commit 10ceef9f3b96e5c7bc783432fe569333a2405cf0. Reason for revert: This isn't wanted in qt-dev. It is in qt-r1-dev and will be delivered in the December Mainline train. Bug: 137245963 Change-Id: I0a5a4991786d6dcbd324663a6d342729166a5528 Merged-In: I567890f3d04544c12adfe29a6a23c06f1db699e7 --- media/codec2/components/aac/C2SoftAacEnc.cpp | 68 ++++++++------------ media/codec2/components/aac/C2SoftAacEnc.h | 2 +- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp index 1dc676bd04..8e3852c110 100644 --- a/media/codec2/components/aac/C2SoftAacEnc.cpp +++ b/media/codec2/components/aac/C2SoftAacEnc.cpp @@ -157,7 +157,7 @@ C2SoftAacEnc::C2SoftAacEnc( mSentCodecSpecificData(false), mInputTimeSet(false), mInputSize(0), - mNextFrameTimestampUs(0), + mInputTimeUs(0), mSignalledError(false), mOutIndex(0u) { } @@ -183,7 +183,7 @@ c2_status_t C2SoftAacEnc::onStop() { mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mNextFrameTimestampUs = 0; + mInputTimeUs = 0; mSignalledError = false; return C2_OK; } @@ -201,7 +201,7 @@ c2_status_t C2SoftAacEnc::onFlush_sm() { mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mNextFrameTimestampUs = 0; + mInputTimeUs = 0; return C2_OK; } @@ -365,18 +365,17 @@ void C2SoftAacEnc::process( capacity = view.capacity(); } if (!mInputTimeSet && capacity > 0) { - mNextFrameTimestampUs = work->input.ordinal.timestamp; + mInputTimeUs = work->input.ordinal.timestamp; mInputTimeSet = true; } size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0)) / mNumBytesPerInputFrame; - ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu " - "mNumBytesPerInputFrame = %u inputTS = %lld", - capacity, mInputSize, numFrames, - mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll()); + ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u", + capacity, mInputSize, numFrames, mNumBytesPerInputFrame); std::shared_ptr block; + std::shared_ptr buffer; std::unique_ptr wView; uint8_t *outPtr = temp; size_t outAvailable = 0u; @@ -443,11 +442,7 @@ void C2SoftAacEnc::process( const std::shared_ptr mBuffer; }; - struct OutputBuffer { - std::shared_ptr buffer; - c2_cntr64_t timestampUs; - }; - std::list outputBuffers; + C2WorkOrdinalStruct outOrdinal = work->input.ordinal; while (encoderErr == AACENC_OK && inargs.numInSamples > 0) { if (numFrames && !block) { @@ -478,22 +473,29 @@ void C2SoftAacEnc::process( &outargs); if (encoderErr == AACENC_OK) { + if (buffer) { + outOrdinal.frameIndex = mOutIndex++; + outOrdinal.timestamp = mInputTimeUs; + cloneAndSend( + inputIndex, + work, + FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer)); + buffer.reset(); + } + if (outargs.numOutBytes > 0) { mInputSize = 0; int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples + outargs.numInSamples; - c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs; - mNextFrameTimestampUs = work->input.ordinal.timestamp + mInputTimeUs = work->input.ordinal.timestamp + (consumed * 1000000ll / channelCount / sampleRate); - std::shared_ptr buffer = createLinearBuffer(block, 0, outargs.numOutBytes); + buffer = createLinearBuffer(block, 0, outargs.numOutBytes); #if defined(LOG_NDEBUG) && !LOG_NDEBUG hexdump(outPtr, std::min(outargs.numOutBytes, 256)); #endif outPtr = temp; outAvailable = 0; block.reset(); - - outputBuffers.push_back({buffer, currentFrameTimestampUs}); } else { mInputSize += outargs.numInSamples * sizeof(int16_t); } @@ -504,9 +506,8 @@ void C2SoftAacEnc::process( inargs.numInSamples -= outargs.numInSamples; } } - ALOGV("encoderErr = %d mInputSize = %zu " - "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld", - encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll()); + ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld", + encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll()); } if (eos && inBufferSize[0] > 0) { @@ -541,27 +542,10 @@ void C2SoftAacEnc::process( &outargs); } - while (outputBuffers.size() > 1) { - const OutputBuffer& front = outputBuffers.front(); - C2WorkOrdinalStruct ordinal = work->input.ordinal; - ordinal.frameIndex = mOutIndex++; - ordinal.timestamp = front.timestampUs; - cloneAndSend( - inputIndex, - work, - FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer)); - outputBuffers.pop_front(); - } - std::shared_ptr buffer; - C2WorkOrdinalStruct ordinal = work->input.ordinal; - ordinal.frameIndex = mOutIndex++; - if (!outputBuffers.empty()) { - ordinal.timestamp = outputBuffers.front().timestampUs; - buffer = outputBuffers.front().buffer; - } - // Mark the end of frame + outOrdinal.frameIndex = mOutIndex++; + outOrdinal.timestamp = mInputTimeUs; FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0), - ordinal, buffer)(work); + outOrdinal, buffer)(work); } c2_status_t C2SoftAacEnc::drain( @@ -585,7 +569,7 @@ c2_status_t C2SoftAacEnc::drain( mSentCodecSpecificData = false; mInputTimeSet = false; mInputSize = 0u; - mNextFrameTimestampUs = 0; + mInputTimeUs = 0; // TODO: we don't have any pending work at this time to drain. return C2_OK; diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h index 26550397af..a38be190a1 100644 --- a/media/codec2/components/aac/C2SoftAacEnc.h +++ b/media/codec2/components/aac/C2SoftAacEnc.h @@ -56,7 +56,7 @@ private: bool mSentCodecSpecificData; bool mInputTimeSet; size_t mInputSize; - c2_cntr64_t mNextFrameTimestampUs; + c2_cntr64_t mInputTimeUs; bool mSignalledError; std::atomic_uint64_t mOutIndex; From 41092178706d6ed388417dac4add325c95bf15f6 Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Fri, 9 Aug 2019 18:20:33 -0700 Subject: [PATCH 43/44] MediaMuxer:SetCaptureRate for GCA SlowMotionRecord MediaMuxer would find 'time-lapse-fps' value in input format from GCA and pass it on to MPEG4Writer for SlowMotionRecord. Bug: 138995916 Test: atest CtsMediaTestCases atest CtsMediaTestCases:android.media.cts.MediaMuxerTest Change-Id: I6af102540ddd439b203351ebba07eabf89f2d330 --- media/libstagefright/MPEG4Writer.cpp | 7 ++++++- media/libstagefright/MediaMuxer.cpp | 14 +++++++++++--- .../include/media/stagefright/MediaWriter.h | 4 ++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 2f13dc9d57..f130c9b082 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -1635,8 +1635,13 @@ status_t MPEG4Writer::setCaptureRate(float captureFps) { return BAD_VALUE; } + // Increase moovExtraSize once only irrespective of how many times + // setCaptureRate is called. + bool containsCaptureFps = mMetaKeys->contains(kMetaKey_CaptureFps); mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps); - mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32; + if (!containsCaptureFps) { + mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32; + } return OK; } diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp index 9ba2add491..7ebdb1aaa3 100644 --- a/media/libstagefright/MediaMuxer.cpp +++ b/media/libstagefright/MediaMuxer.cpp @@ -96,10 +96,18 @@ ssize_t MediaMuxer::addTrack(const sp &format) { sp newTrack = new MediaAdapter(trackMeta); status_t result = mWriter->addSource(newTrack); - if (result == OK) { - return mTrackList.add(newTrack); + if (result != OK) { + return -1; + } + float captureFps = -1.0; + if (format->findAsFloat("time-lapse-fps", &captureFps)) { + ALOGV("addTrack() time-lapse-fps: %f", captureFps); + result = mWriter->setCaptureRate(captureFps); + if (result != OK) { + ALOGW("addTrack() setCaptureRate failed :%d", result); + } } - return -1; + return mTrackList.add(newTrack); } status_t MediaMuxer::setOrientationHint(int degrees) { diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h index 2c12a87f36..972ae1d218 100644 --- a/media/libstagefright/include/media/stagefright/MediaWriter.h +++ b/media/libstagefright/include/media/stagefright/MediaWriter.h @@ -35,6 +35,10 @@ struct MediaWriter : public RefBase { virtual status_t start(MetaData *params = NULL) = 0; virtual status_t stop() = 0; virtual status_t pause() = 0; + virtual status_t setCaptureRate(float /* captureFps */) { + ALOGW("setCaptureRate unsupported"); + return ERROR_UNSUPPORTED; + } virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; } virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; } From 847eaf44dd735b9c1c3c7648add3665bd639bd9a Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Wed, 14 Aug 2019 10:28:29 -0700 Subject: [PATCH 44/44] Add option to remove OMX components from IOmxStore Test: vts-tradefed run vts -m VtsHalMediaOmxStoreV1_0Host Bug: 139111743 Change-Id: Ica1e1619f53615f5e2363f7e7aec1831649631e2 --- services/mediacodec/main_codecservice.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp index f668c3381b..6a82b1b6b8 100644 --- a/services/mediacodec/main_codecservice.cpp +++ b/services/mediacodec/main_codecservice.cpp @@ -21,6 +21,7 @@ #include "minijail.h" #include +#include #include #include #include @@ -57,7 +58,8 @@ int main(int argc __unused, char** argv) } else { LOG(INFO) << "IOmx HAL service created."; } - sp omxStore = new implementation::OmxStore(omx); + sp omxStore = new implementation::OmxStore( + property_get_int64("vendor.media.omx", 1) ? omx : nullptr); if (omxStore == nullptr) { LOG(ERROR) << "Cannot create IOmxStore HAL service."; } else if (omxStore->registerAsService() != OK) {