Merge 24Q3 (ab/AP3A.240905.001) to aosp-main-future
Bug: 347831320
Merged-In: I72523e1de61e5f947174272b732e170e1c2964df
Change-Id: I72820c965561d6ea3d6a1527853206ed6de5d2c5
diff --git a/Android.bp b/Android.bp
index c11e38a..0c7ed6e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -160,11 +160,11 @@
imports: ["android.hardware.audio.core-V2"],
},
],
- frozen: true,
+ frozen: false,
}
-latest_av_audio_types_aidl = "av-audio-types-aidl-V1"
+latest_av_audio_types_aidl = "av-audio-types-aidl-V2"
cc_defaults {
name: "latest_av_audio_types_aidl_ndk_shared",
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f36a743..0c80e7e 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -177,14 +177,11 @@
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
- do {
- binder = sm->getService(toString16(kCameraServiceName));
- if (binder != nullptr) {
- break;
- }
- ALOGW("CameraService not published, waiting...");
- usleep(kCameraServicePollDelay);
- } while(true);
+ binder = sm->checkService(String16(kCameraServiceName));
+ if (binder == nullptr) {
+ ALOGE("%s: Could not get CameraService instance.", __FUNCTION__);
+ return nullptr;
+ }
if (mDeathNotifier == nullptr) {
mDeathNotifier = new DeathNotifier(this);
}
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index d8bf6b1..f4124ef 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -99,7 +99,6 @@
private:
sp<hardware::ICameraService> mCameraService;
- const int kCameraServicePollDelay = 500000; // 0.5s
const char* kCameraServiceName = "media.camera";
Mutex mLock;
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index 16ea15e..6e55a16 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -64,10 +64,6 @@
"libfwdlock-decoder",
],
- whole_static_libs: [
- "libc++fs",
- ],
-
local_include_dirs: ["include"],
relative_install_path: "drm",
diff --git a/media/audioaidlconversion/include/media/AidlConversionEffect.h b/media/audioaidlconversion/include/media/AidlConversionEffect.h
index b03d06b..e51bf8b 100644
--- a/media/audioaidlconversion/include/media/AidlConversionEffect.h
+++ b/media/audioaidlconversion/include/media/AidlConversionEffect.h
@@ -72,9 +72,6 @@
MAKE_EXTENSION_PARAMETER_ID(_effect, _tag##Tag, _extId); \
aidl::android::hardware::audio::effect::Parameter _aidlParam; \
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(_id, &_aidlParam))); \
- aidl::android::hardware::audio::effect::VendorExtension _ext = \
- VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD( \
- _aidlParam, _effect, _tag, _effect::vendor, VendorExtension)); \
return VALUE_OR_RETURN_STATUS( \
aidl::android::aidl2legacy_Parameter_EffectParameterWriter(_aidlParam, _param)); \
}
diff --git a/media/codec2/hal/client/GraphicBufferAllocator.cpp b/media/codec2/hal/client/GraphicBufferAllocator.cpp
index 8f489ec..6a6da0f 100644
--- a/media/codec2/hal/client/GraphicBufferAllocator.cpp
+++ b/media/codec2/hal/client/GraphicBufferAllocator.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "Codec2-GraphicBufferAllocator"
-#include <gui/IProducerListener.h>
#include <media/stagefright/foundation/ADebug.h>
#include <codec2/aidl/GraphicBufferAllocator.h>
@@ -25,25 +24,6 @@
namespace aidl::android::hardware::media::c2::implementation {
-class OnBufferReleasedListener : public ::android::BnProducerListener {
-private:
- uint32_t mGeneration;
- std::weak_ptr<GraphicBufferAllocator> mAllocator;
-public:
- OnBufferReleasedListener(
- uint32_t generation,
- const std::shared_ptr<GraphicBufferAllocator> &allocator)
- : mGeneration(generation), mAllocator(allocator) {}
- virtual ~OnBufferReleasedListener() = default;
- virtual void onBufferReleased() {
- auto p = mAllocator.lock();
- if (p) {
- p->onBufferReleased(mGeneration);
- }
- }
- virtual bool needsReleaseNotify() { return true; }
-};
-
::ndk::ScopedAStatus GraphicBufferAllocator::allocate(
const IGraphicBufferAllocator::Description& in_desc,
IGraphicBufferAllocator::Allocation* _aidl_return) {
@@ -108,15 +88,14 @@
mGraphicsTracker->stop();
}
-const ::android::sp<::android::IProducerListener> GraphicBufferAllocator::createReleaseListener(
- uint32_t generation) {
- return new OnBufferReleasedListener(generation, ref<GraphicBufferAllocator>());
-}
-
void GraphicBufferAllocator::onBufferReleased(uint32_t generation) {
mGraphicsTracker->onReleased(generation);
}
+void GraphicBufferAllocator::onBufferAttached(uint32_t generation) {
+ mGraphicsTracker->onAttached(generation);
+}
+
c2_status_t GraphicBufferAllocator::allocate(
uint32_t width, uint32_t height, ::android::PixelFormat format, uint64_t usage,
AHardwareBuffer **buf, ::android::sp<::android::Fence> *fence) {
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 95f5a6e..8d9e76e 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -1001,6 +1001,11 @@
{
std::unique_lock<std::mutex> l(mLock);
if (mBufferCache->mGeneration == generation) {
+ if (mBufferCache->mNumAttached > 0) {
+ ALOGV("one onReleased() ignored for each prior onAttached().");
+ mBufferCache->mNumAttached--;
+ return;
+ }
if (!adjustDequeueConfLocked(&updateDequeue)) {
mDequeueable++;
writeIncDequeueableLocked(1);
@@ -1012,4 +1017,12 @@
}
}
+void GraphicsTracker::onAttached(uint32_t generation) {
+ std::unique_lock<std::mutex> l(mLock);
+ if (mBufferCache->mGeneration == generation) {
+ ALOGV("buffer attached");
+ mBufferCache->mNumAttached++;
+ }
+}
+
} // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 1d2794e..a137dbb 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -2556,6 +2556,19 @@
mOutputBufferQueue->onBufferReleased(generation);
}
+void Codec2Client::Component::onBufferAttachedToOutputSurface(
+ uint32_t generation) {
+ if (mAidlBase) {
+ std::shared_ptr<AidlGraphicBufferAllocator> gba =
+ mGraphicBufferAllocators->current();
+ if (gba) {
+ gba->onBufferAttached(generation);
+ }
+ return;
+ }
+ mOutputBufferQueue->onBufferAttached(generation);
+}
+
void Codec2Client::Component::holdIgbaBlocks(
const std::list<std::unique_ptr<C2Work>>& workList) {
if (!mAidlBase) {
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
index 902c53f..a797cb7 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicBufferAllocator.h
@@ -71,18 +71,6 @@
void reset();
/**
- * Create a listener for buffer being released.
- *
- * Surface will register this listener and notify whenever the consumer
- * releases a buffer.
- *
- * @param generation generation # for the BufferQueue.
- * @return IProducerListener can be used when connect# to Surface.
- */
- const ::android::sp<::android::IProducerListener> createReleaseListener(
- uint32_t generation);
-
- /**
* Notifies a buffer being released.
*
* @param generation generation # for the BufferQueue.
@@ -90,6 +78,13 @@
void onBufferReleased(uint32_t generation);
/**
+ * Notifies a buffer being attached to the consumer.
+ *
+ * @param generation generation # for the BufferQueue.
+ */
+ void onBufferAttached(uint32_t generation);
+
+ /**
* Allocates a buffer.
*
* @param width width of the requested buffer.
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 762030b..9a4fa12 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -143,6 +143,18 @@
void onReleased(uint32_t generation);
/**
+ * Notifies when a Buffer is attached to Graphics(consumer side).
+ * If generation does not match to the current, notifications via the interface
+ * will be ignored. (In the case, the notifications are from one of the old surfaces
+ * which is no longer used.)
+ * One onReleased() should be ignored for one onAttached() when both of
+ * them have the same generation as params.
+ *
+ * @param[in] generation generation id for specifying Graphics(BQ)
+ */
+ void onAttached(uint32_t generation);
+
+ /**
* Get waitable fd for events.(allocate is ready, end of life cycle)
*
* @param[out] pipeFd a file descriptor created from pipe2()
@@ -217,9 +229,11 @@
BlockedSlot mBlockedSlots[kNumSlots];
- BufferCache() : mBqId{0ULL}, mGeneration{0}, mIgbp{nullptr} {}
+ std::atomic<int> mNumAttached;
+
+ BufferCache() : mBqId{0ULL}, mGeneration{0}, mIgbp{nullptr}, mNumAttached{0} {}
BufferCache(uint64_t bqId, uint32_t generation, const sp<IGraphicBufferProducer>& igbp) :
- mBqId{bqId}, mGeneration{generation}, mIgbp{igbp} {}
+ mBqId{bqId}, mGeneration{generation}, mIgbp{igbp}, mNumAttached{0} {}
~BufferCache();
diff --git a/media/codec2/hal/client/include/codec2/hidl/client.h b/media/codec2/hal/client/include/codec2/hidl/client.h
index 5c75a47..413e92e 100644
--- a/media/codec2/hal/client/include/codec2/hidl/client.h
+++ b/media/codec2/hal/client/include/codec2/hidl/client.h
@@ -481,6 +481,10 @@
void onBufferReleasedFromOutputSurface(
uint32_t generation);
+ // Notify a buffer is attached to output surface.
+ void onBufferAttachedToOutputSurface(
+ uint32_t generation);
+
// When the client received \p workList and the blocks inside
// \p workList are IGBA based graphic blocks, specify the owner
// as the current IGBA for the future operations.
diff --git a/media/codec2/hal/client/include/codec2/hidl/output.h b/media/codec2/hal/client/include/codec2/hidl/output.h
index fda34a8..ddb9855 100644
--- a/media/codec2/hal/client/include/codec2/hidl/output.h
+++ b/media/codec2/hal/client/include/codec2/hidl/output.h
@@ -69,6 +69,9 @@
// update the number of dequeueable/allocatable buffers.
void onBufferReleased(uint32_t generation);
+ // Nofify a buffer is attached to the output surface.
+ void onBufferAttached(uint32_t generation);
+
// Retrieve frame event history from the output surface.
void pollForRenderedFrames(FrameEventHistoryDelta* delta);
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index 36322f5..54d78a0 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -542,6 +542,11 @@
}
}
+void OutputBufferQueue::onBufferAttached(uint32_t generation) {
+ // TODO
+ (void) generation;
+}
+
void OutputBufferQueue::pollForRenderedFrames(FrameEventHistoryDelta* delta) {
if (mIgbp) {
mIgbp->getFrameTimestamps(delta);
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 39aadd7..0aae23c 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -2605,18 +2605,31 @@
c2_status_t status = GetCodec2BlockPool(C2BlockPool::BASIC_LINEAR, nullptr, &pool);
if (status == C2_OK) {
+ int width, height;
+ config->mInputFormat->findInt32("width", &width);
+ config->mInputFormat->findInt32("height", &height);
+ // The length of the qp-map corresponds to the number of 16x16 blocks in one frame
+ int expectedMapSize = ((width + 15) / 16) * ((height + 15) / 16);
size_t mapSize = qpOffsetMap->size();
- std::shared_ptr<C2LinearBlock> block;
- status = pool->fetchLinearBlock(mapSize,
- C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
- if (status == C2_OK && !block->map().get().error()) {
- C2WriteView wView = block->map().get();
- uint8_t* outData = wView.data();
- memcpy(outData, qpOffsetMap->data(), mapSize);
- C2InfoBuffer info = C2InfoBuffer::CreateLinearBuffer(
- kParamIndexQpOffsetMapBuffer,
- block->share(0, mapSize, C2Fence()));
- mChannel->setInfoBuffer(std::make_shared<C2InfoBuffer>(info));
+ if (mapSize >= expectedMapSize) {
+ std::shared_ptr<C2LinearBlock> block;
+ status = pool->fetchLinearBlock(
+ expectedMapSize,
+ C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+ &block);
+ if (status == C2_OK && !block->map().get().error()) {
+ C2WriteView wView = block->map().get();
+ uint8_t* outData = wView.data();
+ memcpy(outData, qpOffsetMap->data(), expectedMapSize);
+ C2InfoBuffer info = C2InfoBuffer::CreateLinearBuffer(
+ kParamIndexQpOffsetMapBuffer,
+ block->share(0, expectedMapSize, C2Fence()));
+ mChannel->setInfoBuffer(std::make_shared<C2InfoBuffer>(info));
+ }
+ } else {
+ ALOGE("Ignoring param key %s as buffer size %zu is less than expected "
+ "buffer size %d",
+ PARAMETER_KEY_QP_OFFSET_MAP, mapSize, expectedMapSize);
}
}
params->removeEntryByName(PARAMETER_KEY_QP_OFFSET_MAP);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index f0a4180..1348ef0 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1469,6 +1469,17 @@
}
}
+void CCodecBufferChannel::onBufferAttachedToOutputSurface(uint32_t generation) {
+ // Note: Since this is called asynchronously from IProducerListener not
+ // knowing the internal state of CCodec/CCodecBufferChannel,
+ // prevent mComponent from being destroyed by holding the shared reference
+ // during this interface being executed.
+ std::shared_ptr<Codec2Client::Component> comp = mComponent;
+ if (comp) {
+ comp->onBufferAttachedToOutputSurface(generation);
+ }
+}
+
status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
bool released = false;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 94a5998..e62742b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -102,6 +102,7 @@
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
void pollForRenderedBuffers() override;
void onBufferReleasedFromOutputSurface(uint32_t generation) override;
+ void onBufferAttachedToOutputSurface(uint32_t generation) override;
status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index db59227..36725ec 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -1890,6 +1890,9 @@
if (mDomain == (IS_VIDEO | IS_ENCODER)) {
AString qpOffsetRects;
if (params->findString(PARAMETER_KEY_QP_OFFSET_RECTS, &qpOffsetRects)) {
+ int width, height;
+ mInputFormat->findInt32("width", &width);
+ mInputFormat->findInt32("height", &height);
std::vector<C2QpOffsetRectStruct> c2QpOffsetRects;
char mutableStrQpOffsetRects[strlen(qpOffsetRects.c_str()) + 1];
strcpy(mutableStrQpOffsetRects, qpOffsetRects.c_str());
@@ -1899,11 +1902,17 @@
if (sscanf(box, "%d,%d-%d,%d=%d", &top, &left, &bottom, &right, &offset) == 5) {
left = c2_max(0, left);
top = c2_max(0, top);
+ right = c2_min(right, width);
+ bottom = c2_min(bottom, height);
if (right > left && bottom > top) {
C2Rect rect(right - left, bottom - top);
rect.at(left, top);
c2QpOffsetRects.push_back(C2QpOffsetRectStruct(rect, offset));
+ } else {
+ ALOGE("Rects configuration %s is not valid.", box);
}
+ } else {
+ ALOGE("Rects configuration %s doesn't follow the string pattern.", box);
}
box = strtok(nullptr, ";");
}
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index 1e8dd40..806932c 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -44,7 +44,77 @@
*
* If a specific HGBP is configured, the HGBP acts as an allocator for creating graphic blocks.
*
- * TODO: add more ducumentation(graphic block life-cycle, waitable object and workaounds)
+ *
+ * HGBP/IGBP and the BlockPool
+ *
+ * GraphicBuffer(s) from BufferQueue(IGBP/IGBC) are based on slot id.
+ * A created GraphicBuffer occupies a slot(so the GraphicBuffer has a slot-id).
+ * A GraphicBuffer is produced and consumed and recyled based on the slot-id
+ * w.r.t. BufferQueue.
+ *
+ * HGBP::dequeueBuffer() returns a slot id where the slot has an available GraphicBuffer.
+ * If it is necessary, HGBP allocates a new GraphicBuffer to the slot and indicates
+ * that a new buffer is allocated as return flag.
+ * To retrieve the GraphicBuffer, HGBP::requestBuffer() along with the slot id
+ * is required. In order to save HGBP remote calls, the blockpool caches the
+ * allocated GraphicBuffer(s) along with the slot information.
+ *
+ * The blockpool provides C2GraphicBlock upon \fetchGraphicBlock().
+ * The C2GraphicBlock has a native handle, which is extracted from a GraphicBuffer
+ * and then cloned for independent life-cycle with the GraphicBuffer. The GraphicBuffer
+ * is allocated by HGBP::dequeueBuffer() and retrieved by HGBP::requestBuffer()
+ * if there is a HGBP configured.
+ *
+ *
+ * Life-cycle of C2GraphicBlock
+ *
+ * The decoder HAL writes a decoded frame into C2GraphicBlock. Upon
+ * completion, the component sends the block to the client in the remote process
+ * (i.e. to MediaCodec). The remote process renders the frame into the output surface
+ * via IGBP::queueBuffer() (Note: this is not hidlized.).
+ *
+ * If the decoder HAL destroys the C2GraphicBlock without transferring to the
+ * client, the destroy request goes to the BlockPool. Then
+ * the BlockPool free the associated GraphicBuffer from a slot to
+ * HGBP in order to recycle via HGBP::cancelBuffer().
+ *
+ *
+ * Clearing the Cache(GraphicBuffer)
+ *
+ * When the output surface is switched to a new surface, The GraphicBuffers from
+ * the old surface is either migrated or cleared.
+ *
+ * The GraphicBuffer(s) still in use are migrated to a new surface during
+ * configuration via HGBP::attachBuffer(). The GraphicBuffer(s) not in use are
+ * cleared from the cache inside the BlockPool.
+ *
+ * When the surface is switched to a null surface, all the
+ * GraphicBuffers in the cache are cleared.
+ *
+ *
+ * Workaround w.r.t. b/322731059 (Deferring cleaning the cache)
+ *
+ * Some vendor devices have issues with graphic buffer lifecycle management,
+ * where the graphic buffers get released even when the cloned native handles
+ * in the remote process are not closed yet. This issue led to rare crashes
+ * for those devices when the cache is cleared early.
+ *
+ * We workarounded the crash by deferring the cleaning of the cache.
+ * The workaround is not enabled by default, and can be enabled via a
+ * system property as shown below:
+ *
+ * 'debug.codec2.bqpool_dealloc_after_stop' = 1
+ *
+ * Configuring the debug flag will call \::setDeferDeallocationAfterStop()
+ * after the blockpool creation. This will enable the deferring.
+ *
+ * After enabling the deferring, clearing the GraphicBuffer is delayed until
+ * 1) \::clearDeferredBlocks() is called.
+ * Typically after HAL processes stop() request.
+ * 2) Or a new ::fetchGraphicBlock() is called.
+ *
+ * Since the deferring will delay the deallocation, the deferring will result
+ * in more memory consumption during the brief period.
*/
class C2BufferQueueBlockPool : public C2BlockPool {
public:
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 21321b9..e19d526 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -574,7 +574,7 @@
* For privacy, the following usages can not be recorded: AAUDIO_VOICE_COMMUNICATION*,
* AAUDIO_USAGE_NOTIFICATION*, AAUDIO_USAGE_ASSISTANCE* and {@link #AAUDIO_USAGE_ASSISTANT}.
*
- * On <a href="/reference/android/os/Build.VERSION_CODES#Q">Build.VERSION_CODES</a>,
+ * On <a href="/reference/android/os/Build.VERSION_CODES#Q">Q</a>,
* this means only {@link #AAUDIO_USAGE_MEDIA} and {@link #AAUDIO_USAGE_GAME} may be captured.
*
* See <a href="/reference/android/media/AudioAttributes.html#ALLOW_CAPTURE_BY_ALL">
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 3e51575..67fc668 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -23,13 +23,6 @@
using namespace aaudio;
-// TODO These defines should be moved to a central place in audio.
-#define SAMPLES_PER_FRAME_MIN 1
-#define SAMPLES_PER_FRAME_MAX FCC_LIMIT
-#define SAMPLE_RATE_HZ_MIN 8000
-// HDMI supports up to 32 channels at 1536000 Hz.
-#define SAMPLE_RATE_HZ_MAX 1600000
-
void AAudioStreamParameters::copyFrom(const AAudioStreamParameters &other) {
mSamplesPerFrame = other.mSamplesPerFrame;
mSampleRate = other.mSampleRate;
@@ -73,8 +66,8 @@
}
aaudio_result_t AAudioStreamParameters::validate() const {
- if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
- && (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
+ if (mSamplesPerFrame != AAUDIO_UNSPECIFIED && (mSamplesPerFrame < CHANNEL_COUNT_MIN_AAUDIO ||
+ mSamplesPerFrame > CHANNEL_COUNT_MAX_AAUDIO)) {
ALOGD("channelCount out of range = %d", mSamplesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -105,8 +98,8 @@
aaudio_result_t result = isFormatValid (mAudioFormat);
if (result != AAUDIO_OK) return result;
- if (mSampleRate != AAUDIO_UNSPECIFIED
- && (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
+ if (mSampleRate != AAUDIO_UNSPECIFIED &&
+ (mSampleRate < SAMPLE_RATE_HZ_MIN_AAUDIO || mSampleRate > SAMPLE_RATE_HZ_MAX_IEC610937)) {
ALOGD("sampleRate out of range = %d", mSampleRate);
return AAUDIO_ERROR_INVALID_RATE;
}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 9bbaf3e..c9d8b35 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -50,15 +50,6 @@
#define AAUDIO_MMAP_POLICY_DEFAULT_AIDL AudioMMapPolicy::NEVER
#define AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT_AIDL AudioMMapPolicy::NEVER
-// These values are for a pre-check before we ask the lower level service to open a stream.
-// So they are just outside the maximum conceivable range of value,
-// on the edge of being ridiculous.
-// TODO These defines should be moved to a central place in audio.
-#define SAMPLES_PER_FRAME_MIN 1
-#define SAMPLES_PER_FRAME_MAX FCC_LIMIT
-#define SAMPLE_RATE_HZ_MIN 8000
-// HDMI supports up to 32 channels at 1536000 Hz.
-#define SAMPLE_RATE_HZ_MAX 1600000
#define FRAMES_PER_DATA_CALLBACK_MIN 1
#define FRAMES_PER_DATA_CALLBACK_MAX (1024 * 1024)
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 85cc9bd..e2386ca 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -319,13 +319,6 @@
const audio_attributes_t* pAttributes,
bool doNotReconnect,
float maxRequiredSpeed)
- : mStatus(NO_INIT),
- mState(STATE_STOPPED),
- mPreviousPriority(ANDROID_PRIORITY_NORMAL),
- mPreviousSchedulingGroup(SP_DEFAULT),
- mPausedPosition(0),
- mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mAudioTrackCallback(new AudioTrackCallback())
{
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 441e329..163a359 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -379,6 +379,8 @@
return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
case media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+ case media::AudioPolicyForcedConfig::BT_BLE:
+ return AUDIO_POLICY_FORCE_BT_BLE;
}
return unexpected(BAD_VALUE);
}
@@ -418,6 +420,8 @@
return media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
return media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
+ case AUDIO_POLICY_FORCE_BT_BLE:
+ return media::AudioPolicyForcedConfig::BT_BLE;
case AUDIO_POLICY_FORCE_CFG_CNT:
break;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
index 2255d4c..111bb2f 100644
--- a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
@@ -36,4 +36,5 @@
ENCODED_SURROUND_NEVER = 13,
ENCODED_SURROUND_ALWAYS = 14,
ENCODED_SURROUND_MANUAL = 15,
+ BT_BLE = 16,
}
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 9c3ad44..ddf14a3 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -134,6 +134,9 @@
"libaudiomanager",
"libaudiopolicy",
],
+ cflags: [
+ "-Wthread-safety",
+ ],
data: ["bbb*.raw"],
srcs: [
"audio_test_utils.cpp",
diff --git a/media/libaudioclient/tests/audio_test_utils.cpp b/media/libaudioclient/tests/audio_test_utils.cpp
index 9a202cc3..1599839 100644
--- a/media/libaudioclient/tests/audio_test_utils.cpp
+++ b/media/libaudioclient/tests/audio_test_utils.cpp
@@ -28,25 +28,35 @@
void OnAudioDeviceUpdateNotifier::onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId) {
- std::unique_lock<std::mutex> lock{mMutex};
ALOGI("%s: audioIo=%d deviceId=%d", __func__, audioIo, deviceId);
- mAudioIo = audioIo;
- mDeviceId = deviceId;
+ {
+ std::lock_guard lock(mMutex);
+ mAudioIo = audioIo;
+ mDeviceId = deviceId;
+ }
mCondition.notify_all();
}
status_t OnAudioDeviceUpdateNotifier::waitForAudioDeviceCb(audio_port_handle_t expDeviceId) {
- std::unique_lock<std::mutex> lock{mMutex};
+ std::unique_lock lock(mMutex);
+ android::base::ScopedLockAssertion lock_assertion(mMutex);
if (mAudioIo == AUDIO_IO_HANDLE_NONE ||
(expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId)) {
mCondition.wait_for(lock, std::chrono::milliseconds(500));
if (mAudioIo == AUDIO_IO_HANDLE_NONE ||
- (expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId))
+ (expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId)) {
return TIMED_OUT;
+ }
}
return OK;
}
+std::pair<audio_io_handle_t, audio_port_handle_t>
+OnAudioDeviceUpdateNotifier::getLastPortAndDevice() const {
+ std::lock_guard lock(mMutex);
+ return {mAudioIo, mDeviceId};
+}
+
AudioPlayback::AudioPlayback(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, audio_output_flags_t flags,
audio_session_t sessionId, AudioTrack::transfer_type transferType,
@@ -147,9 +157,8 @@
}
void AudioPlayback::onBufferEnd() {
- std::unique_lock<std::mutex> lock{mMutex};
+ std::lock_guard lock(mMutex);
mStopPlaying = true;
- mCondition.notify_all();
}
status_t AudioPlayback::fillBuffer() {
@@ -187,7 +196,12 @@
const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
int counter = 0;
size_t totalFrameCount = mMemCapacity / mTrack->frameSize();
- while (!mStopPlaying && counter < maxTries) {
+ bool stopPlaying;
+ {
+ std::lock_guard lock(mMutex);
+ stopPlaying = mStopPlaying;
+ }
+ while (!stopPlaying && counter < maxTries) {
uint32_t currPosition;
mTrack->getPosition(&currPosition);
if (currPosition >= totalFrameCount) counter++;
@@ -213,7 +227,10 @@
mTrack->start();
}
std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_PERIOD_MS));
+ std::lock_guard lock(mMutex);
+ stopPlaying = mStopPlaying;
}
+ std::lock_guard lock(mMutex);
if (!mStopPlaying && counter == maxTries) return TIMED_OUT;
return OK;
}
@@ -228,8 +245,10 @@
}
void AudioPlayback::stop() {
- std::unique_lock<std::mutex> lock{mMutex};
- mStopPlaying = true;
+ {
+ std::lock_guard lock(mMutex);
+ mStopPlaying = true;
+ }
if (mState != PLAY_STOPPED && mState != PLAY_NO_INIT) {
int32_t msec = 0;
(void)mTrack->pendingDuration(&msec);
@@ -257,10 +276,13 @@
return 0;
}
- // no more frames to read
- if (mNumFramesReceived >= mNumFramesToRecord || mStopRecording) {
- mStopRecording = true;
- return 0;
+ {
+ std::lock_guard l(mMutex);
+ // no more frames to read
+ if (mNumFramesReceived >= mNumFramesToRecord || mStopRecording) {
+ mStopRecording = true;
+ return 0;
+ }
}
int64_t timeUs = 0, position = 0, timeNs = 0;
@@ -272,6 +294,7 @@
ts.getBestTimestamp(&position, &timeNs, ExtendedTimestamp::TIMEBASE_MONOTONIC, &location) ==
OK) {
// Use audio timestamp.
+ std::lock_guard l(mMutex);
timeUs = timeNs / 1000 -
(position - mNumFramesReceived + mNumFramesLost) * usPerSec / mSampleRate;
} else {
@@ -300,6 +323,7 @@
} else {
numLostBytes = 0;
}
+ std::lock_guard l(mMutex);
const int64_t timestampUs =
((1000000LL * mNumFramesReceived) + (mRecord->getSampleRate() >> 1)) /
mRecord->getSampleRate();
@@ -313,6 +337,7 @@
if (buffer.size() == 0) {
ALOGW("Nothing is available from AudioRecord callback buffer");
} else {
+ std::lock_guard l(mMutex);
const size_t bufferSize = buffer.size();
const int64_t timestampUs =
((1000000LL * mNumFramesReceived) + (mRecord->getSampleRate() >> 1)) /
@@ -324,9 +349,12 @@
}
if (tmpQueue.size() > 0) {
- std::unique_lock<std::mutex> lock{mMutex};
- for (auto it = tmpQueue.begin(); it != tmpQueue.end(); it++)
- mBuffersReceived.push_back(std::move(*it));
+ {
+ std::lock_guard lock(mMutex);
+ mBuffersReceived.insert(mBuffersReceived.end(),
+ std::make_move_iterator(tmpQueue.begin()),
+ std::make_move_iterator(tmpQueue.end()));
+ }
mCondition.notify_all();
}
return buffer.size();
@@ -334,17 +362,24 @@
void AudioCapture::onOverrun() {
ALOGV("received event overrun");
- mBufferOverrun = true;
}
void AudioCapture::onMarker(uint32_t markerPosition) {
ALOGV("received Callback at position %d", markerPosition);
- mReceivedCbMarkerAtPosition = markerPosition;
+ {
+ std::lock_guard l(mMutex);
+ mReceivedCbMarkerAtPosition = markerPosition;
+ }
+ mMarkerCondition.notify_all();
}
void AudioCapture::onNewPos(uint32_t markerPosition) {
ALOGV("received Callback at position %d", markerPosition);
- mReceivedCbMarkerCount++;
+ {
+ std::lock_guard l(mMutex);
+ mReceivedCbMarkerCount = mReceivedCbMarkerCount.value_or(0) + 1;
+ }
+ mMarkerCondition.notify_all();
}
void AudioCapture::onNewIAudioRecord() {
@@ -362,20 +397,7 @@
mFlags(flags),
mSessionId(sessionId),
mTransferType(transferType),
- mAttributes(attributes) {
- mFrameCount = 0;
- mNotificationFrames = 0;
- mNumFramesToRecord = 0;
- mNumFramesReceived = 0;
- mNumFramesLost = 0;
- mBufferOverrun = false;
- mMarkerPosition = 0;
- mMarkerPeriod = 0;
- mReceivedCbMarkerAtPosition = -1;
- mReceivedCbMarkerCount = 0;
- mState = REC_NO_INIT;
- mStopRecording = false;
-}
+ mAttributes(attributes) {}
AudioCapture::~AudioCapture() {
if (mOutFileFd > 0) close(mOutFileFd);
@@ -484,7 +506,10 @@
status_t AudioCapture::stop() {
status_t status = OK;
- mStopRecording = true;
+ {
+ std::lock_guard l(mMutex);
+ mStopRecording = true;
+ }
if (mState != REC_STOPPED && mState != REC_NO_INIT) {
if (mInputSource != AUDIO_SOURCE_DEFAULT) {
bool state = false;
@@ -503,25 +528,32 @@
const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
int counter = 0;
size_t nonContig = 0;
- while (mNumFramesReceived < mNumFramesToRecord) {
+ int64_t numFramesReceived;
+ {
+ std::lock_guard l(mMutex);
+ numFramesReceived = mNumFramesReceived;
+ }
+ while (numFramesReceived < mNumFramesToRecord) {
AudioRecord::Buffer recordBuffer;
recordBuffer.frameCount = mNotificationFrames;
status_t status = mRecord->obtainBuffer(&recordBuffer, 1, &nonContig);
if (OK == status) {
const int64_t timestampUs =
- ((1000000LL * mNumFramesReceived) + (mRecord->getSampleRate() >> 1)) /
+ ((1000000LL * numFramesReceived) + (mRecord->getSampleRate() >> 1)) /
mRecord->getSampleRate();
RawBuffer buff{-1, timestampUs, static_cast<int32_t>(recordBuffer.size())};
memcpy(buff.mData.get(), recordBuffer.data(), recordBuffer.size());
buffer = std::move(buff);
- mNumFramesReceived += recordBuffer.size() / mRecord->frameSize();
+ numFramesReceived += recordBuffer.size() / mRecord->frameSize();
mRecord->releaseBuffer(&recordBuffer);
counter = 0;
} else if (WOULD_BLOCK == status) {
// if not received a buffer for MAX_WAIT_TIME_MS, something has gone wrong
- if (counter == maxTries) return TIMED_OUT;
- counter++;
+ if (counter++ == maxTries) status = TIMED_OUT;
}
+ std::lock_guard l(mMutex);
+ mNumFramesReceived = numFramesReceived;
+ if (TIMED_OUT == status) return status;
}
return OK;
}
@@ -530,7 +562,8 @@
if (REC_STARTED != mState) return INVALID_OPERATION;
const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
int counter = 0;
- std::unique_lock<std::mutex> lock{mMutex};
+ std::unique_lock lock(mMutex);
+ android::base::ScopedLockAssertion lock_assertion(mMutex);
while (mBuffersReceived.empty() && !mStopRecording && counter < maxTries) {
mCondition.wait_for(lock, std::chrono::milliseconds(WAIT_PERIOD_MS));
counter++;
@@ -548,7 +581,12 @@
status_t AudioCapture::audioProcess() {
RawBuffer buffer;
status_t status = OK;
- while (mNumFramesReceived < mNumFramesToRecord && status == OK) {
+ int64_t numFramesReceived;
+ {
+ std::lock_guard l(mMutex);
+ numFramesReceived = mNumFramesReceived;
+ }
+ while (numFramesReceived < mNumFramesToRecord && status == OK) {
if (mTransferType == AudioRecord::TRANSFER_CALLBACK)
status = obtainBufferCb(buffer);
else
@@ -557,10 +595,52 @@
const char* ptr = static_cast<const char*>(static_cast<void*>(buffer.mData.get()));
write(mOutFileFd, ptr, buffer.mCapacity);
}
+ std::lock_guard l(mMutex);
+ numFramesReceived = mNumFramesReceived;
}
return OK;
}
+uint32_t AudioCapture::getMarkerPeriod() const {
+ std::lock_guard l(mMutex);
+ return mMarkerPeriod;
+}
+
+uint32_t AudioCapture::getMarkerPosition() const {
+ std::lock_guard l(mMutex);
+ return mMarkerPosition;
+}
+
+void AudioCapture::setMarkerPeriod(uint32_t markerPeriod) {
+ std::lock_guard l(mMutex);
+ mMarkerPeriod = markerPeriod;
+}
+
+void AudioCapture::setMarkerPosition(uint32_t markerPosition) {
+ std::lock_guard l(mMutex);
+ mMarkerPosition = markerPosition;
+}
+
+uint32_t AudioCapture::waitAndGetReceivedCbMarkerAtPosition() const {
+ std::unique_lock lock(mMutex);
+ android::base::ScopedLockAssertion lock_assertion(mMutex);
+ mMarkerCondition.wait_for(lock, std::chrono::seconds(3), [this]() {
+ android::base::ScopedLockAssertion lock_assertion(mMutex);
+ return mReceivedCbMarkerAtPosition.has_value();
+ });
+ return mReceivedCbMarkerAtPosition.value_or(~0);
+}
+
+uint32_t AudioCapture::waitAndGetReceivedCbMarkerCount() const {
+ std::unique_lock lock(mMutex);
+ android::base::ScopedLockAssertion lock_assertion(mMutex);
+ mMarkerCondition.wait_for(lock, std::chrono::seconds(3), [this]() {
+ android::base::ScopedLockAssertion lock_assertion(mMutex);
+ return mReceivedCbMarkerCount.has_value();
+ });
+ return mReceivedCbMarkerCount.value_or(0);
+}
+
status_t listAudioPorts(std::vector<audio_port_v7>& portsVec) {
int attempts = 5;
status_t status;
diff --git a/media/libaudioclient/tests/audio_test_utils.h b/media/libaudioclient/tests/audio_test_utils.h
index 76e4642..022ecf3 100644
--- a/media/libaudioclient/tests/audio_test_utils.h
+++ b/media/libaudioclient/tests/audio_test_utils.h
@@ -19,14 +19,13 @@
#include <sys/stat.h>
#include <unistd.h>
-#include <atomic>
-#include <chrono>
-#include <cinttypes>
#include <deque>
#include <memory>
#include <mutex>
#include <thread>
+#include <utility>
+#include <android-base/thread_annotations.h>
#include <binder/MemoryDealer.h>
#include <media/AidlConversion.h>
#include <media/AudioRecord.h>
@@ -63,13 +62,15 @@
class OnAudioDeviceUpdateNotifier : public AudioSystem::AudioDeviceCallback {
public:
- audio_io_handle_t mAudioIo = AUDIO_IO_HANDLE_NONE;
- audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE;
- std::mutex mMutex;
- std::condition_variable mCondition;
-
- void onAudioDeviceUpdate(audio_io_handle_t audioIo, audio_port_handle_t deviceId);
+ void onAudioDeviceUpdate(audio_io_handle_t audioIo, audio_port_handle_t deviceId) override;
status_t waitForAudioDeviceCb(audio_port_handle_t expDeviceId = AUDIO_PORT_HANDLE_NONE);
+ std::pair<audio_io_handle_t, audio_port_handle_t> getLastPortAndDevice() const;
+
+ private:
+ audio_io_handle_t mAudioIo GUARDED_BY(mMutex) = AUDIO_IO_HANDLE_NONE;
+ audio_port_handle_t mDeviceId GUARDED_BY(mMutex) = AUDIO_PORT_HANDLE_NONE;
+ mutable std::mutex mMutex;
+ std::condition_variable mCondition;
};
// Simple AudioPlayback class.
@@ -86,15 +87,14 @@
status_t create();
sp<AudioTrack> getAudioTrackHandle();
status_t start();
- status_t waitForConsumption(bool testSeek = false);
+ status_t waitForConsumption(bool testSeek = false) EXCLUDES(mMutex);
status_t fillBuffer();
status_t onProcess(bool testSeek = false);
- virtual void onBufferEnd() override;
- void stop();
+ void onBufferEnd() override EXCLUDES(mMutex);
+ void stop() EXCLUDES(mMutex);
- bool mStopPlaying;
- std::mutex mMutex;
- std::condition_variable mCondition;
+ bool mStopPlaying GUARDED_BY(mMutex);
+ mutable std::mutex mMutex;
enum State {
PLAY_NO_INIT,
@@ -144,10 +144,10 @@
AudioRecord::transfer_type transferType = AudioRecord::TRANSFER_CALLBACK,
const audio_attributes_t* attributes = nullptr);
~AudioCapture();
- size_t onMoreData(const AudioRecord::Buffer& buffer) override;
+ size_t onMoreData(const AudioRecord::Buffer& buffer) override EXCLUDES(mMutex);
void onOverrun() override;
- void onMarker(uint32_t markerPosition) override;
- void onNewPos(uint32_t newPos) override;
+ void onMarker(uint32_t markerPosition) override EXCLUDES(mMutex);
+ void onNewPos(uint32_t newPos) override EXCLUDES(mMutex);
void onNewIAudioRecord() override;
status_t create();
status_t setRecordDuration(float durationInSec);
@@ -156,21 +156,20 @@
sp<AudioRecord> getAudioRecordHandle();
status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
audio_session_t triggerSession = AUDIO_SESSION_NONE);
- status_t obtainBufferCb(RawBuffer& buffer);
- status_t obtainBuffer(RawBuffer& buffer);
- status_t audioProcess();
- status_t stop();
+ status_t obtainBufferCb(RawBuffer& buffer) EXCLUDES(mMutex);
+ status_t obtainBuffer(RawBuffer& buffer) EXCLUDES(mMutex);
+ status_t audioProcess() EXCLUDES(mMutex);
+ status_t stop() EXCLUDES(mMutex);
+ uint32_t getMarkerPeriod() const EXCLUDES(mMutex);
+ uint32_t getMarkerPosition() const EXCLUDES(mMutex);
+ void setMarkerPeriod(uint32_t markerPeriod) EXCLUDES(mMutex);
+ void setMarkerPosition(uint32_t markerPosition) EXCLUDES(mMutex);
+ uint32_t waitAndGetReceivedCbMarkerAtPosition() const EXCLUDES(mMutex);
+ uint32_t waitAndGetReceivedCbMarkerCount() const EXCLUDES(mMutex);
- uint32_t mFrameCount;
- uint32_t mNotificationFrames;
- int64_t mNumFramesToRecord;
- int64_t mNumFramesReceived;
- int64_t mNumFramesLost;
- uint32_t mMarkerPosition;
- uint32_t mMarkerPeriod;
- uint32_t mReceivedCbMarkerAtPosition;
- uint32_t mReceivedCbMarkerCount;
- bool mBufferOverrun;
+ uint32_t mFrameCount = 0;
+ uint32_t mNotificationFrames = 0;
+ int64_t mNumFramesToRecord = 0;
enum State {
REC_NO_INIT,
@@ -191,14 +190,23 @@
size_t mMaxBytesPerCallback = 2048;
sp<AudioRecord> mRecord;
- State mState;
- bool mStopRecording;
+ State mState = REC_NO_INIT;
+ bool mStopRecording GUARDED_BY(mMutex) = false;
std::string mFileName;
int mOutFileFd = -1;
- std::mutex mMutex;
+ mutable std::mutex mMutex;
std::condition_variable mCondition;
- std::deque<RawBuffer> mBuffersReceived;
+ std::deque<RawBuffer> mBuffersReceived GUARDED_BY(mMutex);
+
+ mutable std::condition_variable mMarkerCondition;
+ uint32_t mMarkerPeriod GUARDED_BY(mMutex) = 0;
+ uint32_t mMarkerPosition GUARDED_BY(mMutex) = 0;
+ std::optional<uint32_t> mReceivedCbMarkerCount GUARDED_BY(mMutex);
+ std::optional<uint32_t> mReceivedCbMarkerAtPosition GUARDED_BY(mMutex);
+
+ int64_t mNumFramesReceived GUARDED_BY(mMutex) = 0;
+ int64_t mNumFramesLost GUARDED_BY(mMutex) = 0;
};
#endif // AUDIO_TEST_UTILS_H_
diff --git a/media/libaudioclient/tests/audioeffect_tests.cpp b/media/libaudioclient/tests/audioeffect_tests.cpp
index 59d0c6a..bedeff9 100644
--- a/media/libaudioclient/tests/audioeffect_tests.cpp
+++ b/media/libaudioclient/tests/audioeffect_tests.cpp
@@ -70,8 +70,8 @@
return effect;
}
-status_t isEffectExistsOnAudioSession(const effect_uuid_t* type, const effect_uuid_t* uuid,
- int priority, audio_session_t sessionId) {
+status_t createAndInitCheckEffect(const effect_uuid_t* type, const effect_uuid_t* uuid,
+ int priority, audio_session_t sessionId) {
sp<AudioEffect> effect = createEffect(type, uuid, priority, sessionId);
return effect->initCheck();
}
@@ -272,10 +272,9 @@
EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
capture->getAudioRecordHandle()))
<< "Effect should not have been default on record. " << type;
- EXPECT_EQ(NO_ERROR,
- isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
- kDefaultInputEffectPriority - 1,
- capture->getAudioRecordHandle()->getSessionId()))
+ EXPECT_EQ(NO_ERROR, createAndInitCheckEffect(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority - 1,
+ capture->getAudioRecordHandle()->getSessionId()))
<< "Effect should not have been added. " << type;
EXPECT_EQ(OK, capture->audioProcess());
EXPECT_EQ(OK, capture->stop());
@@ -296,9 +295,9 @@
capture->getAudioRecordHandle()))
<< "Effect should have been default on record. " << type;
EXPECT_EQ(ALREADY_EXISTS,
- isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
- kDefaultInputEffectPriority - 1,
- capture->getAudioRecordHandle()->getSessionId()))
+ createAndInitCheckEffect(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority - 1,
+ capture->getAudioRecordHandle()->getSessionId()))
<< "Effect should have been added. " << type;
EXPECT_EQ(OK, capture->audioProcess());
EXPECT_EQ(OK, capture->stop());
@@ -313,10 +312,9 @@
EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
capture->getAudioRecordHandle()))
<< "Effect should not have been default on record. " << type;
- EXPECT_EQ(NO_ERROR,
- isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
- kDefaultInputEffectPriority - 1,
- capture->getAudioRecordHandle()->getSessionId()))
+ EXPECT_EQ(NO_ERROR, createAndInitCheckEffect(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority - 1,
+ capture->getAudioRecordHandle()->getSessionId()))
<< "Effect should not have been added. " << type;
EXPECT_EQ(OK, capture->audioProcess());
EXPECT_EQ(OK, capture->stop());
@@ -421,8 +419,8 @@
EXPECT_EQ(NO_ERROR, playback->create());
EXPECT_EQ(NO_ERROR, playback->start());
EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT,
- isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
- playback->getAudioTrackHandle()->getSessionId()))
+ createAndInitCheckEffect(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+ playback->getAudioTrackHandle()->getSessionId()))
<< "Effect should not have been added. " << mTypeStr;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
playback->stop();
@@ -445,8 +443,8 @@
EXPECT_EQ(NO_ERROR, playback->start());
// If effect chosen is not compatible with the session, then effect won't be applied
EXPECT_EQ(compatCheck ? ALREADY_EXISTS : NO_INIT,
- isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
- playback->getAudioTrackHandle()->getSessionId()))
+ createAndInitCheckEffect(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+ playback->getAudioTrackHandle()->getSessionId()))
<< "Effect should have been added. " << mTypeStr;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
if (mSelectFastMode) {
@@ -467,8 +465,8 @@
EXPECT_EQ(NO_ERROR, playback->create());
EXPECT_EQ(NO_ERROR, playback->start());
EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT,
- isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
- playback->getAudioTrackHandle()->getSessionId()))
+ createAndInitCheckEffect(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+ playback->getAudioTrackHandle()->getSessionId()))
<< "Effect should not have been added. " << mTypeStr;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
playback->stop();
@@ -502,8 +500,8 @@
EXPECT_EQ(NO_ERROR, playback->create());
EXPECT_EQ(NO_ERROR, playback->start());
- EXPECT_EQ(ALREADY_EXISTS, isEffectExistsOnAudioSession(
- &mType, &mUuid, kDefaultOutputEffectPriority - 1, sessionId))
+ EXPECT_EQ(ALREADY_EXISTS,
+ createAndInitCheckEffect(&mType, &mUuid, kDefaultOutputEffectPriority - 1, sessionId))
<< "Effect should have been added. " << mTypeStr;
if (mSelectFastMode) {
EXPECT_EQ(mIsFastCompatibleEffect ? AUDIO_OUTPUT_FLAG_FAST : 0,
@@ -556,8 +554,8 @@
ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
EXPECT_EQ(NO_ERROR, playback->create());
EXPECT_EQ(NO_ERROR, playback->start());
- EXPECT_TRUE(isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
- kDefaultOutputEffectPriority - 1, sessionId))
+ ASSERT_EQ(ALREADY_EXISTS, createAndInitCheckEffect(selectedEffectType, selectedEffectUuid,
+ kDefaultOutputEffectPriority - 1, sessionId))
<< "Effect should have been added. " << type;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
playback->stop();
diff --git a/media/libaudioclient/tests/audiorecord_tests.cpp b/media/libaudioclient/tests/audiorecord_tests.cpp
index be6c581..f2fee8b 100644
--- a/media/libaudioclient/tests/audiorecord_tests.cpp
+++ b/media/libaudioclient/tests/audiorecord_tests.cpp
@@ -102,7 +102,10 @@
}
void TearDown() override {
- if (mAC) ASSERT_EQ(OK, mAC->stop());
+ if (mAC) {
+ ASSERT_EQ(OK, mAC->stop());
+ mAC.clear();
+ }
}
};
@@ -120,10 +123,12 @@
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->addAudioDeviceCallback(cb));
EXPECT_EQ(OK, mAC->start()) << "record creation failed";
EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
- EXPECT_EQ(AUDIO_IO_HANDLE_NONE, cbOld->mAudioIo);
- EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, cbOld->mDeviceId);
- EXPECT_NE(AUDIO_IO_HANDLE_NONE, cb->mAudioIo);
- EXPECT_NE(AUDIO_PORT_HANDLE_NONE, cb->mDeviceId);
+ const auto [oldAudioIo, oldDeviceId] = cbOld->getLastPortAndDevice();
+ EXPECT_EQ(AUDIO_IO_HANDLE_NONE, oldAudioIo);
+ EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, oldDeviceId);
+ const auto [audioIo, deviceId] = cb->getLastPortAndDevice();
+ EXPECT_NE(AUDIO_IO_HANDLE_NONE, audioIo);
+ EXPECT_NE(AUDIO_PORT_HANDLE_NONE, deviceId);
EXPECT_EQ(BAD_VALUE, mAC->getAudioRecordHandle()->removeAudioDeviceCallback(nullptr));
EXPECT_EQ(INVALID_OPERATION, mAC->getAudioRecordHandle()->removeAudioDeviceCallback(cbOld));
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->removeAudioDeviceCallback(cb));
@@ -166,31 +171,33 @@
}
TEST_F(AudioRecordTest, TestGetSetMarker) {
- mAC->mMarkerPosition = (mAC->mNotificationFrames << 3) + (mAC->mNotificationFrames >> 1);
- EXPECT_EQ(OK, mAC->getAudioRecordHandle()->setMarkerPosition(mAC->mMarkerPosition))
+ mAC->setMarkerPosition((mAC->mNotificationFrames << 3) + (mAC->mNotificationFrames >> 1));
+ EXPECT_EQ(OK, mAC->getAudioRecordHandle()->setMarkerPosition(mAC->getMarkerPosition()))
<< "setMarkerPosition() failed";
uint32_t marker;
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->getMarkerPosition(&marker))
<< "getMarkerPosition() failed";
EXPECT_EQ(OK, mAC->start()) << "start recording failed";
EXPECT_EQ(OK, mAC->audioProcess()) << "audioProcess failed";
- EXPECT_EQ(marker, mAC->mMarkerPosition)
+ EXPECT_EQ(marker, mAC->getMarkerPosition())
<< "configured marker and received marker are different";
- EXPECT_EQ(mAC->mReceivedCbMarkerAtPosition, mAC->mMarkerPosition)
+ EXPECT_EQ(mAC->waitAndGetReceivedCbMarkerAtPosition(), mAC->getMarkerPosition())
<< "configured marker and received cb marker are different";
}
TEST_F(AudioRecordTest, TestGetSetMarkerPeriodical) {
- mAC->mMarkerPeriod = (mAC->mNotificationFrames << 3) + (mAC->mNotificationFrames >> 1);
- EXPECT_EQ(OK, mAC->getAudioRecordHandle()->setPositionUpdatePeriod(mAC->mMarkerPeriod))
+ mAC->setMarkerPeriod((mAC->mNotificationFrames << 3) + (mAC->mNotificationFrames >> 1));
+ EXPECT_EQ(OK, mAC->getAudioRecordHandle()->setPositionUpdatePeriod(mAC->getMarkerPeriod()))
<< "setPositionUpdatePeriod() failed";
uint32_t marker;
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->getPositionUpdatePeriod(&marker))
<< "getPositionUpdatePeriod() failed";
EXPECT_EQ(OK, mAC->start()) << "start recording failed";
EXPECT_EQ(OK, mAC->audioProcess()) << "audioProcess failed";
- EXPECT_EQ(marker, mAC->mMarkerPeriod) << "configured marker and received marker are different";
- EXPECT_EQ(mAC->mReceivedCbMarkerCount, mAC->mNumFramesToRecord / mAC->mMarkerPeriod)
+ EXPECT_EQ(marker, mAC->getMarkerPeriod())
+ << "configured marker and received marker are different";
+ EXPECT_EQ(mAC->waitAndGetReceivedCbMarkerCount(),
+ mAC->mNumFramesToRecord / mAC->getMarkerPeriod())
<< "configured marker and received cb marker are different";
}
@@ -217,12 +224,12 @@
EXPECT_EQ(mSessionId, mAC->getAudioRecordHandle()->getSessionId());
if (mTransferType != AudioRecord::TRANSFER_CALLBACK) {
uint32_t marker;
- mAC->mMarkerPosition = (mAC->mNotificationFrames << 3) + (mAC->mNotificationFrames >> 1);
+ mAC->setMarkerPosition((mAC->mNotificationFrames << 3) + (mAC->mNotificationFrames >> 1));
EXPECT_EQ(INVALID_OPERATION,
- mAC->getAudioRecordHandle()->setMarkerPosition(mAC->mMarkerPosition));
+ mAC->getAudioRecordHandle()->setMarkerPosition(mAC->getMarkerPosition()));
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->getMarkerPosition(&marker));
EXPECT_EQ(INVALID_OPERATION,
- mAC->getAudioRecordHandle()->setPositionUpdatePeriod(mAC->mMarkerPosition));
+ mAC->getAudioRecordHandle()->setPositionUpdatePeriod(mAC->getMarkerPosition()));
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->getPositionUpdatePeriod(&marker));
}
EXPECT_EQ(OK, mAC->start()) << "start recording failed";
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 3b2285e..8151d39 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -64,16 +64,17 @@
EXPECT_EQ(OK, ap->start()) << "audio track start failed";
EXPECT_EQ(OK, ap->onProcess());
EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
- EXPECT_TRUE(checkPatchPlayback(cb->mAudioIo, cb->mDeviceId));
+ const auto [audioIo, deviceId] = cb->getLastPortAndDevice();
+ EXPECT_TRUE(checkPatchPlayback(audioIo, deviceId));
EXPECT_NE(0, ap->getAudioTrackHandle()->getFlags() & output_flags[i]);
audio_patch patch;
- EXPECT_EQ(OK, getPatchForOutputMix(cb->mAudioIo, patch));
+ EXPECT_EQ(OK, getPatchForOutputMix(audioIo, patch));
if (output_flags[i] != AUDIO_OUTPUT_FLAG_FAST) {
// A "normal" output can still have a FastMixer, depending on the buffer size.
// Thus, a fast track can be created on a mix port which does not have the FAST flag.
for (auto j = 0; j < patch.num_sources; j++) {
if (patch.sources[j].type == AUDIO_PORT_TYPE_MIX &&
- patch.sources[j].ext.mix.handle == cb->mAudioIo) {
+ patch.sources[j].ext.mix.handle == audioIo) {
SCOPED_TRACE(dumpPortConfig(patch.sources[j]));
EXPECT_NE(0, patch.sources[j].flags.output & output_flags[i])
<< "expected output flag "
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index 03c15f4..db998cd 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -108,30 +108,32 @@
// UNIT TESTS
TEST_F(AudioSystemTest, CheckServerSideValues) {
ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
- EXPECT_GT(mAF->sampleRate(mCbPlayback->mAudioIo), 0);
- EXPECT_NE(mAF->format(mCbPlayback->mAudioIo), AUDIO_FORMAT_INVALID);
- EXPECT_GT(mAF->frameCount(mCbPlayback->mAudioIo), 0);
+ const auto [pbAudioIo, _] = mCbPlayback->getLastPortAndDevice();
+ EXPECT_GT(mAF->sampleRate(pbAudioIo), 0);
+ EXPECT_NE(mAF->format(pbAudioIo), AUDIO_FORMAT_INVALID);
+ EXPECT_GT(mAF->frameCount(pbAudioIo), 0);
size_t frameCountHal, frameCountHalCache;
- frameCountHal = mAF->frameCountHAL(mCbPlayback->mAudioIo);
+ frameCountHal = mAF->frameCountHAL(pbAudioIo);
EXPECT_GT(frameCountHal, 0);
- EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(mCbPlayback->mAudioIo, &frameCountHalCache));
+ EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(pbAudioIo, &frameCountHalCache));
EXPECT_EQ(frameCountHal, frameCountHalCache);
- EXPECT_GT(mAF->latency(mCbPlayback->mAudioIo), 0);
+ EXPECT_GT(mAF->latency(pbAudioIo), 0);
// client side latency is at least server side latency
- EXPECT_LE(mAF->latency(mCbPlayback->mAudioIo), mPlayback->getAudioTrackHandle()->latency());
+ EXPECT_LE(mAF->latency(pbAudioIo), mPlayback->getAudioTrackHandle()->latency());
ASSERT_NO_FATAL_FAILURE(createRecordSession());
- EXPECT_GT(mAF->sampleRate(mCbRecord->mAudioIo), 0);
- // EXPECT_NE(mAF->format(mCbRecord->mAudioIo), AUDIO_FORMAT_INVALID);
- EXPECT_GT(mAF->frameCount(mCbRecord->mAudioIo), 0);
- EXPECT_GT(mAF->frameCountHAL(mCbRecord->mAudioIo), 0);
- frameCountHal = mAF->frameCountHAL(mCbRecord->mAudioIo);
+ const auto [recAudioIo, __] = mCbRecord->getLastPortAndDevice();
+ EXPECT_GT(mAF->sampleRate(recAudioIo), 0);
+ // EXPECT_NE(mAF->format(recAudioIo), AUDIO_FORMAT_INVALID);
+ EXPECT_GT(mAF->frameCount(recAudioIo), 0);
+ EXPECT_GT(mAF->frameCountHAL(recAudioIo), 0);
+ frameCountHal = mAF->frameCountHAL(recAudioIo);
EXPECT_GT(frameCountHal, 0);
- EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(mCbRecord->mAudioIo, &frameCountHalCache));
+ EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(recAudioIo, &frameCountHalCache));
EXPECT_EQ(frameCountHal, frameCountHalCache);
- // EXPECT_GT(mAF->latency(mCbRecord->mAudioIo), 0);
+ // EXPECT_GT(mAF->latency(recAudioIo), 0);
// client side latency is at least server side latency
- // EXPECT_LE(mAF->latency(mCbRecord->mAudioIo), mCapture->getAudioRecordHandle()->latency());
+ // EXPECT_LE(mAF->latency(recAudioIo), mCapture->getAudioRecordHandle()->latency());
EXPECT_GT(AudioSystem::getPrimaryOutputSamplingRate(), 0); // first fast mixer sample rate
EXPECT_GT(AudioSystem::getPrimaryOutputFrameCount(), 0); // fast mixer frame count
@@ -200,8 +202,9 @@
TEST_F(AudioSystemTest, GetStreamVolume) {
ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
float origStreamVol;
- EXPECT_EQ(NO_ERROR, AudioSystem::getStreamVolume(AUDIO_STREAM_MUSIC, &origStreamVol,
- mCbPlayback->mAudioIo));
+ const auto [pbAudioIo, _] = mCbPlayback->getLastPortAndDevice();
+ EXPECT_EQ(NO_ERROR,
+ AudioSystem::getStreamVolume(AUDIO_STREAM_MUSIC, &origStreamVol, pbAudioIo));
}
TEST_F(AudioSystemTest, GetStreamMute) {
diff --git a/media/libaudioclient/tests/audiotrack_tests.cpp b/media/libaudioclient/tests/audiotrack_tests.cpp
index cb667a0..cf7d926 100644
--- a/media/libaudioclient/tests/audiotrack_tests.cpp
+++ b/media/libaudioclient/tests/audiotrack_tests.cpp
@@ -157,18 +157,20 @@
EXPECT_EQ(OK, ap->start()) << "audio track start failed";
EXPECT_EQ(OK, ap->onProcess());
EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
- EXPECT_EQ(AUDIO_IO_HANDLE_NONE, cbOld->mAudioIo);
- EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, cbOld->mDeviceId);
- EXPECT_NE(AUDIO_IO_HANDLE_NONE, cb->mAudioIo);
- EXPECT_NE(AUDIO_PORT_HANDLE_NONE, cb->mDeviceId);
- EXPECT_EQ(cb->mAudioIo, ap->getAudioTrackHandle()->getOutput());
- EXPECT_EQ(cb->mDeviceId, ap->getAudioTrackHandle()->getRoutedDeviceId());
+ const auto [oldAudioIo, oldDeviceId] = cbOld->getLastPortAndDevice();
+ EXPECT_EQ(AUDIO_IO_HANDLE_NONE, oldAudioIo);
+ EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, oldDeviceId);
+ const auto [audioIo, deviceId] = cb->getLastPortAndDevice();
+ EXPECT_NE(AUDIO_IO_HANDLE_NONE, audioIo);
+ EXPECT_NE(AUDIO_PORT_HANDLE_NONE, deviceId);
+ EXPECT_EQ(audioIo, ap->getAudioTrackHandle()->getOutput());
+ EXPECT_EQ(deviceId, ap->getAudioTrackHandle()->getRoutedDeviceId());
String8 keys;
keys = ap->getAudioTrackHandle()->getParameters(keys);
if (!keys.empty()) {
std::cerr << "track parameters :: " << keys << std::endl;
}
- EXPECT_TRUE(checkPatchPlayback(cb->mAudioIo, cb->mDeviceId));
+ EXPECT_TRUE(checkPatchPlayback(audioIo, deviceId));
EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->removeAudioDeviceCallback(nullptr));
EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cbOld));
EXPECT_EQ(OK, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cb));
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 64cc7ed..2753906 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -42,6 +42,8 @@
using ::aidl::android::hardware::audio::effect::Descriptor;
using ::aidl::android::hardware::audio::effect::IFactory;
using ::aidl::android::hardware::audio::effect::Processing;
+using ::aidl::android::media::audio::common::AudioDevice;
+using ::aidl::android::media::audio::common::AudioDeviceAddress;
using ::aidl::android::media::audio::common::AudioSource;
using ::aidl::android::media::audio::common::AudioStreamType;
using ::aidl::android::media::audio::common::AudioUuid;
@@ -174,9 +176,6 @@
if (uuid == nullptr || effect == nullptr) {
return BAD_VALUE;
}
- if (sessionId == AUDIO_SESSION_DEVICE && ioId == AUDIO_IO_HANDLE_NONE) {
- return INVALID_OPERATION;
- }
ALOGV("%s session %d ioId %d", __func__, sessionId, ioId);
AudioUuid aidlUuid =
@@ -284,7 +283,8 @@
auto getConfigProcessingWithAidlProcessing =
[&](const auto& aidlProcess, std::vector<effectsConfig::InputStream>& preprocess,
- std::vector<effectsConfig::OutputStream>& postprocess) {
+ std::vector<effectsConfig::OutputStream>& postprocess,
+ std::vector<effectsConfig::DeviceEffects>& deviceprocess) {
if (aidlProcess.type.getTag() == Processing::Type::streamType) {
AudioStreamType aidlType =
aidlProcess.type.template get<Processing::Type::streamType>();
@@ -316,6 +316,25 @@
effectsConfig::InputStream stream = {.type = type.value(),
.effects = std::move(effects)};
preprocess.emplace_back(stream);
+ } else if (aidlProcess.type.getTag() == Processing::Type::device) {
+ AudioDevice aidlDevice =
+ aidlProcess.type.template get<Processing::Type::device>();
+ std::vector<std::shared_ptr<const effectsConfig::Effect>> effects;
+ std::transform(aidlProcess.ids.begin(), aidlProcess.ids.end(),
+ std::back_inserter(effects), getConfigEffectWithDescriptor);
+ audio_devices_t type;
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ status_t status = ::aidl::android::aidl2legacy_AudioDevice_audio_device(
+ aidlDevice, &type, address);
+ if (status != NO_ERROR) {
+ ALOGE("%s device effect has invalid device type / address", __func__);
+ return;
+ }
+ effectsConfig::DeviceEffects device = {
+ {.type = type, .effects = std::move(effects)},
+ .address = address,
+ };
+ deviceprocess.emplace_back(device);
}
};
@@ -323,17 +342,21 @@
[&]() -> std::shared_ptr<const effectsConfig::Processings> {
std::vector<effectsConfig::InputStream> preprocess;
std::vector<effectsConfig::OutputStream> postprocess;
+ std::vector<effectsConfig::DeviceEffects> deviceprocess;
for (const auto& processing : mAidlProcessings) {
- getConfigProcessingWithAidlProcessing(processing, preprocess, postprocess);
+ getConfigProcessingWithAidlProcessing(processing, preprocess, postprocess,
+ deviceprocess);
}
- if (0 == preprocess.size() && 0 == postprocess.size()) {
+ if (0 == preprocess.size() && 0 == postprocess.size() &&
+ 0 == deviceprocess.size()) {
return nullptr;
}
return std::make_shared<const effectsConfig::Processings>(
effectsConfig::Processings({.preprocess = std::move(preprocess),
- .postprocess = std::move(postprocess)}));
+ .postprocess = std::move(postprocess),
+ .deviceprocess = std::move(deviceprocess)}));
}());
return processings;
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index 052522f..a01ac4b 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -929,6 +929,7 @@
!status.isOk()) {
ALOGE("%s: error while resetting port config %d: %s",
__func__, portConfigId, status.getDescription().c_str());
+ return;
}
mPortConfigs.erase(it);
return;
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 2fb4756..030ee2b 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -86,8 +86,8 @@
mStream(stream),
mVendorExt(vext),
mLastReplyLifeTimeNs(
- std::min(static_cast<size_t>(100),
- 2 * mContext.getBufferDurationMs(mConfig.sample_rate))
+ std::min(static_cast<size_t>(20),
+ mContext.getBufferDurationMs(mConfig.sample_rate))
* NANOS_PER_MILLISECOND)
{
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
@@ -449,6 +449,11 @@
state == StreamDescriptor::State::TRANSFER_PAUSED ||
state == StreamDescriptor::State::DRAIN_PAUSED) {
return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
+ } else if (state == StreamDescriptor::State::ACTIVE ||
+ state == StreamDescriptor::State::TRANSFERRING ||
+ state == StreamDescriptor::State::DRAINING) {
+ ALOGD("%s: already in stream state: %s", __func__, toString(state).c_str());
+ return OK;
} else {
ALOGE("%s: unexpected stream state: %s (expected IDLE or one of *PAUSED states)",
__func__, toString(state).c_str());
@@ -795,6 +800,14 @@
}
status_t StreamOutHalAidl::drain(bool earlyNotify) {
+ if (!mStream) return NO_INIT;
+
+ if(const auto state = getState(); state == StreamDescriptor::State::IDLE) {
+ ALOGD("%p %s stream already in IDLE state", this, __func__);
+ if(mContext.isAsynchronous()) onDrainReady();
+ return OK;
+ }
+
return StreamHalAidl::drain(earlyNotify);
}
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 9cb2cff..0587640 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -215,6 +215,11 @@
~StreamHalAidl() override;
+ ::aidl::android::hardware::audio::core::StreamDescriptor::State getState() {
+ std::lock_guard l(mLock);
+ return mLastReply.state;
+ }
+
status_t getLatency(uint32_t *latency);
// Always returns non-negative values.
@@ -268,10 +273,6 @@
result.format = config.format;
return result;
}
- ::aidl::android::hardware::audio::core::StreamDescriptor::State getState() {
- std::lock_guard l(mLock);
- return mLastReply.state;
- }
// Note: Since `sendCommand` takes mLock while holding mCommandReplyLock, never call
// it with `mLock` being held.
status_t sendCommand(
diff --git a/media/libeffects/downmix/aidl/DownmixContext.cpp b/media/libeffects/downmix/aidl/DownmixContext.cpp
index 593e16f..3a55361 100644
--- a/media/libeffects/downmix/aidl/DownmixContext.cpp
+++ b/media/libeffects/downmix/aidl/DownmixContext.cpp
@@ -100,11 +100,6 @@
return RetCode::SUCCESS;
}
-void DownmixContext::reset() {
- disable();
- resetBuffer();
-}
-
IEffect::Status DownmixContext::downmixProcess(float* in, float* out, int samples) {
IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
diff --git a/media/libeffects/downmix/aidl/DownmixContext.h b/media/libeffects/downmix/aidl/DownmixContext.h
index a381d7f..1be1508 100644
--- a/media/libeffects/downmix/aidl/DownmixContext.h
+++ b/media/libeffects/downmix/aidl/DownmixContext.h
@@ -32,9 +32,8 @@
public:
DownmixContext(int statusDepth, const Parameter::Common& common);
~DownmixContext();
- RetCode enable();
- RetCode disable();
- void reset();
+ RetCode enable() override;
+ RetCode disable() override;
RetCode setDmType(Downmix::Type type) {
mType = type;
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.cpp b/media/libeffects/downmix/aidl/EffectDownmix.cpp
index 883d41d..10c7c4f 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.cpp
+++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp
@@ -71,26 +71,6 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus DownmixImpl::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->reset();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
ndk::ScopedAStatus DownmixImpl::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::downmix != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.h b/media/libeffects/downmix/aidl/EffectDownmix.h
index b7d621a..cea6d1b 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.h
+++ b/media/libeffects/downmix/aidl/EffectDownmix.h
@@ -31,7 +31,6 @@
DownmixImpl() = default;
~DownmixImpl() { cleanUp(); }
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
REQUIRES(mImplMutex) override;
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index 836e034..8324473 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -244,27 +244,6 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus DynamicsProcessingImpl::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- return ndk::ScopedAStatus::ok();
- case CommandId::STOP:
- mContext->disable();
- return ndk::ScopedAStatus::ok();
- case CommandId::RESET:
- mContext->disable();
- mContext->resetBuffer();
- return ndk::ScopedAStatus::ok();
- default:
- // Need this default handling for vendor extendable CommandId::VENDOR_COMMAND_*
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
-}
-
bool DynamicsProcessingImpl::isParamInRange(const Parameter::Specific& specific) {
auto& dp = specific.get<Parameter::Specific::dynamicsProcessing>();
return DynamicsProcessingRanges::isParamInRange(dp, kRanges);
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
index e850ba4..b34cdcf 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -36,7 +36,6 @@
ndk::ScopedAStatus open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) override;
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
REQUIRES(mImplMutex) override;
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index ada301b..fd4e615 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -48,10 +48,11 @@
return RetCode::SUCCESS;
}
-void DynamicsProcessingContext::reset() {
+RetCode DynamicsProcessingContext::reset() {
if (mDpFreq != nullptr) {
- mDpFreq.reset();
+ mDpFreq->reset();
}
+ return RetCode::SUCCESS;
}
RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
index ce657db..15c6811 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
@@ -37,9 +37,9 @@
public:
DynamicsProcessingContext(int statusDepth, const Parameter::Common& common);
~DynamicsProcessingContext() = default;
- RetCode enable();
- RetCode disable();
- void reset();
+ RetCode enable() override;
+ RetCode disable() override;
+ RetCode reset() override;
// override EffectContext::setCommon to update mChannelCount
RetCode setCommon(const Parameter::Common& common) override;
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
index b803ee4..55e07fb 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -70,26 +70,6 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus HapticGeneratorImpl::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->reset();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
ndk::ScopedAStatus HapticGeneratorImpl::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
index a775f06..8bae024 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
@@ -30,7 +30,6 @@
HapticGeneratorImpl() = default;
~HapticGeneratorImpl() { cleanUp(); }
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
REQUIRES(mImplMutex) override;
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
index 9b2f443..e040fec 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -71,7 +71,7 @@
return RetCode::SUCCESS;
}
-void HapticGeneratorContext::reset() {
+RetCode HapticGeneratorContext::reset() {
for (auto& filter : mProcessorsRecord.filters) {
filter->clear();
}
@@ -81,6 +81,7 @@
for (auto& distortion : mProcessorsRecord.distortions) {
distortion->clear();
}
+ return RetCode::SUCCESS;
}
RetCode HapticGeneratorContext::setHgHapticScales(
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
index 8a736e3..cf38e47 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
@@ -65,9 +65,9 @@
public:
HapticGeneratorContext(int statusDepth, const Parameter::Common& common);
~HapticGeneratorContext();
- RetCode enable();
- RetCode disable();
- void reset();
+ RetCode enable() override;
+ RetCode disable() override;
+ RetCode reset() override;
RetCode setHgHapticScales(const std::vector<HapticGenerator::HapticScale>& hapticScales);
std::vector<HapticGenerator::HapticScale> getHgHapticScales() const;
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
index f89606e..592fd60 100644
--- a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
@@ -70,27 +70,6 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus LoudnessEnhancerImpl::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->disable();
- mContext->resetBuffer();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
ndk::ScopedAStatus LoudnessEnhancerImpl::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
index 98bdc6b..1e050f3 100644
--- a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
@@ -30,7 +30,6 @@
LoudnessEnhancerImpl() = default;
~LoudnessEnhancerImpl() { cleanUp(); }
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
REQUIRES(mImplMutex) override;
diff --git a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
index d8bcfc0..ac8b14a 100644
--- a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
+++ b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
@@ -43,17 +43,13 @@
return RetCode::SUCCESS;
}
-void LoudnessEnhancerContext::reset() {
- float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification
+RetCode LoudnessEnhancerContext::setLeGain(int gainMb) {
+ float targetAmp = pow(10, gainMb / 2000.0f); // mB to linear amplification
if (mCompressor != nullptr) {
// Get samplingRate from input
mCompressor->Initialize(targetAmp, mCommon.input.base.sampleRate);
}
-}
-
-RetCode LoudnessEnhancerContext::setLeGain(int gainMb) {
mGain = gainMb;
- reset(); // apply parameter update
return RetCode::SUCCESS;
}
diff --git a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
index 192b212..67ccd24 100644
--- a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
+++ b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
@@ -34,9 +34,8 @@
LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common);
~LoudnessEnhancerContext() = default;
- RetCode enable();
- RetCode disable();
- void reset();
+ RetCode enable() override;
+ RetCode disable() override;
RetCode setLeGain(int gainMb);
int getLeGain() const { return mGain; }
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 044c8dd..e5ab40d 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -35,9 +35,9 @@
void deInit();
lvm::BundleEffectType getBundleType() const { return mType; }
- RetCode enable();
+ RetCode enable() override;
RetCode enableOperatingMode();
- RetCode disable();
+ RetCode disable() override;
RetCode disableOperatingMode();
bool isDeviceSupportedBassBoost(
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index 70c276d..2a81673 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -428,27 +428,6 @@
return RetCode::SUCCESS;
}
-ndk::ScopedAStatus EffectBundleAidl::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->disable();
- mContext->resetBuffer();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
// Processing method running in EffectWorker thread.
IEffect::Status EffectBundleAidl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
index 429e941..479579b 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -49,8 +49,6 @@
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
-
std::string getEffectName() override { return *mEffectName; }
private:
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
index 4d369b1..201c659 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -361,27 +361,6 @@
return RetCode::SUCCESS;
}
-ndk::ScopedAStatus EffectReverb::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->disable();
- mContext->resetBuffer();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
// Processing method running in EffectWorker thread.
IEffect::Status EffectReverb::effectProcessImpl(float* in, float* out, int sampleToProcess) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
index e0771a1..4acac1d 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
@@ -42,8 +42,6 @@
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
-
std::string getEffectName() override { return *mEffectName; }
private:
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
index 44391f2..f55eac5 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
@@ -51,8 +51,8 @@
RetCode init();
void deInit();
- RetCode enable();
- RetCode disable();
+ RetCode enable() override;
+ RetCode disable() override;
bool isAuxiliary();
bool isPreset();
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
index 87d267b..4bc34e7 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -417,27 +417,6 @@
return RetCode::SUCCESS;
}
-ndk::ScopedAStatus EffectPreProcessing::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->disable();
- mContext->resetBuffer();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
// Processing method running in EffectWorker thread.
IEffect::Status EffectPreProcessing::effectProcessImpl(float* in, float* out, int sampleToProcess) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
index 9ce5597..31f5737 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
@@ -43,8 +43,6 @@
IEffect::Status effectProcessImpl(float* in, float* out, int samples)
REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
-
std::string getEffectName() override { return *mEffectName; }
private:
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.h b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
index 11a2bea..1b9b77b 100644
--- a/media/libeffects/preprocessing/aidl/PreProcessingContext.h
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
@@ -45,8 +45,8 @@
PreProcessingEffectType getPreProcessingType() const { return mType; }
- RetCode enable();
- RetCode disable();
+ RetCode enable() override;
+ RetCode disable() override;
RetCode setCommon(const Parameter::Common& common) override;
void updateConfigs(const Parameter::Common& common);
diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp
index 9b493d4..f4b9b25 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.cpp
+++ b/media/libeffects/visualizer/aidl/Visualizer.cpp
@@ -85,27 +85,6 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus VisualizerImpl::commandImpl(CommandId command) {
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- switch (command) {
- case CommandId::START:
- mContext->enable();
- break;
- case CommandId::STOP:
- mContext->disable();
- break;
- case CommandId::RESET:
- mContext->disable();
- mContext->resetBuffer();
- break;
- default:
- LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
- return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
- "commandIdNotSupported");
- }
- return ndk::ScopedAStatus::ok();
-}
-
ndk::ScopedAStatus VisualizerImpl::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
@@ -222,6 +201,7 @@
RetCode VisualizerImpl::releaseContext() {
if (mContext) {
mContext->disable();
+ mContext->reset();
mContext->resetBuffer();
}
return RetCode::SUCCESS;
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
index 3180972..f25b78d 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.h
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -32,7 +32,6 @@
VisualizerImpl() = default;
~VisualizerImpl() { cleanUp(); }
- ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
REQUIRES(mImplMutex) override;
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.cpp b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
index 1e08674..a368e52 100644
--- a/media/libeffects/visualizer/aidl/VisualizerContext.cpp
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
@@ -57,7 +57,7 @@
#endif
mChannelCount = channelCount;
mCommon = common;
- std::fill(mCaptureBuf.begin(), mCaptureBuf.end(), 0x80);
+ reset();
return RetCode::SUCCESS;
}
@@ -77,8 +77,9 @@
return RetCode::SUCCESS;
}
-void VisualizerContext::reset() {
+RetCode VisualizerContext::reset() {
std::fill(mCaptureBuf.begin(), mCaptureBuf.end(), 0x80);
+ return RetCode::SUCCESS;
}
RetCode VisualizerContext::setCaptureSamples(int samples) {
@@ -109,7 +110,6 @@
mDownstreamLatency = latency;
return RetCode::SUCCESS;
}
-
int VisualizerContext::getDownstreamLatency() {
return mDownstreamLatency;
}
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.h b/media/libeffects/visualizer/aidl/VisualizerContext.h
index 9715e20..d4abbd3 100644
--- a/media/libeffects/visualizer/aidl/VisualizerContext.h
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.h
@@ -36,10 +36,10 @@
RetCode initParams(const Parameter::Common& common);
- RetCode enable();
- RetCode disable();
+ RetCode enable() override;
+ RetCode disable() override;
// keep all parameters and reset buffer.
- void reset();
+ RetCode reset() override;
RetCode setCaptureSamples(int32_t captureSize);
int32_t getCaptureSamples();
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9cd0e6e..8a962c6 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -255,6 +255,45 @@
}
cc_library_shared {
+ name: "libmedia_codeclist_capabilities",
+
+ srcs: [
+ "AudioCapabilities.cpp",
+ "CodecCapabilities.cpp",
+ "CodecCapabilitiesUtils.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
+cc_library_shared {
name: "libmedia_codeclist",
srcs: [
@@ -270,6 +309,7 @@
"android.hardware.media.omx@1.0",
"libbinder",
"liblog",
+ "libmedia_codeclist_capabilities",
"libstagefright_foundation",
"libutils",
],
@@ -278,10 +318,6 @@
"android.media.codec-aconfig-cc",
],
- include_dirs: [
- "system/libhidl/transport/token/1.0/utils/include",
- ],
-
export_include_dirs: [
"include",
],
@@ -364,7 +400,6 @@
"av-types-aidl-cpp",
"liblog",
"libcutils",
- "libprocessgroup",
"libutils",
"libbinder",
"libbinder_ndk",
diff --git a/media/libmedia/AudioCapabilities.cpp b/media/libmedia/AudioCapabilities.cpp
new file mode 100644
index 0000000..e8cf517
--- /dev/null
+++ b/media/libmedia/AudioCapabilities.cpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2024, 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioCapabilities"
+
+#include <android-base/strings.h>
+#include <android-base/properties.h>
+
+#include <media/AudioCapabilities.h>
+#include <media/CodecCapabilities.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+namespace android {
+
+const Range<int>& AudioCapabilities::getBitrateRange() const {
+ return mBitrateRange;
+}
+
+const std::vector<int>& AudioCapabilities::getSupportedSampleRates() const {
+ return mSampleRates;
+}
+
+const std::vector<Range<int>>&
+ AudioCapabilities::getSupportedSampleRateRanges() const {
+ return mSampleRateRanges;
+}
+
+int AudioCapabilities::getMaxInputChannelCount() const {
+ int overallMax = 0;
+ for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) {
+ int lmax = mInputChannelRanges[i].upper();
+ if (lmax > overallMax) {
+ overallMax = lmax;
+ }
+ }
+ return overallMax;
+}
+
+int AudioCapabilities::getMinInputChannelCount() const {
+ int overallMin = MAX_INPUT_CHANNEL_COUNT;
+ for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) {
+ int lmin = mInputChannelRanges[i].lower();
+ if (lmin < overallMin) {
+ overallMin = lmin;
+ }
+ }
+ return overallMin;
+}
+
+const std::vector<Range<int>>&
+ AudioCapabilities::getInputChannelCountRanges() const {
+ return mInputChannelRanges;
+}
+
+// static
+std::shared_ptr<AudioCapabilities> AudioCapabilities::Create(std::string mediaType,
+ std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
+ std::shared_ptr<AudioCapabilities> caps(new AudioCapabilities());
+ caps->init(mediaType, profLevs, format);
+ return caps;
+}
+
+void AudioCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+ const sp<AMessage> &format) {
+ mMediaType = mediaType;
+ mProfileLevels = profLevs;
+ mError = 0;
+
+ initWithPlatformLimits();
+ applyLevelLimits();
+ parseFromInfo(format);
+}
+
+void AudioCapabilities::initWithPlatformLimits() {
+ mBitrateRange = Range<int>(0, INT_MAX);
+ mInputChannelRanges.push_back(Range<int>(1, MAX_INPUT_CHANNEL_COUNT));
+
+ const int minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350);
+ const int maxSampleRate = base::GetIntProperty("ro.mediacodec.max_sample_rate", 192000);
+ mSampleRateRanges.push_back(Range<int>(minSampleRate, maxSampleRate));
+}
+
+bool AudioCapabilities::supports(int sampleRate, int inputChannels) {
+ // channels and sample rates are checked orthogonally
+ if (inputChannels != 0
+ && !std::any_of(mInputChannelRanges.begin(), mInputChannelRanges.end(),
+ [inputChannels](const Range<int> &a) { return a.contains(inputChannels); })) {
+ return false;
+ }
+ if (sampleRate != 0
+ && !std::any_of(mSampleRateRanges.begin(), mSampleRateRanges.end(),
+ [sampleRate](const Range<int> &a) { return a.contains(sampleRate); })) {
+ return false;
+ }
+ return true;
+}
+
+bool AudioCapabilities::isSampleRateSupported(int sampleRate) {
+ return supports(sampleRate, 0);
+}
+
+void AudioCapabilities::limitSampleRates(std::vector<int> rates) {
+ std::vector<Range<int>> sampleRateRanges;
+ std::sort(rates.begin(), rates.end());
+ for (int rate : rates) {
+ if (supports(rate, 0 /* channels */)) {
+ sampleRateRanges.push_back(Range<int>(rate, rate));
+ }
+ }
+ mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, sampleRateRanges);
+ createDiscreteSampleRates();
+}
+
+void AudioCapabilities::createDiscreteSampleRates() {
+ mSampleRates.clear();
+ for (int i = 0; i < mSampleRateRanges.size(); i++) {
+ mSampleRates.push_back(mSampleRateRanges[i].lower());
+ }
+}
+
+void AudioCapabilities::limitSampleRates(std::vector<Range<int>> rateRanges) {
+ sortDistinctRanges(&rateRanges);
+ mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
+ // check if all values are discrete
+ for (Range<int> range: mSampleRateRanges) {
+ if (range.lower() != range.upper()) {
+ mSampleRates.clear();
+ return;
+ }
+ }
+ createDiscreteSampleRates();
+}
+
+void AudioCapabilities::applyLevelLimits() {
+ std::vector<int> sampleRates;
+ std::optional<Range<int>> sampleRateRange;
+ std::optional<Range<int>> bitRates;
+ int maxChannels = MAX_INPUT_CHANNEL_COUNT;
+
+ // const char *mediaType = mMediaType.c_str();
+ if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MPEG)) {
+ sampleRates = {
+ 8000, 11025, 12000,
+ 16000, 22050, 24000,
+ 32000, 44100, 48000 };
+ bitRates = Range<int>(8000, 320000);
+ maxChannels = 2;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)) {
+ sampleRates = { 8000 };
+ bitRates = Range<int>(4750, 12200);
+ maxChannels = 1;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)) {
+ sampleRates = { 16000 };
+ bitRates = Range<int>(6600, 23850);
+ maxChannels = 1;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
+ sampleRates = {
+ 7350, 8000,
+ 11025, 12000, 16000,
+ 22050, 24000, 32000,
+ 44100, 48000, 64000,
+ 88200, 96000 };
+ bitRates = Range<int>(8000, 510000);
+ maxChannels = 48;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_VORBIS)) {
+ bitRates = Range<int>(32000, 500000);
+ sampleRateRange = Range<int>(8000, 192000);
+ maxChannels = 255;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_OPUS)) {
+ bitRates = Range<int>(6000, 510000);
+ sampleRates = { 8000, 12000, 16000, 24000, 48000 };
+ maxChannels = 255;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_RAW)) {
+ sampleRateRange = Range<int>(1, 192000);
+ bitRates = Range<int>(1, 10000000);
+ maxChannels = MAX_NUM_CHANNELS;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
+ sampleRateRange = Range<int>(1, 655350);
+ // lossless codec, so bitrate is ignored
+ maxChannels = 255;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
+ || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)) {
+ sampleRates = { 8000 };
+ bitRates = Range<int>(64000, 64000);
+ // platform allows multiple channels for this format
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
+ sampleRates = { 8000 };
+ bitRates = Range<int>(13000, 13000);
+ maxChannels = 1;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC3)) {
+ maxChannels = 6;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_EAC3)) {
+ maxChannels = 16;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_EAC3_JOC)) {
+ sampleRates = { 48000 };
+ bitRates = Range<int>(32000, 6144000);
+ maxChannels = 16;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC4)) {
+ sampleRates = { 44100, 48000, 96000, 192000 };
+ bitRates = Range<int>(16000, 2688000);
+ maxChannels = 24;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)) {
+ sampleRates = { 44100, 48000 };
+ bitRates = Range<int>(96000, 1524000);
+ maxChannels = 6;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD)) {
+ for (ProfileLevel profileLevel: mProfileLevels) {
+ switch (profileLevel.mProfile) {
+ case DTS_HDProfileLBR:
+ sampleRates = { 22050, 24000, 44100, 48000 };
+ bitRates = Range<int>(32000, 768000);
+ break;
+ case DTS_HDProfileHRA:
+ case DTS_HDProfileMA:
+ sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
+ bitRates = Range<int>(96000, 24500000);
+ break;
+ default:
+ ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile,
+ mMediaType.c_str());
+ mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
+ sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
+ bitRates = Range<int>(96000, 24500000);
+ }
+ }
+ maxChannels = 8;
+ } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_UHD)) {
+ for (ProfileLevel profileLevel: mProfileLevels) {
+ switch (profileLevel.mProfile) {
+ case DTS_UHDProfileP2:
+ sampleRates = { 48000 };
+ bitRates = Range<int>(96000, 768000);
+ maxChannels = 10;
+ break;
+ case DTS_UHDProfileP1:
+ sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
+ bitRates = Range<int>(96000, 24500000);
+ maxChannels = 32;
+ break;
+ default:
+ ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile,
+ mMediaType.c_str());
+ mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
+ sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
+ bitRates = Range<int>(96000, 24500000);
+ maxChannels = 32;
+ }
+ }
+ } else {
+ ALOGW("Unsupported mediaType %s", mMediaType.c_str());
+ mError |= ERROR_CAPABILITIES_UNSUPPORTED;
+ }
+
+ // restrict ranges
+ if (!sampleRates.empty()) {
+ limitSampleRates(sampleRates);
+ } else if (sampleRateRange) {
+ std::vector<Range<int>> rateRanges = { sampleRateRange.value() };
+ limitSampleRates(rateRanges);
+ }
+
+ Range<int> channelRange = Range<int>(1, maxChannels);
+ std::vector<Range<int>> inputChannels = { channelRange };
+ applyLimits(inputChannels, bitRates);
+}
+
+void AudioCapabilities::applyLimits(
+ const std::vector<Range<int>> &inputChannels,
+ const std::optional<Range<int>> &bitRates) {
+ // clamp & make a local copy
+ std::vector<Range<int>> inputChannelsCopy(inputChannels.size());
+ for (int i = 0; i < inputChannels.size(); i++) {
+ int lower = inputChannels[i].clamp(1);
+ int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
+ inputChannelsCopy[i] = Range<int>(lower, upper);
+ }
+
+ // sort, intersect with existing, & save channel list
+ sortDistinctRanges(&inputChannelsCopy);
+ mInputChannelRanges = intersectSortedDistinctRanges(inputChannelsCopy, mInputChannelRanges);
+
+ if (bitRates) {
+ mBitrateRange = mBitrateRange.intersect(bitRates.value());
+ }
+}
+
+void AudioCapabilities::parseFromInfo(const sp<AMessage> &format) {
+ int maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
+ std::vector<Range<int>> channels = { Range<int>(1, maxInputChannels) };
+ std::optional<Range<int>> bitRates = POSITIVE_INTEGERS;
+
+ AString rateAString;
+ if (format->findString("sample-rate-ranges", &rateAString)) {
+ std::vector<std::string> rateStrings = base::Split(std::string(rateAString.c_str()), ",");
+ std::vector<Range<int>> rateRanges;
+ for (std::string rateString : rateStrings) {
+ std::optional<Range<int>> rateRange = ParseIntRange(rateString);
+ if (!rateRange) {
+ continue;
+ }
+ rateRanges.push_back(rateRange.value());
+ }
+ limitSampleRates(rateRanges);
+ }
+
+ // we will prefer channel-ranges over max-channel-count
+ AString valueStr;
+ if (format->findString("channel-ranges", &valueStr)) {
+ std::vector<std::string> channelStrings = base::Split(std::string(valueStr.c_str()), ",");
+ std::vector<Range<int>> channelRanges;
+ for (std::string channelString : channelStrings) {
+ std::optional<Range<int>> channelRange = ParseIntRange(channelString);
+ if (!channelRange) {
+ continue;
+ }
+ channelRanges.push_back(channelRange.value());
+ }
+ channels = channelRanges;
+ } else if (format->findString("channel-range", &valueStr)) {
+ std::optional<Range<int>> oneRange = ParseIntRange(std::string(valueStr.c_str()));
+ if (oneRange) {
+ channels = { oneRange.value() };
+ }
+ } else if (format->findString("max-channel-count", &valueStr)) {
+ maxInputChannels = std::atoi(valueStr.c_str());
+ if (maxInputChannels == 0) {
+ channels = { Range<int>(0, 0) };
+ } else {
+ channels = { Range<int>(1, maxInputChannels) };
+ }
+ } else if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) {
+ maxInputChannels = 0;
+ channels = { Range<int>(0, 0) };
+ }
+
+ if (format->findString("bitrate-range", &valueStr)) {
+ std::optional<Range<int>> parsedBitrate = ParseIntRange(valueStr.c_str());
+ if (parsedBitrate) {
+ bitRates = bitRates.value().intersect(parsedBitrate.value());
+ }
+ }
+
+ applyLimits(channels, bitRates);
+}
+
+void AudioCapabilities::getDefaultFormat(sp<AMessage> &format) {
+ // report settings that have only a single choice
+ if (mBitrateRange.lower() == mBitrateRange.upper()) {
+ format->setInt32(KEY_BIT_RATE, mBitrateRange.lower());
+ }
+ if (getMaxInputChannelCount() == 1) {
+ // mono-only format
+ format->setInt32(KEY_CHANNEL_COUNT, 1);
+ }
+ if (!mSampleRates.empty() && mSampleRates.size() == 1) {
+ format->setInt32(KEY_SAMPLE_RATE, mSampleRates[0]);
+ }
+}
+
+bool AudioCapabilities::supportsFormat(const sp<AMessage> &format) {
+ int32_t sampleRate;
+ format->findInt32(KEY_SAMPLE_RATE, &sampleRate);
+ int32_t channels;
+ format->findInt32(KEY_CHANNEL_COUNT, &channels);
+
+ if (!supports(sampleRate, channels)) {
+ return false;
+ }
+
+ if (!CodecCapabilities::SupportsBitrate(mBitrateRange, format)) {
+ return false;
+ }
+
+ // nothing to do for:
+ // KEY_CHANNEL_MASK: codecs don't get this
+ // KEY_IS_ADTS: required feature for all AAC decoders
+ return true;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libmedia/CodecCapabilities.cpp b/media/libmedia/CodecCapabilities.cpp
new file mode 100644
index 0000000..5bed1c4
--- /dev/null
+++ b/media/libmedia/CodecCapabilities.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024, 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CodecCapabilities"
+
+#include <utils/Log.h>
+#include <media/CodecCapabilities.h>
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+bool CodecCapabilities::SupportsBitrate(Range<int> bitrateRange,
+ const sp<AMessage> &format) {
+ // consider max bitrate over average bitrate for support
+ int32_t maxBitrate = 0;
+ format->findInt32(KEY_MAX_BIT_RATE, &maxBitrate);
+ int32_t bitrate = 0;
+ format->findInt32(KEY_BIT_RATE, &bitrate);
+
+ if (bitrate == 0) {
+ bitrate = maxBitrate;
+ } else if (maxBitrate != 0) {
+ bitrate = std::max(bitrate, maxBitrate);
+ }
+
+ if (bitrate > 0) {
+ return bitrateRange.contains(bitrate);
+ }
+
+ return true;
+}
+
+const std::string& CodecCapabilities::getMediaType() {
+ return mMediaType;
+}
+
+const std::vector<ProfileLevel>& CodecCapabilities::getProfileLevels() {
+ return mProfileLevels;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libmedia/CodecCapabilitiesUtils.cpp b/media/libmedia/CodecCapabilitiesUtils.cpp
new file mode 100644
index 0000000..edfc9be
--- /dev/null
+++ b/media/libmedia/CodecCapabilitiesUtils.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CodecCapabilitiesUtils"
+#include <utils/Log.h>
+
+#include <algorithm>
+#include <cmath>
+#include <regex>
+#include <string>
+#include <vector>
+
+#include <media/CodecCapabilitiesUtils.h>
+
+#include <media/stagefright/foundation/AUtils.h>
+
+namespace android {
+
+std::optional<Range<int>> ParseIntRange(const std::string &str) {
+ if (str.empty()) {
+ ALOGW("could not parse empty integer range");
+ return std::nullopt;
+ }
+ int lower, upper;
+ std::regex regex("([0-9]+)-([0-9]+)");
+ std::smatch match;
+ if (std::regex_match(str, match, regex)) {
+ lower = std::atoi(match[1].str().c_str());
+ upper = std::atoi(match[2].str().c_str());
+ } else if (std::atoi(str.c_str()) != 0) {
+ lower = upper = std::atoi(str.c_str());
+ } else {
+ ALOGW("could not parse integer range: %s", str.c_str());
+ return std::nullopt;
+ }
+ return std::make_optional<Range<int>>(lower, upper);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index cdb1837..ef6250f 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -23,7 +23,6 @@
#include <binder/Parcel.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaMetadataRetriever.h>
-#include <processgroup/sched_policy.h>
#include <utils/String8.h>
#include <utils/KeyedVector.h>
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index c45c5c3..d5d1a09 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -18,8 +18,6 @@
#define LOG_TAG "MediaCodecInfo"
#include <utils/Log.h>
-#include <media/IOMX.h>
-
#include <media/MediaCodecInfo.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libmedia/include/media/AudioCapabilities.h b/media/libmedia/include/media/AudioCapabilities.h
new file mode 100644
index 0000000..2bc3335
--- /dev/null
+++ b/media/libmedia/include/media/AudioCapabilities.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2024, 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 AUDIO_CAPABILITIES_H_
+
+#define AUDIO_CAPABILITIES_H_
+
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <system/audio.h>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct AudioCapabilities {
+ /**
+ * Create AudioCapabilities.
+ */
+ static std::shared_ptr<AudioCapabilities> Create(std::string mediaType,
+ std::vector<ProfileLevel> profLevs, const sp<AMessage> &format);
+
+ /**
+ * Returns the range of supported bitrates in bits/second.
+ */
+ const Range<int>& getBitrateRange() const;
+
+ /**
+ * Returns the array of supported sample rates if the codec
+ * supports only discrete values. Otherwise, it returns an empty array.
+ * The array is sorted in ascending order.
+ */
+ const std::vector<int>& getSupportedSampleRates() const;
+
+ /**
+ * Returns the array of supported sample rate ranges. The
+ * array is sorted in ascending order, and the ranges are
+ * distinct.
+ */
+ const std::vector<Range<int>>& getSupportedSampleRateRanges() const;
+
+ /**
+ * Returns the maximum number of input channels supported.
+ * The returned value should be between 1 and 255.
+ *
+ * Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support
+ * for any number of input channels between 1 and this maximum value.
+ *
+ * As of {@link android.os.Build.VERSION_CODES#S},
+ * the implied lower limit of 1 channel is no longer valid.
+ * As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is
+ * superseded by {@link #getInputChannelCountRanges},
+ * which returns an array of ranges of channels.
+ * The {@link #getMaxInputChannelCount} method will return the highest value
+ * in the ranges returned by {@link #getInputChannelCountRanges}
+ */
+ int getMaxInputChannelCount() const;
+
+ /**
+ * Returns the minimum number of input channels supported.
+ * This is often 1, but does vary for certain mime types.
+ *
+ * This returns the lowest channel count in the ranges returned by
+ * {@link #getInputChannelCountRanges}.
+ */
+ int getMinInputChannelCount() const;
+
+ /**
+ * Returns an array of ranges representing the number of input channels supported.
+ * The codec supports any number of input channels within this range.
+ *
+ * This supersedes the {@link #getMaxInputChannelCount} method.
+ *
+ * For many codecs, this will be a single range [1..N], for some N.
+ *
+ * The returned array cannot be empty.
+ */
+ const std::vector<Range<int>>& getInputChannelCountRanges() const;
+
+ /**
+ * Query whether the sample rate is supported by the codec.
+ */
+ bool isSampleRateSupported(int sampleRate);
+
+ /* For internal use only. Not exposed as a public API */
+ void getDefaultFormat(sp<AMessage> &format);
+
+ /* For internal use only. Not exposed as a public API */
+ bool supportsFormat(const sp<AMessage> &format);
+
+private:
+ static constexpr int MAX_INPUT_CHANNEL_COUNT = 30;
+ static constexpr uint32_t MAX_NUM_CHANNELS = FCC_LIMIT;
+
+ int mError;
+ std::string mMediaType;
+ std::vector<ProfileLevel> mProfileLevels;
+
+ Range<int> mBitrateRange;
+
+ std::vector<int> mSampleRates;
+ std::vector<Range<int>> mSampleRateRanges;
+ std::vector<Range<int>> mInputChannelRanges;
+
+ /* no public constructor */
+ AudioCapabilities() {}
+ void init(std::string mediaType, std::vector<ProfileLevel> profLevs,
+ const sp<AMessage> &format);
+ void initWithPlatformLimits();
+ bool supports(int sampleRate, int inputChannels);
+ void limitSampleRates(std::vector<int> rates);
+ void createDiscreteSampleRates();
+ void limitSampleRates(std::vector<Range<int>> rateRanges);
+ void applyLevelLimits();
+ void applyLimits(const std::vector<Range<int>> &inputChannels,
+ const std::optional<Range<int>> &bitRates);
+ void parseFromInfo(const sp<AMessage> &format);
+
+ friend struct CodecCapabilities;
+};
+
+} // namespace android
+
+#endif // AUDIO_CAPABILITIES_H_
\ No newline at end of file
diff --git a/media/libmedia/include/media/CodecCapabilities.h b/media/libmedia/include/media/CodecCapabilities.h
new file mode 100644
index 0000000..9d1c4ea
--- /dev/null
+++ b/media/libmedia/include/media/CodecCapabilities.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2024, 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 CODEC_CAPABILITIES_H_
+
+#define CODEC_CAPABILITIES_H_
+
+#include <media/AudioCapabilities.h>
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+struct CodecCapabilities {
+
+ static bool SupportsBitrate(Range<int> bitrateRange,
+ const sp<AMessage> &format);
+
+ /**
+ * Returns the media type for which this codec-capability object was created.
+ */
+ const std::string& getMediaType();
+
+ /**
+ * Returns the supported profile levels.
+ */
+ const std::vector<ProfileLevel>& getProfileLevels();
+
+private:
+ std::string mMediaType;
+ std::vector<ProfileLevel> mProfileLevels;
+
+ std::shared_ptr<AudioCapabilities> mAudioCaps;
+};
+
+} // namespace android
+
+#endif // CODEC_CAPABILITIES_H_
\ No newline at end of file
diff --git a/media/libmedia/include/media/CodecCapabilitiesUtils.h b/media/libmedia/include/media/CodecCapabilitiesUtils.h
new file mode 100644
index 0000000..2bf822a
--- /dev/null
+++ b/media/libmedia/include/media/CodecCapabilitiesUtils.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2024 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 CODEC_CAPABILITIES__UTILS_H_
+
+#define CODEC_CAPABILITIES__UTILS_H_
+
+#include <algorithm>
+#include <cmath>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/AUtils.h>
+
+namespace android {
+
+struct ProfileLevel {
+ uint32_t mProfile;
+ uint32_t mLevel;
+ bool operator <(const ProfileLevel &o) const {
+ return mProfile < o.mProfile || (mProfile == o.mProfile && mLevel < o.mLevel);
+ }
+};
+
+/**
+ * Immutable class for describing the range of two numeric values.
+ *
+ * To make it immutable, all data are private and all functions are const.
+ *
+ * From frameworks/base/core/java/android/util/Range.java
+ */
+template<typename T>
+struct Range {
+ Range() : lower_(), upper_() {}
+
+ Range(T l, T u) : lower_(l), upper_(u) {}
+
+ constexpr bool empty() const { return lower_ > upper_; }
+
+ T lower() const { return lower_; }
+
+ T upper() const { return upper_; }
+
+ // Check if a value is in the range.
+ bool contains(T value) const {
+ return lower_ <= value && upper_ >= value;
+ }
+
+ bool contains(Range<T> range) const {
+ return (range.lower_ >= lower_) && (range.upper_ <= upper_);
+ }
+
+ // Clamp a value in the range
+ T clamp(T value) const{
+ if (value < lower_) {
+ return lower_;
+ } else if (value > upper_) {
+ return upper_;
+ } else {
+ return value;
+ }
+ }
+
+ // Return the intersected range
+ Range<T> intersect(Range<T> range) const {
+ if (lower_ >= range.lower() && range.upper() >= upper_) {
+ // range includes this
+ return *this;
+ } else if (range.lower() >= lower_ && range.upper() <= upper_) {
+ // this includes range
+ return range;
+ } else {
+ // if ranges are disjoint returns an empty Range(lower > upper)
+ Range<T> result = Range<T>(std::max(lower_, range.lower_),
+ std::min(upper_, range.upper_));
+ if (result.empty()) {
+ ALOGE("Failed to intersect 2 ranges as they are disjoint");
+ }
+ return result;
+ }
+ }
+
+ /**
+ * Returns the intersection of this range and the inclusive range
+ * specified by {@code [lower, upper]}.
+ * <p>
+ * See {@link #intersect(Range)} for more details.</p>
+ *
+ * @param lower a non-{@code null} {@code T} reference
+ * @param upper a non-{@code null} {@code T} reference
+ * @return the intersection of this range and the other range
+ *
+ * @throws NullPointerException if {@code lower} or {@code upper} was {@code null}
+ * @throws IllegalArgumentException if the ranges are disjoint.
+ */
+ Range<T> intersect(T lower, T upper) {
+ return Range(std::max(lower_, lower), std::min(upper_, upper));
+ }
+
+private:
+ T lower_;
+ T upper_;
+};
+
+static const Range<int> POSITIVE_INTEGERS = Range<int>(1, INT_MAX);
+
+// found stuff that is not supported by framework (=> this should not happen)
+constexpr int ERROR_CAPABILITIES_UNRECOGNIZED = (1 << 0);
+// found profile/level for which we don't have capability estimates
+constexpr int ERROR_CAPABILITIES_UNSUPPORTED = (1 << 1);
+// have not found any profile/level for which we don't have capability estimate
+// constexpr int ERROR_NONE_SUPPORTED = (1 << 2);
+
+/**
+ * Sorts distinct (non-intersecting) range array in ascending order.
+ * From frameworks/base/media/java/android/media/Utils.java
+ */
+template<typename T>
+void sortDistinctRanges(std::vector<Range<T>> *ranges) {
+ std::sort(ranges->begin(), ranges->end(),
+ [](Range<T> r1, Range<T> r2) {
+ if (r1.upper() < r2.lower()) {
+ return true;
+ } else if (r1.lower() > r2.upper()) {
+ return false;
+ } else {
+ ALOGE("sample rate ranges must be distinct.");
+ return false;
+ }
+ });
+}
+
+/**
+ * Returns the intersection of two sets of non-intersecting ranges
+ * From frameworks/base/media/java/android/media/Utils.java
+ * @param one a sorted set of non-intersecting ranges in ascending order
+ * @param another another sorted set of non-intersecting ranges in ascending order
+ * @return the intersection of the two sets, sorted in ascending order
+ */
+template<typename T>
+std::vector<Range<T>> intersectSortedDistinctRanges(
+ const std::vector<Range<T>> &one, const std::vector<Range<T>> &another) {
+ std::vector<Range<T>> result;
+ int ix = 0;
+ for (Range<T> range : another) {
+ while (ix < one.size() && one[ix].upper() < range.lower()) {
+ ++ix;
+ }
+ while (ix < one.size() && one[ix].upper() < range.upper()) {
+ result.push_back(range.intersect(one[ix]));
+ ++ix;
+ }
+ if (ix == one.size()) {
+ break;
+ }
+ if (one[ix].lower() <= range.upper()) {
+ result.push_back(range.intersect(one[ix]));
+ }
+ }
+ return result;
+}
+
+// parse string into int range
+std::optional<Range<int>> ParseIntRange(const std::string &str);
+
+} // namespace android
+
+#endif // CODEC_CAPABILITIES__UTILS_H_
\ No newline at end of file
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index 88a2dc4..72aca98 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -20,6 +20,8 @@
#include <android-base/macros.h>
#include <binder/Parcel.h>
+#include <media/CodecCapabilities.h>
+#include <media/CodecCapabilitiesUtils.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AString.h>
@@ -43,13 +45,10 @@
struct MediaCodecListWriter;
struct MediaCodecInfo : public RefBase {
- struct ProfileLevel {
- uint32_t mProfile;
- uint32_t mLevel;
- bool operator <(const ProfileLevel &o) const {
- return mProfile < o.mProfile || (mProfile == o.mProfile && mLevel < o.mLevel);
- }
- };
+
+ // Moved to CodecCapabilitiesUtils.h
+ // Map MediaCodecInfo::ProfileLevel to android::ProfileLevel to maintain compatibility.
+ typedef ::android::ProfileLevel ProfileLevel;
struct CapabilitiesWriter;
diff --git a/media/libmedia/tests/codeccapabilities/Android.bp b/media/libmedia/tests/codeccapabilities/Android.bp
new file mode 100644
index 0000000..79eb71a
--- /dev/null
+++ b/media/libmedia/tests/codeccapabilities/Android.bp
@@ -0,0 +1,36 @@
+cc_test {
+ name: "CodecCapabilitiesTest",
+ team: "trendy_team_media_codec_framework",
+
+ test_suites: [
+ "general-tests",
+ ],
+ gtest: true,
+
+ srcs: [
+ "CodecCapabilitiesTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmedia_codeclist", // available >= R
+ "libmedia_codeclist_capabilities",
+ "libstagefright",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
new file mode 100644
index 0000000..89c9739
--- /dev/null
+++ b/media/libmedia/tests/codeccapabilities/CodecCapabilitiesTest.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CodecCapabilitiesTest"
+
+#include <utils/Log.h>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <media/CodecCapabilities.h>
+#include <media/CodecCapabilitiesUtils.h>
+#include <media/MediaCodecInfo.h>
+
+#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+
+using namespace android;
+
+class AudioCapsAacTest : public testing::Test {
+protected:
+ AudioCapsAacTest() {
+ std::string mediaType = MIMETYPE_AUDIO_AAC;
+
+ sp<AMessage> details = new AMessage;
+ details->setString("bitrate-range", "8000-960000");
+ details->setString("max-channel-count", "8");
+ details->setString("sample-rate-ranges",
+ "7350,8000,11025,12000,16000,22050,24000,32000,44100,48000");
+
+ std::vector<ProfileLevel> profileLevel{
+ ProfileLevel(2, 0),
+ ProfileLevel(5, 0),
+ ProfileLevel(29, 0),
+ ProfileLevel(23, 0),
+ ProfileLevel(39, 0),
+ ProfileLevel(20, 0),
+ ProfileLevel(42, 0),
+ };
+
+ audioCaps = AudioCapabilities::Create(mediaType, profileLevel, details);
+ }
+
+ std::shared_ptr<AudioCapabilities> audioCaps;
+};
+
+TEST_F(AudioCapsAacTest, AudioCaps_Aac_Bitrate) {
+ const Range<int>& bitrateRange = audioCaps->getBitrateRange();
+ EXPECT_EQ(bitrateRange.lower(), 8000) << "bitrate range1 does not match. lower: "
+ << bitrateRange.lower();
+ EXPECT_EQ(bitrateRange.upper(), 510000) << "bitrate range1 does not match. upper: "
+ << bitrateRange.upper();
+}
+
+TEST_F(AudioCapsAacTest, AudioCaps_Aac_InputChannelCount) {
+ int maxInputChannelCount = audioCaps->getMaxInputChannelCount();
+ EXPECT_EQ(maxInputChannelCount, 8);
+ int minInputChannelCount = audioCaps->getMinInputChannelCount();
+ EXPECT_EQ(minInputChannelCount, 1);
+}
+
+TEST_F(AudioCapsAacTest, AudioCaps_Aac_SupportedSampleRates) {
+ const std::vector<int>& sampleRates = audioCaps->getSupportedSampleRates();
+ EXPECT_EQ(sampleRates, std::vector<int>({7350, 8000, 11025, 12000, 16000, 22050,
+ 24000, 32000, 44100, 48000}));
+
+ EXPECT_FALSE(audioCaps->isSampleRateSupported(6000))
+ << "isSampleRateSupported returned true for unsupported sample rate";
+ EXPECT_TRUE(audioCaps->isSampleRateSupported(8000))
+ << "isSampleRateSupported returned false for supported sample rate";
+ EXPECT_TRUE(audioCaps->isSampleRateSupported(12000))
+ << "isSampleRateSupported returned false for supported sample rate";
+ EXPECT_FALSE(audioCaps->isSampleRateSupported(44000))
+ << "isSampleRateSupported returned true for unsupported sample rate";
+ EXPECT_TRUE(audioCaps->isSampleRateSupported(48000))
+ << "isSampleRateSupported returned true for unsupported sample rate";
+}
+
+class AudioCapsRawTest : public testing::Test {
+protected:
+ AudioCapsRawTest() {
+ std::string mediaType = MIMETYPE_AUDIO_RAW;
+
+ sp<AMessage> details = new AMessage;
+ details->setString("bitrate-range", "1-10000000");
+ details->setString("channel-ranges", "1,2,3,4,5,6,7,8,9,10,11,12");
+ details->setString("sample-rate-ranges", "8000-192000");
+
+ std::vector<ProfileLevel> profileLevel;
+
+ audioCaps = AudioCapabilities::Create(mediaType, profileLevel, details);
+ }
+
+ std::shared_ptr<AudioCapabilities> audioCaps;
+};
+
+TEST_F(AudioCapsRawTest, AudioCaps_Raw_Bitrate) {
+ const Range<int>& bitrateRange = audioCaps->getBitrateRange();
+ EXPECT_EQ(bitrateRange.lower(), 1);
+ EXPECT_EQ(bitrateRange.upper(), 10000000);
+}
+
+TEST_F(AudioCapsRawTest, AudioCaps_Raw_InputChannelCount) {
+ int maxInputChannelCount = audioCaps->getMaxInputChannelCount();
+ EXPECT_EQ(maxInputChannelCount, 12);
+ int minInputChannelCount = audioCaps->getMinInputChannelCount();
+ EXPECT_EQ(minInputChannelCount, 1);
+}
+
+TEST_F(AudioCapsRawTest, AudioCaps_Raw_InputChannelCountRanges) {
+ const std::vector<Range<int>>& inputChannelCountRanges
+ = audioCaps->getInputChannelCountRanges();
+ std::vector<Range<int>> expectedOutput({{1,1}, {2,2}, {3,3}, {4,4}, {5,5},
+ {6,6}, {7,7}, {8,8}, {9,9}, {10,10}, {11,11}, {12,12}});
+ ASSERT_EQ(inputChannelCountRanges.size(), expectedOutput.size());
+ for (int i = 0; i < inputChannelCountRanges.size(); i++) {
+ EXPECT_EQ(inputChannelCountRanges.at(i).lower(), expectedOutput.at(i).lower());
+ EXPECT_EQ(inputChannelCountRanges.at(i).upper(), expectedOutput.at(i).upper());
+ }
+}
+
+TEST_F(AudioCapsRawTest, AudioCaps_Raw_SupportedSampleRates) {
+ const std::vector<Range<int>>& sampleRateRanges = audioCaps->getSupportedSampleRateRanges();
+ EXPECT_EQ(sampleRateRanges.size(), 1);
+ EXPECT_EQ(sampleRateRanges.at(0).lower(), 8000);
+ EXPECT_EQ(sampleRateRanges.at(0).upper(), 192000);
+
+ EXPECT_EQ(audioCaps->isSampleRateSupported(7000), false);
+ EXPECT_EQ(audioCaps->isSampleRateSupported(10000), true);
+ EXPECT_EQ(audioCaps->isSampleRateSupported(193000), false);
+}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f0e1b9e..dce6ba8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1334,10 +1334,10 @@
// cause out-of-memory due to large input buffer size. And audio recording
// probably doesn't make sense in the scenario, since the slow-down factor
// is probably huge (eg. mSampleRate=48K, mCaptureFps=240, mFrameRate=1).
- const static int32_t SAMPLE_RATE_HZ_MAX = 192000;
+ const static int32_t kSampleRateHzMax = 192000;
sourceSampleRate =
(mSampleRate * mCaptureFps + mFrameRate / 2) / mFrameRate;
- if (sourceSampleRate < mSampleRate || sourceSampleRate > SAMPLE_RATE_HZ_MAX) {
+ if (sourceSampleRate < mSampleRate || sourceSampleRate > kSampleRateHzMax) {
ALOGE("source sample rate out of range! "
"(mSampleRate %d, mCaptureFps %.2f, mFrameRate %d",
mSampleRate, mCaptureFps, mFrameRate);
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index ad42813..16e267b 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -50,7 +50,7 @@
using namespace hardware::cas::native::V1_0;
using DrmBufferType = hardware::drm::V1_0::BufferType;
using BufferInfo = ACodecBufferChannel::BufferInfo;
-using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
+using BufferInfoIterator = std::vector<BufferInfo>::const_iterator;
ACodecBufferChannel::~ACodecBufferChannel() {
if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
@@ -59,7 +59,7 @@
}
static BufferInfoIterator findClientBuffer(
- const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+ const std::shared_ptr<const std::vector<BufferInfo>> &array,
const sp<MediaCodecBuffer> &buffer) {
return std::find_if(
array->begin(), array->end(),
@@ -67,7 +67,7 @@
}
static BufferInfoIterator findBufferId(
- const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+ const std::shared_ptr<const std::vector<BufferInfo>> &array,
IOMX::buffer_id bufferId) {
return std::find_if(
array->begin(), array->end(),
@@ -97,7 +97,7 @@
}
status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
@@ -138,7 +138,7 @@
if (!hasCryptoOrDescrambler() || mDealer == nullptr) {
return -ENOSYS;
}
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
@@ -352,7 +352,7 @@
size_t numSubSamples,
const sp<MediaCodecBuffer> &buffer,
AString* errorDetailMsg) {
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
@@ -473,7 +473,7 @@
status_t ACodecBufferChannel::renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mOutputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
if (it == array->end()) {
@@ -495,7 +495,7 @@
}
status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mInputBuffers));
bool input = true;
BufferInfoIterator it = findClientBuffer(array, buffer);
@@ -517,7 +517,7 @@
}
void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
- std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
+ std::shared_ptr<const std::vector<BufferInfo>> inputBuffers(
std::atomic_load(&mInputBuffers));
array->clear();
for (const BufferInfo &elem : *inputBuffers) {
@@ -526,7 +526,7 @@
}
void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
- std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
+ std::shared_ptr<const std::vector<BufferInfo>> outputBuffers(
std::atomic_load(&mOutputBuffers));
array->clear();
for (const BufferInfo &elem : *outputBuffers) {
@@ -583,7 +583,7 @@
mDecryptDestination = mDealer->allocate(destinationBufferSize);
}
}
- std::vector<const BufferInfo> inputBuffers;
+ std::vector<BufferInfo> inputBuffers;
for (const BufferAndId &elem : array) {
sp<IMemory> sharedEncryptedBuffer;
if (hasCryptoOrDescrambler()) {
@@ -593,22 +593,22 @@
}
std::atomic_store(
&mInputBuffers,
- std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
+ std::make_shared<const std::vector<BufferInfo>>(inputBuffers));
}
void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
- std::vector<const BufferInfo> outputBuffers;
+ std::vector<BufferInfo> outputBuffers;
for (const BufferAndId &elem : array) {
outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
}
std::atomic_store(
&mOutputBuffers,
- std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
+ std::make_shared<const std::vector<BufferInfo>>(outputBuffers));
}
void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
ALOGV("fillThisBuffer #%d", bufferId);
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findBufferId(array, bufferId);
@@ -629,7 +629,7 @@
IOMX::buffer_id bufferId,
OMX_U32 omxFlags) {
ALOGV("drainThisBuffer #%d", bufferId);
- std::shared_ptr<const std::vector<const BufferInfo>> array(
+ std::shared_ptr<const std::vector<BufferInfo>> array(
std::atomic_load(&mOutputBuffers));
BufferInfoIterator it = findBufferId(array, bufferId);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index e918b5e..15188b0 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -72,6 +72,9 @@
static const int64_t kMaxMetadataSize = 0x4000000LL; // 64MB max per-frame metadata size
static const int64_t kMaxCttsOffsetTimeUs = 30 * 60 * 1000000LL; // 30 minutes
static const size_t kESDSScratchBufferSize = 10; // kMaxAtomSize in Mpeg4Extractor 64MB
+// Allow up to 100 milli second, which is safely above the maximum delay observed in manual testing
+// between posting from setNextFd and handling it
+static const int64_t kFdCondWaitTimeoutNs = 100000000;
static const char kMetaKey_Version[] = "com.android.version";
static const char kMetaKey_Manufacturer[] = "com.android.manufacturer";
@@ -1262,9 +1265,13 @@
return OK;
}
+ // Wait for the signal only if the new file is not available.
if (mNextFd == -1) {
- ALOGW("No FileDescriptor for next recording");
- return INVALID_OPERATION;
+ status_t res = mFdCond.waitRelative(mLock, kFdCondWaitTimeoutNs);
+ if (res != OK) {
+ ALOGW("No FileDescriptor for next recording");
+ return INVALID_OPERATION;
+ }
}
mSwitchPending = true;
@@ -2433,6 +2440,7 @@
return INVALID_OPERATION;
}
mNextFd = dup(fd);
+ mFdCond.signal();
return OK;
}
@@ -4886,8 +4894,15 @@
int32_t mediaTime = (mFirstSampleStartOffsetUs * mTimeScale + 5E5) / 1E6;
int32_t firstSampleOffsetTicks =
(mFirstSampleStartOffsetUs * mvhdTimeScale + 5E5) / 1E6;
- // samples before 0 don't count in for duration, hence subtract firstSampleOffsetTicks.
- addOneElstTableEntry(tkhdDurationTicks - firstSampleOffsetTicks, mediaTime, 1, 0);
+ if (tkhdDurationTicks >= firstSampleOffsetTicks) {
+ // samples before 0 don't count in for duration, hence subtract
+ // firstSampleOffsetTicks.
+ addOneElstTableEntry(tkhdDurationTicks - firstSampleOffsetTicks, mediaTime, 1, 0);
+ } else {
+ ALOGW("The track header duration %" PRId64
+ " is smaller than the first sample offset %" PRId64,
+ mTrackDurationUs, mFirstSampleStartOffsetUs);
+ }
} else {
// Track starting at zero.
ALOGV("No edit list entry required for this track");
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 0401e82..04364a8 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -852,6 +852,13 @@
}
}
+ void notifyBufferAttached() {
+ auto p = mBufferChannel.lock();
+ if (p) {
+ p->onBufferAttachedToOutputSurface(mGeneration);
+ }
+ }
+
public:
explicit OnBufferReleasedListener(
uint32_t generation,
@@ -869,6 +876,14 @@
}
bool needsReleaseNotify() override { return true; }
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ void onBufferAttached() override {
+ notifyBufferAttached();
+ }
+
+ bool needsAttachNotify() override { return true; }
+#endif
};
class BufferCallback : public CodecBase::BufferCallback {
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index 946d533..46a5183 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -155,8 +155,8 @@
// obtained. Inside BufferInfo, mBufferId and mSharedEncryptedBuffer are
// immutable objects. We write internal states of mClient/CodecBuffer when
// the caller has given up the reference, so that access is also safe.
- std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
- std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
+ std::shared_ptr<const std::vector<BufferInfo>> mInputBuffers;
+ std::shared_ptr<const std::vector<BufferInfo>> mOutputBuffers;
sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index fcd17b9..f42e315 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -236,7 +236,7 @@
// Start of members protected by mBatchLock
std::deque<uint32_t> mInflightBatchSizes;
std::vector<native_handle_t*> mInflightReturnedHandles;
- std::vector<const sp<IMemory>> mInflightReturnedMemorys;
+ std::vector<sp<IMemory>> mInflightReturnedMemorys;
// End of members protected by mBatchLock
void releaseQueuedFrames();
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index bffb294..c6087b0 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -517,6 +517,15 @@
};
/**
+ * Notify a buffer is attached to output surface.
+ *
+ * @param generation MediaCodec's surface specifier
+ */
+ virtual void onBufferAttachedToOutputSurface(uint32_t /*generation*/) {
+ // default: no-op
+ };
+
+ /**
* Discard a buffer to the underlying CodecBase object.
*
* TODO: remove once this operation can be handled by just clearing the
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 054a4b8..ee75129 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -144,6 +144,7 @@
std::mutex mFallocMutex;
bool mPreAllocFirstTime; // Pre-allocate space for file and track headers only once per file.
uint64_t mPrevAllTracksTotalMetaDataSizeEstimate;
+ Condition mFdCond;
List<Track *> mTracks;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 4e4aa75..b1cf665 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -562,6 +562,30 @@
}
}
+inline constexpr int32_t DTS_HDProfileHRA = 0x1;
+inline constexpr int32_t DTS_HDProfileLBR = 0x2;
+inline constexpr int32_t DTS_HDProfileMA = 0x4;
+
+inline static const char *asString_Dts_HDProfile(int32_t i, const char *def = "??") {
+ switch (i) {
+ case DTS_HDProfileHRA: return "HRA";
+ case DTS_HDProfileLBR: return "LBR";
+ case DTS_HDProfileMA: return "MA";
+ default: return def;
+ }
+}
+
+inline constexpr int32_t DTS_UHDProfileP1 = 0x1;
+inline constexpr int32_t DTS_UHDProfileP2 = 0x2;
+
+inline static const char *asString_Dts_UHDProfile(int32_t i, const char *def = "??") {
+ switch (i) {
+ case DTS_UHDProfileP1: return "P1";
+ case DTS_UHDProfileP2: return "P2";
+ default: return def;
+ }
+}
+
inline constexpr int32_t BITRATE_MODE_CBR = 2;
inline constexpr int32_t BITRATE_MODE_CBR_FD = 3;
inline constexpr int32_t BITRATE_MODE_CQ = 0;
@@ -729,8 +753,13 @@
inline constexpr char MIMETYPE_AUDIO_FLAC[] = "audio/flac";
inline constexpr char MIMETYPE_AUDIO_MSGSM[] = "audio/gsm";
inline constexpr char MIMETYPE_AUDIO_AC3[] = "audio/ac3";
+inline constexpr char MIMETYPE_AUDIO_AC4[] = "audio/ac4";
inline constexpr char MIMETYPE_AUDIO_EAC3[] = "audio/eac3";
+inline constexpr char MIMETYPE_AUDIO_EAC3_JOC[] = "audio/eac3-joc";
inline constexpr char MIMETYPE_AUDIO_SCRAMBLED[] = "audio/scrambled";
+inline constexpr char MIMETYPE_AUDIO_DTS[] = "audio/vnd.dts";
+inline constexpr char MIMETYPE_AUDIO_DTS_HD[] = "audio/vnd.dts.hd";
+inline constexpr char MIMETYPE_AUDIO_DTS_UHD[] = "audio/vnd.dts.uhd";
inline constexpr char MIMETYPE_IMAGE_ANDROID_HEIC[] = "image/vnd.android.heic";
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index ca862b0..151ce7c 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -290,7 +290,7 @@
// Max file duration limit is set
if (mMaxFileDurationLimitUs != 0) {
if (bitRate > 0) {
- int64_t size2 = ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
+ int64_t size2 = ((mMaxFileDurationLimitUs / 1000) * bitRate * 6) / 8000000;
if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
// When both file size and duration limits are set,
// we use the smaller limit of the two.
diff --git a/media/module/bufferpool/2.0/AccessorImpl.cpp b/media/module/bufferpool/2.0/AccessorImpl.cpp
index b9483bf..3d7f0c7 100644
--- a/media/module/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/module/bufferpool/2.0/AccessorImpl.cpp
@@ -923,7 +923,7 @@
std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors,
std::mutex &mutex,
std::condition_variable &cv) {
- std::list<const std::weak_ptr<Accessor::Impl>> evictList;
+ std::list<std::weak_ptr<Accessor::Impl>> evictList;
while (true) {
int expired = 0;
int evicted = 0;
diff --git a/media/module/codecserviceregistrant/Android.bp b/media/module/codecserviceregistrant/Android.bp
index becb98a..56cd8b8 100644
--- a/media/module/codecserviceregistrant/Android.bp
+++ b/media/module/codecserviceregistrant/Android.bp
@@ -55,6 +55,8 @@
"com.android.media.swcodec",
],
+ export_include_dirs: ["include"],
+
srcs: [
"CodecServiceRegistrant.cpp",
],
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 6df9dc8..42fd94e 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -40,7 +40,7 @@
#include <codec2/aidl/ComponentStore.h>
#include <codec2/aidl/ParamTypes.h>
-#include <media/CodecServiceRegistrant.h>
+#include <codecserviceregistrant/CodecServiceRegistrant.h>
namespace /* unnamed */ {
@@ -775,13 +775,12 @@
return nullptr;
}
-extern "C" void RegisterCodecServices() {
+/**
+ * This function encapsulates the core logic required to register codec services,
+ * separated from threadpool management to avoid timeouts when called by the fuzzer.
+ */
+static void RegisterCodecServicesWithExistingThreadpool() {
const bool aidlSelected = c2_aidl::utils::IsSelected();
- constexpr int kThreadCount = 64;
- ABinderProcess_setThreadPoolMaxThreadCount(kThreadCount);
- ABinderProcess_startThreadPool();
- ::android::hardware::configureRpcThreadpool(kThreadCount, false);
-
LOG(INFO) << "Creating software Codec2 service...";
std::shared_ptr<C2ComponentStore> store =
android::GetCodec2PlatformComponentStore();
@@ -880,8 +879,16 @@
if (registered) {
LOG(INFO) << "Software Codec2 service created and registered.";
}
+}
+
+extern "C" void RegisterCodecServices() {
+ constexpr int kThreadCount = 64;
+ ABinderProcess_setThreadPoolMaxThreadCount(kThreadCount);
+ ABinderProcess_startThreadPool();
+ ::android::hardware::configureRpcThreadpool(kThreadCount, false);
+
+ RegisterCodecServicesWithExistingThreadpool();
ABinderProcess_joinThreadPool();
::android::hardware::joinRpcThreadpool();
}
-
diff --git a/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp b/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
index 4868e0c..0baf1ca 100644
--- a/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
+++ b/media/module/codecserviceregistrant/fuzzer/codecServiceRegistrant_fuzzer.cpp
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <codecserviceregistrant/CodecServiceRegistrant.h>
+
#include "../CodecServiceRegistrant.cpp"
#include "fuzzer/FuzzedDataProvider.h"
#include <C2Config.h>
@@ -166,9 +169,9 @@
void CodecServiceRegistrantFuzzer::process(const uint8_t *data, size_t size) {
mFDP = new FuzzedDataProvider(data, size);
invokeH2C2ComponentStore();
- /** RegisterCodecServices is called here to improve code coverage */
- /** as currently it is not called by codecServiceRegistrant */
- RegisterCodecServices();
+ /** RegisterCodecServicesWithExistingThreadpool() is called here to improve
+ * code coverage as currently it is not called in codecServiceRegistrant.cpp */
+ RegisterCodecServicesWithExistingThreadpool();
delete mFDP;
}
diff --git a/media/libmedia/include/media/CodecServiceRegistrant.h b/media/module/codecserviceregistrant/include/codecserviceregistrant/CodecServiceRegistrant.h
similarity index 77%
rename from media/libmedia/include/media/CodecServiceRegistrant.h
rename to media/module/codecserviceregistrant/include/codecserviceregistrant/CodecServiceRegistrant.h
index e0af781..1c6f71f 100644
--- a/media/libmedia/include/media/CodecServiceRegistrant.h
+++ b/media/module/codecserviceregistrant/include/codecserviceregistrant/CodecServiceRegistrant.h
@@ -18,6 +18,13 @@
#define CODEC_SERVICE_REGISTRANT_H_
+/**
+ * This function starts the threadpool, calls the registration logic
+ * encapsulated in RegisterCodecServicesWithExistingThreadpool(), and
+ * then stops the threadpool.
+ */
+extern "C" void RegisterCodecServices();
+
typedef void (*RegisterCodecServicesFunc)();
#endif // CODEC_SERVICE_REGISTRANT_H_
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index b3707c8..f247f8c 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -523,11 +523,10 @@
}
[this, &track] {
- int64_t duration;
+ int64_t duration = track->mMdhdDurationUs;
int32_t samplerate;
// Only for audio track.
- if (track->elst_needs_processing && mHeaderTimescale != 0 &&
- AMediaFormat_getInt64(track->meta, AMEDIAFORMAT_KEY_DURATION, &duration) &&
+ if (track->elst_needs_processing && mHeaderTimescale != 0 && duration != 0 &&
AMediaFormat_getInt32(track->meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &samplerate)) {
// Elst has to be processed only the first time this function is called.
track->elst_needs_processing = false;
@@ -1645,7 +1644,10 @@
(long long) duration, (long long) mLastTrack->timescale);
return ERROR_MALFORMED;
}
- AMediaFormat_setInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION, durationUs);
+ // Store this track's mdhd duration to calculate the padding.
+ mLastTrack->mMdhdDurationUs = (int64_t)durationUs;
+ } else {
+ mLastTrack->mMdhdDurationUs = 0;
}
uint8_t lang[2];
@@ -3907,17 +3909,18 @@
}
int32_t id;
+ int64_t duration;
if (version == 1) {
// we can get ctime value from U64_AT(&buffer[4])
// we can get mtime value from U64_AT(&buffer[12])
id = U32_AT(&buffer[20]);
- // we can get duration value from U64_AT(&buffer[28])
+ duration = U64_AT(&buffer[28]);
} else if (version == 0) {
// we can get ctime value from U32_AT(&buffer[4])
// we can get mtime value from U32_AT(&buffer[8])
id = U32_AT(&buffer[12]);
- // we can get duration value from U32_AT(&buffer[20])
+ duration = U32_AT(&buffer[20]);
} else {
return ERROR_UNSUPPORTED;
}
@@ -3926,6 +3929,15 @@
return ERROR_MALFORMED;
AMediaFormat_setInt32(mLastTrack->meta, AMEDIAFORMAT_KEY_TRACK_ID, id);
+ if (duration != 0 && mHeaderTimescale != 0) {
+ long double durationUs = ((long double)duration * 1000000) / mHeaderTimescale;
+ if (durationUs < 0 || durationUs > INT64_MAX) {
+ ALOGE("cannot represent %lld * 1000000 / %lld in 64 bits",
+ (long long) duration, (long long) mHeaderTimescale);
+ return ERROR_MALFORMED;
+ }
+ AMediaFormat_setInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION, durationUs);
+ }
size_t matrixOffset = dynSize + 16;
int32_t a00 = U32_AT(&buffer[matrixOffset]);
diff --git a/media/module/extractors/mp4/include/MPEG4Extractor.h b/media/module/extractors/mp4/include/MPEG4Extractor.h
index 542a3e6..59626f6 100644
--- a/media/module/extractors/mp4/include/MPEG4Extractor.h
+++ b/media/module/extractors/mp4/include/MPEG4Extractor.h
@@ -96,7 +96,7 @@
uint8_t *mTx3gBuffer;
size_t mTx3gSize, mTx3gFilled;
-
+ int64_t mMdhdDurationUs;
Track() {
next = NULL;
diff --git a/media/mtp/tests/MtpFuzzer/Android.bp b/media/mtp/tests/MtpFuzzer/Android.bp
index acae06a..2e9c58b 100644
--- a/media/mtp/tests/MtpFuzzer/Android.bp
+++ b/media/mtp/tests/MtpFuzzer/Android.bp
@@ -29,7 +29,6 @@
"liblog",
"libutils",
],
- static_libs: ["libc++fs",],
cflags: [
"-Wall",
"-Wextra",
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 197e202..def142c 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -49,16 +49,16 @@
/*
* AMediaDataSource's callbacks will be invoked on an implementation-defined thread
* or thread pool. No guarantees are provided about which thread(s) will be used for
- * callbacks. For example, |close| can be invoked from a different thread than the
- * thread invoking |readAt|. As such, the Implementations of AMediaDataSource callbacks
+ * callbacks. For example, `close` can be invoked from a different thread than the
+ * thread invoking `readAt`. As such, the Implementations of AMediaDataSource callbacks
* must be threadsafe.
*/
/**
- * Called to request data from the given |offset|.
+ * Called to request data from the given `offset`.
*
- * Implementations should should write up to |size| bytes into
- * |buffer|, and return the number of bytes written.
+ * Implementations should should write up to `size` bytes into
+ * `buffer`, and return the number of bytes written.
*
* Return 0 if size is zero (thus no bytes are read).
*
@@ -78,9 +78,9 @@
* Called to close the data source, unblock reads, and release associated
* resources.
*
- * The NDK media framework guarantees that after the first |close| is
+ * The NDK media framework guarantees that after the first `close` is
* called, no future callbacks will be invoked on the data source except
- * for |close| itself.
+ * for `close` itself.
*
* Closing a data source allows readAt calls that were blocked waiting
* for I/O data to return promptly.
@@ -101,7 +101,7 @@
/**
* Called to get an estimate of the number of bytes that can be read from this data source
- * starting at |offset| without blocking for I/O.
+ * starting at `offset` without blocking for I/O.
*
* Return -1 when such an estimate is not possible.
*/
@@ -111,10 +111,10 @@
* Create new media data source. Returns NULL if memory allocation
* for the new data source object fails.
*
- * Set the |uri| from which the data source will read,
+ * Set the `uri` from which the data source will read,
* plus additional http headers when initiating the request.
*
- * Headers will contain corresponding items from |key_values|
+ * Headers will contain corresponding items from `key_values`
* in the following fashion:
*
* key_values[0]:key_values[1]
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 60be37d..a17ac58 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3812,7 +3812,11 @@
IAfPlaybackThread* AudioFlinger::primaryPlaybackThread_l() const
{
- audio_utils::lock_guard lock(hardwareMutex());
+ // The atomic ptr mPrimaryHardwareDev requires both the
+ // AudioFlinger and the Hardware mutex for modification.
+ // As we hold the AudioFlinger mutex, we access it
+ // safely without the Hardware mutex, to avoid mutex order
+ // inversion with Thread methods and the ThreadBase mutex.
if (mPrimaryHardwareDev == nullptr) {
return nullptr;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 501aed1..dcad0e2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -339,7 +339,9 @@
const String8& address,
audio_output_flags_t flags) final REQUIRES(mutex());
const DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>&
- getAudioHwDevs_l() const final REQUIRES(mutex()) { return mAudioHwDevs; }
+ getAudioHwDevs_l() const final REQUIRES(mutex(), hardwareMutex()) {
+ return mAudioHwDevs;
+ }
void updateDownStreamPatches_l(const struct audio_patch* patch,
const std::set<audio_io_handle_t>& streams) final REQUIRES(mutex());
void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices) final
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
index feae97e..7cb9329 100644
--- a/services/audioflinger/DeviceEffectManager.cpp
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -71,10 +71,15 @@
void DeviceEffectManager::onReleaseAudioPatch(audio_patch_handle_t handle) {
ALOGV("%s", __func__);
+ // Keep a reference on disconnected handle to delay destruction without lock held.
+ std::vector<sp<IAfEffectHandle>> disconnectedHandles{};
audio_utils::lock_guard _l(mutex());
for (auto& effectProxies : mDeviceEffects) {
for (auto& effect : effectProxies.second) {
- effect->onReleasePatch(handle);
+ sp<IAfEffectHandle> disconnectedHandle = effect->onReleasePatch(handle);
+ if (disconnectedHandle != nullptr) {
+ disconnectedHandles.push_back(std::move(disconnectedHandle));
+ }
}
}
}
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index c73b946..cfd0a5e 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1046,8 +1046,21 @@
return;
}
- (void)getCallback()->addEffectToHal(mEffectInterface);
- mCurrentHalStream = getCallback()->io();
+ status_t status = getCallback()->addEffectToHal(mEffectInterface);
+ if (status == NO_ERROR) {
+ mCurrentHalStream = getCallback()->io();
+ }
+ }
+}
+
+void HwAccDeviceEffectModule::addEffectToHal_l()
+{
+ if (mAddedToHal) {
+ return;
+ }
+ status_t status = getCallback()->addEffectToHal(mEffectInterface);
+ if (status == NO_ERROR) {
+ mAddedToHal = true;
}
}
@@ -1153,6 +1166,16 @@
return NO_ERROR;
}
+status_t HwAccDeviceEffectModule::removeEffectFromHal_l()
+{
+ if (!mAddedToHal) {
+ return NO_ERROR;
+ }
+ getCallback()->removeEffectFromHal(mEffectInterface);
+ mAddedToHal = false;
+ return NO_ERROR;
+}
+
// round up delta valid if value and divisor are positive.
template <typename T>
static T roundUpDelta(const T &value, const T &divisor) {
@@ -1373,12 +1396,12 @@
((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
(mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND ||
(mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_MONITOR)) {
- status = setVolumeInternal(left, right, controller);
+ status = setVolumeInternal_ll(left, right, controller);
}
return status;
}
-status_t EffectModule::setVolumeInternal(
+status_t EffectModule::setVolumeInternal_ll(
uint32_t *left, uint32_t *right, bool controller) {
if (mVolume.has_value() && *left == mVolume.value()[0] && *right == mVolume.value()[1] &&
!controller) {
@@ -1737,6 +1760,9 @@
const sp<media::IEffectClient>& effectClient,
int32_t priority, bool notifyFramesProcessed)
{
+ if (client == nullptr && effectClient == nullptr) {
+ return sp<InternalEffectHandle>::make(effect, notifyFramesProcessed);
+ }
return sp<EffectHandle>::make(
effect, client, effectClient, priority, notifyFramesProcessed);
}
@@ -1744,12 +1770,14 @@
EffectHandle::EffectHandle(const sp<IAfEffectBase>& effect,
const sp<Client>& client,
const sp<media::IEffectClient>& effectClient,
- int32_t priority, bool notifyFramesProcessed)
- : BnEffect(),
+ int32_t priority, bool notifyFramesProcessed,
+ bool isInternal,
+ audio_utils::MutexOrder mutexOrder)
+ : BnEffect(), mMutex(audio_utils::mutex{mutexOrder}),
mEffect(effect), mEffectClient(media::EffectClientAsyncProxy::makeIfNeeded(effectClient)),
mClient(client), mCblk(nullptr),
mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false),
- mNotifyFramesProcessed(notifyFramesProcessed)
+ mNotifyFramesProcessed(notifyFramesProcessed), mIsInternal(isInternal)
{
ALOGV("constructor %p client %p", this, client.get());
setMinSchedulerPolicy(SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
@@ -1916,7 +1944,7 @@
void EffectHandle::disconnect(bool unpinIfLast)
{
- audio_utils::lock_guard _l(mutex());
+ audio_utils::unique_lock _l(mutex());
ALOGV("disconnect(%s) %p", unpinIfLast ? "true" : "false", this);
if (mDisconnected) {
if (unpinIfLast) {
@@ -1928,11 +1956,19 @@
{
sp<IAfEffectBase> effect = mEffect.promote();
if (effect != 0) {
+ // Unlock e.g. for device effect: may need to acquire AudioFlinger lock
+ // Also Internal Effect Handle would require Proxy lock (and vice versa).
+ if (isInternal()) {
+ _l.unlock();
+ }
if (effect->disconnectHandle(this, unpinIfLast) > 0) {
ALOGW("%s Effect handle %p disconnected after thread destruction",
__func__, this);
}
effect->updatePolicyState();
+ if (isInternal()) {
+ _l.lock();
+ }
}
}
@@ -3511,19 +3547,17 @@
ALOGV("%s reusing HAL effect", __func__);
} else {
mDevicePort = *port;
- mHalEffect = new EffectModule(mMyCallback,
- const_cast<effect_descriptor_t *>(&mDescriptor),
- mMyCallback->newEffectId(), AUDIO_SESSION_DEVICE,
- false /* pinned */, port->id);
+ mHalEffect = sp<HwAccDeviceEffectModule>::make(mMyCallback,
+ const_cast<effect_descriptor_t *>(&mDescriptor), mMyCallback->newEffectId(),
+ port->id);
+ mHalEffect->configure_l();
if (audio_is_input_device(mDevice.mType)) {
mHalEffect->setInputDevice(mDevice);
} else {
mHalEffect->setDevices({mDevice});
}
- mHalEffect->configure_l();
}
- *handle = new EffectHandle(mHalEffect, nullptr, nullptr, 0 /*priority*/,
- mNotifyFramesProcessed);
+ *handle = new InternalEffectHandle(mHalEffect, mNotifyFramesProcessed);
status = (*handle)->initCheck();
if (status == OK) {
status = mHalEffect->addHandle((*handle).get());
@@ -3570,15 +3604,16 @@
return status;
}
-void DeviceEffectProxy::onReleasePatch(audio_patch_handle_t patchHandle) {
- sp<IAfEffectHandle> effect;
+sp<IAfEffectHandle> DeviceEffectProxy::onReleasePatch(audio_patch_handle_t patchHandle) {
+ sp<IAfEffectHandle> disconnectedHandle;
{
audio_utils::lock_guard _l(proxyMutex());
if (mEffectHandles.find(patchHandle) != mEffectHandles.end()) {
- effect = mEffectHandles.at(patchHandle);
+ disconnectedHandle = std::move(mEffectHandles.at(patchHandle));
mEffectHandles.erase(patchHandle);
}
}
+ return disconnectedHandle;
}
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index d107543..9ecf89e 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -179,7 +179,7 @@
// the attached track(s) to accumulate their auxiliary channel.
class EffectModule : public IAfEffectModule, public EffectBase {
public:
- EffectModule(const sp<EffectCallbackInterface>& callabck,
+ EffectModule(const sp<EffectCallbackInterface>& callback,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
@@ -228,7 +228,7 @@
REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
bool isOffloaded_l() const final
REQUIRES(audio_utils::EffectChain_Mutex) EXCLUDES_EffectBase_Mutex;
- void addEffectToHal_l() final REQUIRES(audio_utils::EffectChain_Mutex);
+ void addEffectToHal_l() override REQUIRES(audio_utils::EffectChain_Mutex);
void release_l(const std::string& from = "") final REQUIRES(audio_utils::EffectChain_Mutex);
sp<IAfEffectModule> asEffectModule() final { return this; }
@@ -250,6 +250,9 @@
void dump(int fd, const Vector<String16>& args) const final;
+protected:
+ sp<EffectHalInterface> mEffectInterface; // Effect module HAL
+
private:
// Maximum time allocated to effect engines to complete the turn off sequence
@@ -259,18 +262,18 @@
status_t start_ll() REQUIRES(audio_utils::EffectChain_Mutex, audio_utils::EffectBase_Mutex);
status_t stop_ll() REQUIRES(audio_utils::EffectChain_Mutex, audio_utils::EffectBase_Mutex);
- status_t removeEffectFromHal_l() REQUIRES(audio_utils::EffectChain_Mutex);
+ status_t removeEffectFromHal_l() override REQUIRES(audio_utils::EffectChain_Mutex);
status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);
effect_buffer_access_e requiredEffectBufferAccessMode() const {
return mConfig.inputCfg.buffer.raw == mConfig.outputCfg.buffer.raw
? EFFECT_BUFFER_ACCESS_WRITE : EFFECT_BUFFER_ACCESS_ACCUMULATE;
}
- status_t setVolumeInternal(uint32_t* left, uint32_t* right,
- bool controller /* the volume controller effect of the chain */);
+ status_t setVolumeInternal_ll(uint32_t* left, uint32_t* right,
+ bool controller /* the volume controller effect of the chain */)
+ REQUIRES(audio_utils::EffectChain_Mutex, audio_utils::EffectBase_Mutex);
effect_config_t mConfig; // input and output audio configuration
- sp<EffectHalInterface> mEffectInterface; // Effect module HAL
sp<EffectBufferHalInterface> mInBuffer; // Buffers for interacting with HAL
sp<EffectBufferHalInterface> mOutBuffer;
status_t mStatus; // initialization status
@@ -292,12 +295,12 @@
template <typename MUTEX>
class AutoLockReentrant {
public:
- AutoLockReentrant(MUTEX& mutex, pid_t allowedTid)
+ AutoLockReentrant(MUTEX& mutex, pid_t allowedTid) ACQUIRE(audio_utils::EffectBase_Mutex)
: mMutex(gettid() == allowedTid ? nullptr : &mutex)
{
if (mMutex != nullptr) mMutex->lock();
}
- ~AutoLockReentrant() {
+ ~AutoLockReentrant() RELEASE(audio_utils::EffectBase_Mutex) {
if (mMutex != nullptr) mMutex->unlock();
}
private:
@@ -314,7 +317,19 @@
// here is used to indicate the volume to apply before this effect.
std::optional<std::vector<uint32_t>> mReturnedVolume;
// TODO: b/315995877, remove this debugging string after root cause
- std::string mEffectInterfaceDebug;
+ std::string mEffectInterfaceDebug GUARDED_BY(audio_utils::EffectChain_Mutex);
+};
+
+class HwAccDeviceEffectModule : public EffectModule {
+public:
+ HwAccDeviceEffectModule(const sp<EffectCallbackInterface>& callback, effect_descriptor_t *desc,
+ int id, audio_port_handle_t deviceId) :
+ EffectModule(callback, desc, id, AUDIO_SESSION_DEVICE, /* pinned */ false, deviceId) {}
+ void addEffectToHal_l() final REQUIRES(audio_utils::EffectChain_Mutex);
+
+private:
+ status_t removeEffectFromHal_l() final REQUIRES(audio_utils::EffectChain_Mutex);
+ bool mAddedToHal = false;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -329,7 +344,8 @@
EffectHandle(const sp<IAfEffectBase>& effect,
const sp<Client>& client,
const sp<media::IEffectClient>& effectClient,
- int32_t priority, bool notifyFramesProcessed);
+ int32_t priority, bool notifyFramesProcessed, bool isInternal = false,
+ audio_utils::MutexOrder mutexOrder = audio_utils::MutexOrder::kEffectHandle_Mutex);
~EffectHandle() override;
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) final;
@@ -349,6 +365,11 @@
int32_t* _aidl_return) final;
const sp<Client>& client() const final { return mClient; }
+ /**
+ * Checks if the handle is internal, aka created by AudioFlinger for internal needs (e.g.
+ * device effect HAL handle or device effect thread handle).
+ */
+ virtual bool isInternal() const { return mIsInternal; }
sp<android::media::IEffect> asIEffect() final {
return sp<android::media::IEffect>::fromExisting(this);
@@ -386,15 +407,18 @@
void dumpToBuffer(char* buffer, size_t size) const final;
+protected:
+ // protects IEffect method calls
+ mutable audio_utils::mutex mMutex;
private:
DISALLOW_COPY_AND_ASSIGN(EffectHandle);
- audio_utils::mutex& mutex() const RETURN_CAPABILITY(android::audio_utils::EffectHandle_Mutex) {
+ virtual audio_utils::mutex& mutex() const
+ RETURN_CAPABILITY(android::audio_utils::EffectHandle_Mutex) {
return mMutex;
}
- // protects IEffect method calls
- mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kEffectHandle_Mutex};
+
const wp<IAfEffectBase> mEffect; // pointer to controlled EffectModule
const sp<media::IEffectClient> mEffectClient; // callback interface for client notifications
/*const*/ sp<Client> mClient; // client for shared memory allocation, see
@@ -410,6 +434,28 @@
bool mDisconnected; // Set to true by disconnect()
const bool mNotifyFramesProcessed; // true if the client callback event
// EVENT_FRAMES_PROCESSED must be generated
+ const bool mIsInternal;
+};
+
+/**
+ * There are 2 types of effects:
+ * -Session Effect: handle is directly called from the client, without AudioFlinger lock.
+ * -Device Effect: a device effect proxy is aggregating a collection of internal effect handles that
+ * controls the same effect added on all audio patches involving the device effect selected port
+ * requested either by a client or by AudioPolicyEffects. These internal effect handles do not have
+ * client. Sequence flow implies a different locking order, hence the lock is specialied.
+ */
+class InternalEffectHandle : public EffectHandle {
+public:
+ InternalEffectHandle(const sp<IAfEffectBase>& effect, bool notifyFramesProcessed) :
+ EffectHandle(effect, /* client= */ nullptr, /* effectClient= */ nullptr,
+ /* priority= */ 0, notifyFramesProcessed, /* isInternal */ true,
+ audio_utils::MutexOrder::kDeviceEffectHandle_Mutex) {}
+
+ virtual audio_utils::mutex& mutex() const
+ RETURN_CAPABILITY(android::audio_utils::DeviceEffectHandle_Mutex) {
+ return mMutex;
+ }
};
// the EffectChain class represents a group of effects associated to one audio session.
@@ -713,7 +759,7 @@
uint32_t mRightVolume; // previous volume on right channel
uint32_t mNewLeftVolume; // new volume on left channel
uint32_t mNewRightVolume; // new volume on right channel
- product_strategy_t mStrategy; // strategy for this effect chain
+ product_strategy_t mStrategy = PRODUCT_STRATEGY_NONE; // strategy for this effect chain
// mSuspendedEffects lists all effects currently suspended in the chain.
// Use effect type UUID timelow field as key. There is no real risk of identical
// timeLow fields among effect type UUIDs.
@@ -747,7 +793,7 @@
status_t onUpdatePatch(audio_patch_handle_t oldPatchHandle, audio_patch_handle_t newPatchHandle,
const IAfPatchPanel::Patch& patch) final;
- void onReleasePatch(audio_patch_handle_t patchHandle) final;
+ sp<IAfEffectHandle> onReleasePatch(audio_patch_handle_t patchHandle) final;
size_t removeEffect(const sp<IAfEffectModule>& effect) final;
@@ -796,7 +842,10 @@
audio_channel_mask_t outChannelMask() const override;
uint32_t outChannelCount() const override;
audio_channel_mask_t hapticChannelMask() const override { return AUDIO_CHANNEL_NONE; }
- size_t frameCount() const override { return 0; }
+ /**
+ * frameCount cannot be zero.
+ */
+ size_t frameCount() const override { return 1; }
uint32_t latency() const override { return 0; }
status_t addEffectToHal(const sp<EffectHalInterface>& effect) override;
@@ -808,7 +857,7 @@
void checkSuspendOnEffectEnabled(const sp<IAfEffectBase>& effect __unused,
bool enabled __unused, bool threadLocked __unused) override {}
void resetVolume_l() override REQUIRES(audio_utils::EffectChain_Mutex) {}
- product_strategy_t strategy() const override { return static_cast<product_strategy_t>(0); }
+ product_strategy_t strategy() const override { return PRODUCT_STRATEGY_NONE; }
int32_t activeTrackCnt() const override { return 0; }
void onEffectEnable(const sp<IAfEffectBase>& effect __unused) override;
void onEffectDisable(const sp<IAfEffectBase>& effect __unused) override;
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index bb82afb..3452e94 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -153,7 +153,7 @@
public:
static sp<IAfEffectModule> create(
- const sp<EffectCallbackInterface>& callabck,
+ const sp<EffectCallbackInterface>& callback,
effect_descriptor_t *desc,
int id,
audio_session_t sessionId,
@@ -214,6 +214,7 @@
virtual status_t stop_l() = 0;
virtual void addEffectToHal_l() = 0;
+ virtual status_t removeEffectFromHal_l() = 0;
virtual void release_l(const std::string& from) = 0;
};
@@ -399,7 +400,14 @@
virtual status_t onUpdatePatch(audio_patch_handle_t oldPatchHandle,
audio_patch_handle_t newPatchHandle,
const IAfPatchPanel::Patch& patch) = 0;
- virtual void onReleasePatch(audio_patch_handle_t patchHandle) = 0;
+ /**
+ * Checks (and release) of the effect handle is linked with the given release patch handle.
+ *
+ * @param patchHandle handle of the released patch
+ * @return a reference on the effect handle released if any, nullptr otherwise.
+ * It allows to delay the destruction of the handle.
+ */
+ virtual sp<IAfEffectHandle> onReleasePatch(audio_patch_handle_t patchHandle) = 0;
virtual void dump2(int fd, int spaces) const = 0; // TODO(b/291319101) naming?
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 4518d48..a7da658 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -19,8 +19,9 @@
#include <android/media/IAudioTrackCallback.h>
#include <android/media/IEffectClient.h>
#include <audiomanager/IAudioManager.h>
-#include <audio_utils/mutex.h>
+#include <audio_utils/DeferredExecutor.h>
#include <audio_utils/MelProcessor.h>
+#include <audio_utils/mutex.h>
#include <binder/MemoryDealer.h>
#include <datapath/AudioStreamIn.h>
#include <datapath/AudioStreamOut.h>
@@ -395,6 +396,12 @@
// avoid races.
virtual void waitWhileThreadBusy_l(audio_utils::unique_lock& ul)
REQUIRES(mutex()) = 0;
+
+ // The ThreadloopExecutor is used to defer functors or dtors
+ // to when the Threadloop does not hold any mutexes (at the end of the
+ // processing period cycle).
+ virtual audio_utils::DeferredExecutor& getThreadloopExecutor() = 0;
+
// Dynamic cast to derived interface
virtual sp<IAfDirectOutputThread> asIAfDirectOutputThread() { return nullptr; }
virtual sp<IAfDuplicatingThread> asIAfDuplicatingThread() { return nullptr; }
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 7a66e5b..2cc6236 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -455,7 +455,7 @@
void queueBuffer(Buffer& inBuffer);
void clearBufferQueue();
- void restartIfDisabled();
+ void restartIfDisabled() override;
// Maximum number of pending buffers allocated by OutputTrack::write()
static const uint8_t kMaxOverFlowBuffers = 10;
@@ -519,7 +519,7 @@
void releaseBuffer(Proxy::Buffer* buffer) final;
private:
- void restartIfDisabled();
+ void restartIfDisabled() override;
}; // end of PatchTrack
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 66e89e4..5c0ca5e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4646,7 +4646,11 @@
// FIXME Note that the above .clear() is no longer necessary since effectChains
// is now local to this block, but will keep it for now (at least until merge done).
+
+ mThreadloopExecutor.process();
}
+ mThreadloopExecutor.process(); // process any remaining deferred actions.
+ // deferred actions after this point are ignored.
threadLoop_exit();
@@ -7185,14 +7189,11 @@
{
PlaybackThread::flushHw_l();
mOutput->flush();
+ mHwPaused = false;
mFlushPending = false;
mTimestampVerifier.discontinuity(discontinuityForStandbyOrFlush());
mTimestamp.clear();
mMonotonicFrameCounter.onFlush();
- // We do not reset mHwPaused which is hidden from the Track client.
- // Note: the client track in Tracks.cpp and AudioTrack.cpp
- // has a FLUSHED state but the DirectOutputThread does not;
- // those tracks will continue to show isStopped().
}
int64_t DirectOutputThread::computeWaitTimeNs_l() const {
@@ -8670,6 +8671,9 @@
// loop over each active track
for (size_t i = 0; i < size; i++) {
+ if (activeTrack) { // ensure track release is outside lock.
+ oldActiveTracks.emplace_back(std::move(activeTrack));
+ }
activeTrack = activeTracks[i];
// skip fast tracks, as those are handled directly by FastCapture
@@ -8813,11 +8817,14 @@
mIoJitterMs.add(jitterMs);
mProcessTimeMs.add(processMs);
}
+ mThreadloopExecutor.process();
// update timing info.
mLastIoBeginNs = lastIoBeginNs;
mLastIoEndNs = lastIoEndNs;
lastLoopCountRead = loopCount;
}
+ mThreadloopExecutor.process(); // process any remaining deferred actions.
+ // deferred actions after this point are ignored.
standbyIfNotAlreadyInStandby();
@@ -10603,7 +10610,10 @@
unlockEffectChains(effectChains);
// Effect chains will be actually deleted here if they were removed from
// mEffectChains list during mixing or effects processing
+ mThreadloopExecutor.process();
}
+ mThreadloopExecutor.process(); // process any remaining deferred actions.
+ // deferred actions after this point are ignored.
threadLoop_exit();
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 4b2ade4..654b841 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -571,6 +571,10 @@
void stopMelComputation_l() override
REQUIRES(audio_utils::AudioFlinger_Mutex);
+ audio_utils::DeferredExecutor& getThreadloopExecutor() override {
+ return mThreadloopExecutor;
+ }
+
protected:
// entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -877,6 +881,14 @@
SimpleLog mLocalLog; // locked internally
+ // mThreadloopExecutor contains deferred functors and object (dtors) to
+ // be executed at the end of the processing period, without any
+ // mutexes held.
+ //
+ // mThreadloopExecutor is locked internally, so its methods are thread-safe
+ // for access.
+ audio_utils::DeferredExecutor mThreadloopExecutor;
+
private:
void dumpBase_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
void dumpEffectChains_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 5708c61..a0b85f7 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -333,6 +333,9 @@
// true for Track, false for RecordTrack,
// this could be a track type if needed later
+ void deferRestartIfDisabled();
+ virtual void restartIfDisabled() {}
+
const wp<IAfThreadBase> mThread;
const alloc_type mAllocType;
/*const*/ sp<Client> mClient; // see explanation at ~TrackBase() why not const
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a268df8..f5f11cc 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -314,6 +314,17 @@
return NO_ERROR;
}
+void TrackBase::deferRestartIfDisabled()
+{
+ const auto thread = mThread.promote();
+ if (thread == nullptr) return;
+ thread->getThreadloopExecutor().defer(
+ [track = wp<TrackBase>::fromExisting(this)] {
+ const auto actual = track.promote();
+ if (actual) actual->restartIfDisabled();
+ });
+}
+
PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
IAfThreadBase* thread, const Timeout& timeout)
: mProxy(proxy)
@@ -2310,7 +2321,7 @@
waitTimeLeftMs = 0;
}
if (status == NOT_ENOUGH_DATA) {
- restartIfDisabled();
+ deferRestartIfDisabled();
continue;
}
}
@@ -2322,7 +2333,7 @@
buf.mFrameCount = outFrames;
buf.mRaw = NULL;
mClientProxy->releaseBuffer(&buf);
- restartIfDisabled();
+ deferRestartIfDisabled();
pInBuffer->frameCount -= outFrames;
pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize;
mOutBuffer.frameCount -= outFrames;
@@ -2577,7 +2588,7 @@
const size_t originalFrameCount = buffer->mFrameCount;
do {
if (status == NOT_ENOUGH_DATA) {
- restartIfDisabled();
+ deferRestartIfDisabled();
buffer->mFrameCount = originalFrameCount; // cleared on error, must be restored.
}
status = mProxy->obtainBuffer(buffer, timeOut);
@@ -2588,7 +2599,7 @@
void PatchTrack::releaseBuffer(Proxy::Buffer* buffer)
{
mProxy->releaseBuffer(buffer);
- restartIfDisabled();
+ deferRestartIfDisabled();
// Check if the PatchTrack has enough data to write once in releaseBuffer().
// If not, prevent an underrun from occurring by moving the track into FS_FILLING;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 04d5362..ee6af4c 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -38,10 +38,6 @@
static const uint32_t SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY = 5000;
-// For mixed output and inputs, the policy will use max mixer sampling rates.
-// Do not limit sampling rate otherwise
-#define SAMPLE_RATE_HZ_MAX 192000
-
// Used when a client opens a capture stream, without specifying a desired sample rate.
#define SAMPLE_RATE_HZ_DEFAULT 48000
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c502fc2..7002e63 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -282,6 +282,11 @@
const AudioProfileVector& getSupportedProfiles() { return mSupportedProfiles; }
+ /**
+ * @brief checks if all devices in device vector are attached to the HwModule or not
+ * @return true if all the devices in device vector are attached, otherwise false
+ */
+ bool areAllDevicesAttached() const;
// Return a string to describe the DeviceVector. The sensitive information will only be
// added to the string if `includeSensitiveInfo` is true.
std::string toString(bool includeSensitiveInfo = false) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index b92cd70..f7b9b33 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -99,21 +99,20 @@
* @return ioHandle if found, AUDIO_IO_HANDLE_NONE otherwise.
*/
audio_io_handle_t getIoForSession(audio_session_t sessionId,
- const effect_uuid_t *effectType = nullptr) const;
- bool hasOrphansForSession(audio_session_t sessionId) const;
- EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const;
- void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
+ const effect_uuid_t* effectType = nullptr) const;
/**
- * @brief Checks if there is at least one orphan effect with given sessionId and effect type
- * uuid.
+ * @brief Checks if there is at least one orphan effect with given sessionId and optional effect
+ * type uuid.
* @param sessionId Session ID.
- * @param effectType Effect type UUID, the implementation will be same as hasOrphansForSession
- * if null.
+ * @param effectType Optional effect type UUID pointer to effect_uuid_t, nullptr by default.
* @return True if there is an orphan effect for given sessionId and type UUID, false otherwise.
*/
- bool hasOrphanEffectsForSessionAndType(audio_session_t sessionId,
- const effect_uuid_t* effectType) const;
+ bool hasOrphansForSession(audio_session_t sessionId,
+ const effect_uuid_t* effectType = nullptr) const;
+
+ EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const;
+ void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
private:
status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 9f7b8fc..46a04de 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -541,4 +541,14 @@
return filteredDevices;
}
+bool DeviceVector::areAllDevicesAttached() const
+{
+ for (const auto &device : *this) {
+ if (!device->isAttached()) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 7971b61..090da6c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -210,27 +210,13 @@
}
}
-bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId) const
-{
+bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId,
+ const effect_uuid_t* effectType) const {
for (size_t i = 0; i < size(); ++i) {
sp<EffectDescriptor> effect = valueAt(i);
- if (effect->mSession == sessionId && effect->mIsOrphan) {
- return true;
- }
- }
- return false;
-}
-
-bool EffectDescriptorCollection::hasOrphanEffectsForSessionAndType(
- audio_session_t sessionId, const effect_uuid_t* effectType) const {
- if (effectType == nullptr) {
- return hasOrphansForSession(sessionId);
- }
-
- for (size_t i = 0; i < size(); ++i) {
- sp<EffectDescriptor> effect = valueAt(i);
- if (effect->mIsOrphan && effect->mSession == sessionId &&
- memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0) {
+ if (effect->mSession == sessionId && effect->mIsOrphan &&
+ (effectType == nullptr ||
+ memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0)) {
return true;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
index ae99191..cd54626 100644
--- a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
@@ -20,6 +20,7 @@
#include "PolicyAudioPort.h"
#include "HwModule.h"
#include <policy.h>
+#include <system/audio.h>
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 406bc4f..b04aff0 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -143,7 +143,8 @@
}
break;
case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
- if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_NONE) {
+ if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_BT_BLE
+ && config != AUDIO_POLICY_FORCE_NONE) {
ALOGW("setForceUse() invalid config %d for VIBRATE_RINGING", config);
return BAD_VALUE;
}
@@ -402,6 +403,40 @@
}
}
}
+
+ // if LEA headset is connected and we are told to use it, play ringtone over
+ // speaker and BT LEA
+ if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllBleSet()).isEmpty()) {
+ DeviceVector devices2;
+ devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_BLE_HEADSET, AUDIO_DEVICE_OUT_BLE_SPEAKER});
+ // Use ONLY Bluetooth LEA output when ringing in vibration mode
+ if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+ && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
+ if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
+ == AUDIO_POLICY_FORCE_BT_BLE) {
+ if (!devices2.isEmpty()) {
+ devices = devices2;
+ break;
+ }
+ }
+ }
+ // Use both Bluetooth LEA and phone default output when ringing in normal mode
+ if (audio_is_ble_out_device(getPreferredDeviceTypeForLegacyStrategy(
+ availableOutputDevices, STRATEGY_PHONE))) {
+ if (strategy == STRATEGY_SONIFICATION) {
+ devices.replaceDevicesByType(
+ AUDIO_DEVICE_OUT_SPEAKER,
+ availableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_SPEAKER_SAFE));
+ }
+ if (!devices2.isEmpty()) {
+ devices.add(devices2);
+ break;
+ }
+ }
+ }
+
// The second device used for sonification is the same as the device used by media strategy
FALLTHROUGH_INTENDED;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 07073c7..41bf68e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -374,6 +374,7 @@
checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, 0);
mpClientInterface->onAudioPortListUpdate();
+ ALOGV("%s() completed for device: %s", __func__, device->toString().c_str());
return NO_ERROR;
} // end if is output device
@@ -389,6 +390,8 @@
return INVALID_OPERATION;
}
+ ALOGV("%s() connecting device %s", __func__, device->toString().c_str());
+
if (mAvailableInputDevices.add(device) < 0) {
return NO_MEMORY;
}
@@ -461,6 +464,7 @@
}
mpClientInterface->onAudioPortListUpdate();
+ ALOGV("%s() completed for device: %s", __func__, device->toString().c_str());
return NO_ERROR;
} // end if is input device
@@ -1551,7 +1555,7 @@
(config->channel_mask == desc->getChannelMask()) &&
(session == desc->mDirectClientSession)) {
desc->mDirectOpenCount++;
- ALOGV("%s reusing direct output %d for session %d", __func__,
+ ALOGI("%s reusing direct output %d for session %d", __func__,
mOutputs.keyAt(i), session);
*output = mOutputs.keyAt(i);
return NO_ERROR;
@@ -1561,17 +1565,23 @@
if (!profile->canOpenNewIo()) {
if (!com::android::media::audioserver::direct_track_reprioritization()) {
+ ALOGW("%s profile %s can't open new output maxOpenCount reached", __func__,
+ profile->getName().c_str());
return NAME_NOT_FOUND;
} else if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0) {
// MMAP gracefully handles lack of an exclusive track resource by mixing
// above the audio framework. For AAudio to know that the limit is reached,
// return an error.
+ ALOGW("%s profile %s can't open new mmap output maxOpenCount reached", __func__,
+ profile->getName().c_str());
return NAME_NOT_FOUND;
} else {
// Close outputs on this profile, if available, to free resources for this request
for (int i = 0; i < mOutputs.size() && !profile->canOpenNewIo(); i++) {
const auto desc = mOutputs.valueAt(i);
if (desc->mProfile == profile) {
+ ALOGV("%s closeOutput %d to prioritize session %d on profile %s", __func__,
+ desc->mIoHandle, session, profile->getName().c_str());
closeOutput(desc->mIoHandle);
}
}
@@ -1580,6 +1590,8 @@
// Unable to close streams to find free resources for this request
if (!profile->canOpenNewIo()) {
+ ALOGW("%s profile %s can't open new output maxOpenCount reached", __func__,
+ profile->getName().c_str());
return NAME_NOT_FOUND;
}
@@ -2133,8 +2145,7 @@
// matching criteria values in priority order for best matching output so far
std::vector<uint32_t> bestMatchCriteria(8, 0);
- const bool hasOrphanHaptic =
- mEffects.hasOrphanEffectsForSessionAndType(sessionId, FX_IID_HAPTICGENERATOR);
+ const bool hasOrphanHaptic = mEffects.hasOrphansForSession(sessionId, FX_IID_HAPTICGENERATOR);
const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
@@ -3426,8 +3437,8 @@
ALOGW("%s: no group for stream %s, bailing out", __func__, toString(stream).c_str());
return NO_ERROR;
}
- ALOGV("%s: stream %s attributes=%s", __func__,
- toString(stream).c_str(), toString(attributes).c_str());
+ ALOGV("%s: stream %s attributes=%s, index %d , device 0x%X", __func__,
+ toString(stream).c_str(), toString(attributes).c_str(), index, device);
return setVolumeIndexForAttributes(attributes, index, device);
}
@@ -3586,7 +3597,9 @@
if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
isVoiceVolSrc, isBtScoVolSrc, __func__)
&& (isVoiceVolSrc || isBtScoVolSrc)) {
- setVoiceVolume(index, curves, isVoiceVolSrc, 0);
+ bool voiceVolumeManagedByHost = isVoiceVolSrc &&
+ !audio_is_ble_out_device(mCallRxSourceClient->sinkDevice()->type());
+ setVoiceVolume(index, curves, voiceVolumeManagedByHost, 0);
}
}
@@ -3603,8 +3616,8 @@
bool hasVoice = hasVoiceStream(volumeCurves.getStreamTypes());
if (((index < volumeCurves.getVolumeIndexMin()) && !(hasVoice && index == 0)) ||
(index > volumeCurves.getVolumeIndexMax())) {
- ALOGD("%s: wrong index %d min=%d max=%d", __FUNCTION__, index,
- volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax());
+ ALOGE("%s: wrong index %d min=%d max=%d, device 0x%X", __FUNCTION__, index,
+ volumeCurves.getVolumeIndexMin(), volumeCurves.getVolumeIndexMax(), device);
return BAD_VALUE;
}
if (!audio_is_output_device(device)) {
@@ -6282,7 +6295,7 @@
// means haptic use cases (either the client channelmask includes haptic bits, or created a
// HapticGenerator effect for this session) are not supported.
return clientHapticChannel == 0 &&
- !mEffects.hasOrphanEffectsForSessionAndType(sessionId, FX_IID_HAPTICGENERATOR);
+ !mEffects.hasOrphansForSession(sessionId, FX_IID_HAPTICGENERATOR);
}
}
@@ -6574,6 +6587,14 @@
if (!mConfig->getOutputDevices().contains(supportedDevice)) {
continue;
}
+
+ if (outProfile->isMmap() && !outProfile->hasDynamicAudioProfile()
+ && availProfileDevices.areAllDevicesAttached()) {
+ ALOGV("%s skip opening output for mmap profile %s", __func__,
+ outProfile->getTagName().c_str());
+ continue;
+ }
+
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
@@ -6633,6 +6654,14 @@
__func__, inProfile->getTagName().c_str());
continue;
}
+
+ if (inProfile->isMmap() && !inProfile->hasDynamicAudioProfile()
+ && availProfileDevices.areAllDevicesAttached()) {
+ ALOGV("%s skip opening input for mmap profile %s", __func__,
+ inProfile->getTagName().c_str());
+ continue;
+ }
+
sp<AudioInputDescriptor> inputDesc =
new AudioInputDescriptor(inProfile, mpClientInterface);
@@ -6640,12 +6669,12 @@
status_t status = inputDesc->open(nullptr,
availProfileDevices.itemAt(0),
AUDIO_SOURCE_MIC,
- AUDIO_INPUT_FLAG_NONE,
+ (audio_input_flags_t) inProfile->getFlags(),
&input);
if (status != NO_ERROR) {
- ALOGW("Cannot open input stream for device %s on hw module %s",
- availProfileDevices.toString().c_str(),
- hwModule->getName());
+ ALOGW("%s: Cannot open input stream for device %s for profile %s on hw module %s",
+ __func__, availProfileDevices.toString().c_str(),
+ inProfile->getTagName().c_str(), hwModule->getName());
continue;
}
for (const auto &device : availProfileDevices) {
@@ -6753,8 +6782,8 @@
sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
if (profile->supportsDevice(device)) {
profiles.add(profile);
- ALOGV("checkOutputsForDevice(): adding profile %zu from module %s",
- j, hwModule->getName());
+ ALOGV("%s(): adding profile %s from module %s",
+ __func__, profile->getTagName().c_str(), hwModule->getName());
}
}
}
@@ -6787,7 +6816,11 @@
if (j != outputs.size()) {
continue;
}
-
+ if (profile->isMmap() && !profile->hasDynamicAudioProfile()) {
+ ALOGV("%s skip opening output for mmap profile %s",
+ __func__, profile->getTagName().c_str());
+ continue;
+ }
if (!profile->canOpenNewIo()) {
ALOGW("Max Output number %u already opened for this profile %s",
profile->maxOpenCount, profile->getTagName().c_str());
@@ -6848,9 +6881,8 @@
if (!profile->supportsDevice(device)) {
continue;
}
- ALOGV("checkOutputsForDevice(): "
- "clearing direct output profile %zu on module %s",
- j, hwModule->getName());
+ ALOGV("%s(): clearing direct output profile %s on module %s",
+ __func__, profile->getTagName().c_str(), hwModule->getName());
profile->clearAudioProfiles();
if (!profile->hasDynamicAudioProfile()) {
continue;
@@ -6905,8 +6937,8 @@
if (profile->supportsDevice(device)) {
profiles.add(profile);
- ALOGV("checkInputsForDevice(): adding profile %zu from module %s",
- profile_index, hwModule->getName());
+ ALOGV("%s : adding profile %s from module %s", __func__,
+ profile->getTagName().c_str(), hwModule->getName());
}
}
}
@@ -6938,15 +6970,22 @@
continue;
}
+ if (profile->isMmap() && !profile->hasDynamicAudioProfile()) {
+ ALOGV("%s skip opening input for mmap profile %s",
+ __func__, profile->getTagName().c_str());
+ continue;
+ }
if (!profile->canOpenNewIo()) {
- ALOGW("Max Input number %u already opened for this profile %s",
- profile->maxOpenCount, profile->getTagName().c_str());
+ ALOGW("%s Max Input number %u already opened for this profile %s",
+ __func__, profile->maxOpenCount, profile->getTagName().c_str());
continue;
}
desc = new AudioInputDescriptor(profile, mpClientInterface);
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
- status = desc->open(nullptr, device, AUDIO_SOURCE_MIC, AUDIO_INPUT_FLAG_NONE, &input);
+ ALOGV("%s opening input for profile %s", __func__, profile->getTagName().c_str());
+ status = desc->open(nullptr, device, AUDIO_SOURCE_MIC,
+ (audio_input_flags_t) profile->getFlags(), &input);
if (status == NO_ERROR) {
const String8& address = String8(device->address().c_str());
@@ -6957,7 +6996,8 @@
}
updateAudioProfiles(device, input, profile);
if (!profile->hasValidAudioProfile()) {
- ALOGW("checkInputsForDevice() direct input missing param");
+ ALOGW("%s direct input missing param for profile %s", __func__,
+ profile->getTagName().c_str());
desc->close();
input = AUDIO_IO_HANDLE_NONE;
}
@@ -6968,18 +7008,20 @@
} // endif input != 0
if (input == AUDIO_IO_HANDLE_NONE) {
- ALOGW("%s could not open input for device %s", __func__,
- device->toString().c_str());
+ ALOGW("%s could not open input for device %s on profile %s", __func__,
+ device->toString().c_str(), profile->getTagName().c_str());
profiles.removeAt(profile_index);
profile_index--;
} else {
if (audio_device_is_digital(device->type())) {
device->importAudioPortAndPickAudioProfile(profile);
}
- ALOGV("checkInputsForDevice(): adding input %d", input);
+ ALOGV("%s: adding input %d for profile %s", __func__,
+ input, profile->getTagName().c_str());
if (checkCloseInput(desc)) {
- ALOGV("%s closing input %d", __func__, input);
+ ALOGV("%s: closing input %d for profile %s", __func__,
+ input, profile->getTagName().c_str());
closeInput(input);
}
}
@@ -6998,8 +7040,8 @@
profile_index++) {
sp<IOProfile> profile = hwModule->getInputProfiles()[profile_index];
if (profile->supportsDevice(device)) {
- ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %s",
- profile_index, hwModule->getName());
+ ALOGV("%s: clearing direct input profile %s on module %s", __func__,
+ profile->getTagName().c_str(), hwModule->getName());
profile->clearAudioProfiles();
}
}
@@ -8269,9 +8311,10 @@
float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
if (outputDesc->isFixedVolume(deviceTypes) ||
- // Force VoIP volume to max for bluetooth SCO device except if muted
+ // Force VoIP volume to max for bluetooth SCO/BLE device except if muted
(index != 0 && (isVoiceVolSrc || isBtScoVolSrc) &&
- isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
+ (isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device)
+ || isSingleDeviceType(deviceTypes, audio_is_ble_out_device)))) {
volumeDb = 0.0f;
}
const bool muted = (index == 0) && (volumeDb != 0.0f);
@@ -8279,17 +8322,19 @@
deviceTypes, delayMs, force, isVoiceVolSrc);
if (outputDesc == mPrimaryOutput && (isVoiceVolSrc || isBtScoVolSrc)) {
- setVoiceVolume(index, curves, isVoiceVolSrc, delayMs);
+ bool voiceVolumeManagedByHost = isVoiceVolSrc &&
+ !isSingleDeviceType(deviceTypes, audio_is_ble_out_device);
+ setVoiceVolume(index, curves, voiceVolumeManagedByHost, delayMs);
}
return NO_ERROR;
}
void AudioPolicyManager::setVoiceVolume(
- int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs) {
+ int index, IVolumeCurves &curves, bool voiceVolumeManagedByHost, int delayMs) {
float voiceVolume;
- // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed
+ // Force voice volume to max or mute for Bluetooth SCO/BLE as other attenuations are managed
// by the headset
- if (isVoiceVolSrc) {
+ if (voiceVolumeManagedByHost) {
voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
} else {
voiceVolume = index == 0 ? 0.0 : 1.0;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 2990099..fcba9bc 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -295,7 +295,7 @@
}
List<const CameraDeviceBase::PhysicalCameraSettingsList> metadataRequestList;
- std::list<const SurfaceMap> surfaceMapList;
+ std::list<SurfaceMap> surfaceMapList;
submitInfo->mRequestId = mRequestIdCounter;
uint32_t loopCounter = 0;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 225d7f5..c995cbe 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1588,7 +1588,7 @@
// The chrome plane could be either Cb first, or Cr first. Take the
// smaller address.
uint8_t *src = std::min(yuvBuffer.dataCb, yuvBuffer.dataCr);
- MediaImage2::PlaneIndex dstPlane = codecUvOffsetDiff > 0 ? MediaImage2::U : MediaImage2::V;
+ MediaImage2::PlaneIndex dstPlane = codecUPlaneFirst ? MediaImage2::U : MediaImage2::V;
for (auto row = top/2; row < (top+height)/2; row++) {
uint8_t *dst = codecBuffer->data() + imageInfo->mPlane[dstPlane].mOffset +
imageInfo->mPlane[dstPlane].mRowInc * (row - top/2);
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index cfc41c3..aceb5c0 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -136,7 +136,7 @@
* Output lastFrameNumber is the expected last frame number of the list of requests.
*/
virtual status_t captureList(const List<const PhysicalCameraSettingsList> &requests,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber = NULL) = 0;
/**
@@ -152,7 +152,7 @@
* Output lastFrameNumber is the last frame number of the previous streaming request.
*/
virtual status_t setStreamingRequestList(const List<const PhysicalCameraSettingsList> &requests,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber = NULL) = 0;
/**
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 97cfdac..9f6829c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -720,7 +720,7 @@
status_t Camera3Device::convertMetadataListToRequestListLocked(
const List<const PhysicalCameraSettingsList> &metadataList,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
bool repeating, nsecs_t requestTimeNs,
RequestList *requestList) {
if (requestList == NULL) {
@@ -730,7 +730,7 @@
int32_t burstId = 0;
List<const PhysicalCameraSettingsList>::const_iterator metadataIt = metadataList.begin();
- std::list<const SurfaceMap>::const_iterator surfaceMapIt = surfaceMaps.begin();
+ std::list<SurfaceMap>::const_iterator surfaceMapIt = surfaceMaps.begin();
for (; metadataIt != metadataList.end() && surfaceMapIt != surfaceMaps.end();
++metadataIt, ++surfaceMapIt) {
sp<CaptureRequest> newRequest = setUpRequestLocked(*metadataIt, *surfaceMapIt);
@@ -778,14 +778,14 @@
ATRACE_CALL();
List<const PhysicalCameraSettingsList> requestsList;
- std::list<const SurfaceMap> surfaceMaps;
+ std::list<SurfaceMap> surfaceMaps;
convertToRequestList(requestsList, surfaceMaps, request);
return captureList(requestsList, surfaceMaps, lastFrameNumber);
}
void Camera3Device::convertToRequestList(List<const PhysicalCameraSettingsList>& requestsList,
- std::list<const SurfaceMap>& surfaceMaps,
+ std::list<SurfaceMap>& surfaceMaps,
const CameraMetadata& request) {
PhysicalCameraSettingsList requestList;
requestList.push_back({getId(), request});
@@ -803,7 +803,7 @@
status_t Camera3Device::submitRequestsHelper(
const List<const PhysicalCameraSettingsList> &requests,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
bool repeating,
/*out*/
int64_t *lastFrameNumber) {
@@ -851,7 +851,7 @@
}
status_t Camera3Device::captureList(const List<const PhysicalCameraSettingsList> &requestsList,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber) {
ATRACE_CALL();
@@ -863,7 +863,7 @@
ATRACE_CALL();
List<const PhysicalCameraSettingsList> requestsList;
- std::list<const SurfaceMap> surfaceMaps;
+ std::list<SurfaceMap> surfaceMaps;
convertToRequestList(requestsList, surfaceMaps, request);
return setStreamingRequestList(requestsList, /*surfaceMap*/surfaceMaps,
@@ -872,7 +872,7 @@
status_t Camera3Device::setStreamingRequestList(
const List<const PhysicalCameraSettingsList> &requestsList,
- const std::list<const SurfaceMap> &surfaceMaps, int64_t *lastFrameNumber) {
+ const std::list<SurfaceMap> &surfaceMaps, int64_t *lastFrameNumber) {
ATRACE_CALL();
return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/true, lastFrameNumber);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 9f414e8..62ae38c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -132,12 +132,12 @@
// idle state
status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL) override;
status_t captureList(const List<const PhysicalCameraSettingsList> &requestsList,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber = NULL) override;
status_t setStreamingRequest(const CameraMetadata &request,
int64_t *lastFrameNumber = NULL) override;
status_t setStreamingRequestList(const List<const PhysicalCameraSettingsList> &requestsList,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
int64_t *lastFrameNumber = NULL) override;
status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL) override;
@@ -703,17 +703,17 @@
status_t convertMetadataListToRequestListLocked(
const List<const PhysicalCameraSettingsList> &metadataList,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
bool repeating, nsecs_t requestTimeNs,
/*out*/
RequestList *requestList);
void convertToRequestList(List<const PhysicalCameraSettingsList>& requestsList,
- std::list<const SurfaceMap>& surfaceMaps,
+ std::list<SurfaceMap>& surfaceMaps,
const CameraMetadata& request);
status_t submitRequestsHelper(const List<const PhysicalCameraSettingsList> &requestsList,
- const std::list<const SurfaceMap> &surfaceMaps,
+ const std::list<SurfaceMap> &surfaceMaps,
bool repeating,
int64_t *lastFrameNumber = NULL);
diff --git a/services/camera/libcameraservice/fuzzer/Android.bp b/services/camera/libcameraservice/fuzzer/Android.bp
index 7760f6a..667ba02 100644
--- a/services/camera/libcameraservice/fuzzer/Android.bp
+++ b/services/camera/libcameraservice/fuzzer/Android.bp
@@ -26,7 +26,18 @@
cc_defaults {
name: "libcameraservice_fuzz_defaults",
fuzz_config: {
- componentid: 41727
+ cc: [
+ "android-camera-fwk-eng@google.com",
+ ],
+ componentid: 41727,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libcameraservice",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
@@ -37,9 +48,9 @@
"DistortionMapperFuzzer.cpp",
],
shared_libs: [
- "libcameraservice",
+ "camera_platform_flags_c_lib",
"libcamera_client",
- "camera_platform_flags_c_lib"
+ "libcameraservice",
],
}
@@ -50,8 +61,8 @@
"DepthProcessorFuzzer.cpp",
],
shared_libs: [
+ "camera_platform_flags_c_lib",
"libcameraservice",
- "camera_platform_flags_c_lib"
],
corpus: ["corpus/*.jpg"],
}
diff --git a/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp b/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
index 650ca91..5c5e177 100644
--- a/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
+++ b/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
@@ -14,49 +14,92 @@
* limitations under the License.
*/
-#include <array>
-#include <vector>
+#include "common/DepthPhotoProcessor.h"
+
+#include <random>
#include <fuzzer/FuzzedDataProvider.h>
-#include "common/DepthPhotoProcessor.h"
-
using namespace android;
using namespace android::camera3;
-static const size_t kTestBufferWidth = 640;
-static const size_t kTestBufferHeight = 480;
-static const size_t kTestBufferDepthSize (kTestBufferWidth * kTestBufferHeight);
+static const float kMinRatio = 0.1f;
+static const float kMaxRatio = 0.9f;
-void generateDepth16Buffer(const uint8_t* data, size_t size, std::array<uint16_t, kTestBufferDepthSize> *depth16Buffer /*out*/) {
- FuzzedDataProvider dataProvider(data, size);
- for (size_t i = 0; i < depth16Buffer->size(); i++) {
- (*depth16Buffer)[i] = dataProvider.ConsumeIntegral<uint16_t>();
+static const uint8_t kTotalDepthJpegBufferCount = 3;
+static const uint8_t kIntrinsicCalibrationSize = 5;
+static const uint8_t kLensDistortionSize = 5;
+
+static const DepthPhotoOrientation kDepthPhotoOrientations[] = {
+ DepthPhotoOrientation::DEPTH_ORIENTATION_0_DEGREES,
+ DepthPhotoOrientation::DEPTH_ORIENTATION_90_DEGREES,
+ DepthPhotoOrientation::DEPTH_ORIENTATION_180_DEGREES,
+ DepthPhotoOrientation::DEPTH_ORIENTATION_270_DEGREES};
+
+void generateDepth16Buffer(std::vector<uint16_t>* depth16Buffer /*out*/, size_t length,
+ FuzzedDataProvider& fdp) {
+ std::default_random_engine gen(fdp.ConsumeIntegral<uint8_t>());
+ std::uniform_int_distribution uniDist(0, UINT16_MAX - 1);
+ for (size_t i = 0; i < length; ++i) {
+ (*depth16Buffer)[i] = uniDist(gen);
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
DepthPhotoInputFrame inputFrame;
+
+ /**
+ * Consuming 80% of the data to set mMainJpegBuffer. This ensures that we
+ * don't completely exhaust data and use the rest 20% for fuzzing of APIs.
+ */
+ std::vector<uint8_t> buffer = fdp.ConsumeBytes<uint8_t>((size * 80) / 100);
+ inputFrame.mMainJpegBuffer = reinterpret_cast<const char*>(buffer.data());
+
+ /**
+ * Calculate height and width based on buffer size and a ratio within [0.1, 0.9].
+ * The ratio adjusts the dimensions while maintaining a relationship to the total buffer size.
+ */
+ const float ratio = fdp.ConsumeFloatingPointInRange<float>(kMinRatio, kMaxRatio);
+ const size_t height = std::sqrt(buffer.size()) * ratio;
+ const size_t width = std::sqrt(buffer.size()) / ratio;
+
+ inputFrame.mMainJpegHeight = height;
+ inputFrame.mMainJpegWidth = width;
+ inputFrame.mMainJpegSize = buffer.size();
// Worst case both depth and confidence maps have the same size as the main color image.
- inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
+ inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * kTotalDepthJpegBufferCount;
+
+ std::vector<uint16_t> depth16Buffer(height * width);
+ generateDepth16Buffer(&depth16Buffer, height * width, fdp);
+ inputFrame.mDepthMapBuffer = depth16Buffer.data();
+ inputFrame.mDepthMapHeight = height;
+ inputFrame.mDepthMapWidth = inputFrame.mDepthMapStride = width;
+
+ inputFrame.mIsLogical = fdp.ConsumeBool();
+
+ inputFrame.mOrientation = fdp.PickValueInArray<DepthPhotoOrientation>(kDepthPhotoOrientations);
+
+ if (fdp.ConsumeBool()) {
+ for (uint8_t i = 0; i < kIntrinsicCalibrationSize; ++i) {
+ inputFrame.mIntrinsicCalibration[i] = fdp.ConsumeFloatingPoint<float>();
+ }
+ inputFrame.mIsIntrinsicCalibrationValid = 1;
+ }
+
+ if (fdp.ConsumeBool()) {
+ for (uint8_t i = 0; i < kLensDistortionSize; ++i) {
+ inputFrame.mLensDistortion[i] = fdp.ConsumeFloatingPoint<float>();
+ }
+ inputFrame.mIsLensDistortionValid = 1;
+ }
std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
size_t actualDepthPhotoSize = 0;
- std::array<uint16_t, kTestBufferDepthSize> depth16Buffer;
- generateDepth16Buffer(data, size, &depth16Buffer);
+ processDepthPhotoFrame(inputFrame, depthPhotoBuffer.size(), depthPhotoBuffer.data(),
+ &actualDepthPhotoSize);
- inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (data);
- inputFrame.mMainJpegSize = size;
- inputFrame.mDepthMapBuffer = depth16Buffer.data();
- inputFrame.mDepthMapStride = kTestBufferWidth;
- inputFrame.mDepthMapWidth = kTestBufferWidth;
- inputFrame.mDepthMapHeight = kTestBufferHeight;
- processDepthPhotoFrame(
- inputFrame,
- depthPhotoBuffer.size(),
- depthPhotoBuffer.data(),
- &actualDepthPhotoSize);
-
- return 0;
+ return 0;
}
diff --git a/services/camera/virtualcamera/util/JpegUtil.h b/services/camera/virtualcamera/util/JpegUtil.h
index 184dd56..0a8df90 100644
--- a/services/camera/virtualcamera/util/JpegUtil.h
+++ b/services/camera/virtualcamera/util/JpegUtil.h
@@ -18,6 +18,7 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_JPEGUTIL_H
#include <optional>
+#include <vector>
#include "android/hardware_buffer.h"
#include "util/Util.h"
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 41efce0..92f0745 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -85,5 +85,6 @@
getegid32: 1
getgroups32: 1
sysinfo: 1
+setsockopt: 1
@include /apex/com.android.media.swcodec/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp b/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp
index d329e54..2b31de7 100644
--- a/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp
+++ b/services/mediaextractor/fuzzers/MediaExtractorServiceFuzzer.cpp
@@ -22,6 +22,7 @@
using ::android::MediaExtractorService;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ signal(SIGPIPE, SIG_IGN);
auto service = sp<MediaExtractorService>::make();
fuzzService(service, FuzzedDataProvider(data, size));
return 0;
diff --git a/services/mediametrics/include/mediametricsservice/TimedAction.h b/services/mediametrics/include/mediametricsservice/TimedAction.h
index 8b53ded..8901ced 100644
--- a/services/mediametrics/include/mediametricsservice/TimedAction.h
+++ b/services/mediametrics/include/mediametricsservice/TimedAction.h
@@ -81,9 +81,8 @@
void threadLoop() NO_THREAD_SAFETY_ANALYSIS { // thread safety doesn't cover unique_lock
std::unique_lock l(mLock);
while (!mQuit) {
- auto sleepUntilTime = std::chrono::time_point<TimerClock>::max();
if (!mMap.empty()) {
- sleepUntilTime = mMap.begin()->first;
+ auto sleepUntilTime = mMap.begin()->first;
const auto now = TimerClock::now();
if (sleepUntilTime <= now) {
auto node = mMap.extract(mMap.begin()); // removes from mMap.
@@ -96,8 +95,17 @@
// of REALTIME specification, use kWakeupInterval to ensure minimum
// granularity if suspended.
sleepUntilTime = std::min(sleepUntilTime, now + kWakeupInterval);
+ mCondition.wait_until(l, sleepUntilTime);
+ } else {
+ // As TimerClock is system_clock (which is not monotonic), libcxx's
+ // implementation of condition_variable::wait_until(l, std::chrono::time_point)
+ // recalculates the 'until' time into the wait duration and then goes back to the
+ // absolute timestamp when calling pthread_cond_timedwait(); this back-and-forth
+ // calculation sometimes loses the 'max' value because enough time passes in
+ // between, and instead passes incorrect timestamp into the syscall, causing a
+ // crash. Mitigating it by explicitly calling the non-timed wait here.
+ mCondition.wait(l);
}
- mCondition.wait_until(l, sleepUntilTime);
}
}
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 5dfec30..ac41959 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -30,7 +30,7 @@
"server_configurable_flags",
],
defaults: [
- "aconfig_lib_cc_static_link.defaults",
+ "aconfig_lib_cc_shared_link.defaults",
],
include_dirs: [
"frameworks/av/include",
@@ -84,6 +84,9 @@
"libactivitymanager_aidl",
"server_configurable_flags",
],
+ defaults: [
+ "aconfig_lib_cc_shared_link.defaults",
+ ],
include_dirs: [
"frameworks/av/include",
"frameworks/av/services/mediaresourcemanager",