Merge "audio policy: fix LE audio input device selection." into tm-dev
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 42b3c43..0acf7d7 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -1502,6 +1502,7 @@
igbp = new B2HGraphicBufferProducer2(surface);
}
+ std::scoped_lock lock(mOutputMutex);
std::shared_ptr<SurfaceSyncObj> syncObj;
if (!surface) {
@@ -1586,6 +1587,24 @@
mOutputBufferQueue->updateMaxDequeueBufferCount(maxDequeueCount);
}
+void Codec2Client::Component::stopUsingOutputSurface(
+ C2BlockPool::local_id_t blockPoolId) {
+ std::scoped_lock lock(mOutputMutex);
+ mOutputBufferQueue->stop();
+ Return<Status> transStatus = mBase1_0->setOutputSurface(
+ static_cast<uint64_t>(blockPoolId), nullptr);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
+ } else {
+ c2_status_t status =
+ static_cast<c2_status_t>(static_cast<Status>(transStatus));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "setOutputSurface(stopUsingOutputSurface) -- call failed: "
+ << status << ".";
+ }
+ }
+}
+
c2_status_t Codec2Client::Component::connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
std::shared_ptr<InputSurfaceConnection>* connection) {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 347e58a..49d9b28 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -411,6 +411,10 @@
// Set max dequeue count for output surface.
void setOutputSurfaceMaxDequeueCount(int maxDequeueCount);
+ // Stop using the current output surface.
+ void stopUsingOutputSurface(
+ C2BlockPool::local_id_t blockPoolId);
+
// Connect to a given InputSurface.
c2_status_t connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
@@ -441,6 +445,11 @@
struct OutputBufferQueue;
std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
+ // (b/202903117) Sometimes MediaCodec::setSurface races between normal
+ // setSurface and setSurface with ReleaseSurface due to timing issues.
+ // In order to prevent the race condition mutex is added.
+ std::mutex mOutputMutex;
+
static c2_status_t setDeathListener(
const std::shared_ptr<Component>& component,
const std::shared_ptr<Listener>& listener);
diff --git a/media/codec2/hidl/client/include/codec2/hidl/output.h b/media/codec2/hidl/client/include/codec2/hidl/output.h
index 877148a..a13edf3 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/output.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/output.h
@@ -50,6 +50,10 @@
int maxDequeueBufferCount,
std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);
+ // Stop using the current output surface. Pending buffer opeations will not
+ // perform anymore.
+ void stop();
+
// Render a graphic block to current surface.
status_t outputBuffer(
const C2ConstGraphicBlock& block,
@@ -81,6 +85,7 @@
sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
+ bool mStopped;
bool registerBuffer(const C2ConstGraphicBlock& block);
};
diff --git a/media/codec2/hidl/client/output.cpp b/media/codec2/hidl/client/output.cpp
index de34c24..f789030 100644
--- a/media/codec2/hidl/client/output.cpp
+++ b/media/codec2/hidl/client/output.cpp
@@ -169,7 +169,7 @@
} // unnamed namespace
OutputBufferQueue::OutputBufferQueue()
- : mGeneration{0}, mBqId{0} {
+ : mGeneration{0}, mBqId{0}, mStopped{false} {
}
OutputBufferQueue::~OutputBufferQueue() {
@@ -219,6 +219,8 @@
poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
{
std::scoped_lock<std::mutex> l(mMutex);
+ bool stopped = mStopped;
+ mStopped = false;
if (generation == mGeneration) {
// case of old BlockPool destruction
C2SyncVariables *var = mSyncMem ? mSyncMem->mem() : nullptr;
@@ -258,7 +260,7 @@
return false;
}
for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
- if (mBqId == 0 || !mBuffers[i]) {
+ if (mBqId == 0 || !mBuffers[i] || stopped) {
continue;
}
std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
@@ -317,6 +319,12 @@
return true;
}
+void OutputBufferQueue::stop() {
+ std::scoped_lock<std::mutex> l(mMutex);
+ mStopped = true;
+ mOwner.reset(); // destructor of the block will not triger IGBP::cancel()
+}
+
bool OutputBufferQueue::registerBuffer(const C2ConstGraphicBlock& block) {
std::shared_ptr<_C2BlockPoolData> data =
_C2BlockFactory::GetGraphicBlockPoolData(block);
@@ -325,7 +333,7 @@
}
std::scoped_lock<std::mutex> l(mMutex);
- if (!mIgbp) {
+ if (!mIgbp || mStopped) {
return false;
}
@@ -371,11 +379,17 @@
std::shared_ptr<C2SurfaceSyncMemory> syncMem;
mMutex.lock();
+ bool stopped = mStopped;
sp<IGraphicBufferProducer> outputIgbp = mIgbp;
uint32_t outputGeneration = mGeneration;
syncMem = mSyncMem;
mMutex.unlock();
+ if (stopped) {
+ LOG(INFO) << "outputBuffer -- already stopped.";
+ return DEAD_OBJECT;
+ }
+
status_t status = attachToBufferQueue(
block, outputIgbp, outputGeneration, &bqSlot, syncMem);
@@ -408,12 +422,18 @@
std::shared_ptr<C2SurfaceSyncMemory> syncMem;
mMutex.lock();
+ bool stopped = mStopped;
sp<IGraphicBufferProducer> outputIgbp = mIgbp;
uint32_t outputGeneration = mGeneration;
uint64_t outputBqId = mBqId;
syncMem = mSyncMem;
mMutex.unlock();
+ if (stopped) {
+ LOG(INFO) << "outputBuffer -- already stopped.";
+ return DEAD_OBJECT;
+ }
+
if (!outputIgbp) {
LOG(VERBOSE) << "outputBuffer -- output surface is null.";
return NO_INIT;
@@ -467,7 +487,7 @@
mMutex.lock();
mMaxDequeueBufferCount = maxDequeueBufferCount;
auto syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
- if (syncVar) {
+ if (syncVar && !mStopped) {
syncVar->lock();
syncVar->updateMaxDequeueCountLocked(maxDequeueBufferCount);
syncVar->unlock();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 62a1d02..159e885 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1570,6 +1570,14 @@
Mutexed<Output>::Locked output(mOutput);
output->buffers.reset();
}
+ if (mOutputSurface.lock()->surface) {
+ C2BlockPool::local_id_t outputPoolId;
+ {
+ Mutexed<BlockPools>::Locked pools(mBlockPools);
+ outputPoolId = pools->outputPoolId;
+ }
+ mComponent->stopUsingOutputSurface(outputPoolId);
+ }
}
void CCodecBufferChannel::release() {
diff --git a/media/codec2/vndk/include/C2BqBufferPriv.h b/media/codec2/vndk/include/C2BqBufferPriv.h
index bec978a..29aad5e 100644
--- a/media/codec2/vndk/include/C2BqBufferPriv.h
+++ b/media/codec2/vndk/include/C2BqBufferPriv.h
@@ -129,8 +129,9 @@
// Create a local BlockPoolData.
C2BufferQueueBlockPoolData(
uint32_t generation, uint64_t bqId, int32_t bqSlot,
+ const std::shared_ptr<int> &owner,
const android::sp<HGraphicBufferProducer>& producer,
- std::shared_ptr<C2SurfaceSyncMemory>, int noUse);
+ std::shared_ptr<C2SurfaceSyncMemory>);
virtual ~C2BufferQueueBlockPoolData() override;
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 63b0f39..e67e42f 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -542,7 +542,7 @@
std::make_shared<C2BufferQueueBlockPoolData>(
slotBuffer->getGenerationNumber(),
mProducerId, slot,
- mProducer, mSyncMem, 0);
+ mIgbpValidityToken, mProducer, mSyncMem);
mPoolDatas[slot] = poolData;
*block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
return C2_OK;
@@ -572,10 +572,11 @@
Impl(const std::shared_ptr<C2Allocator> &allocator)
: mInit(C2_OK), mProducerId(0), mGeneration(0),
mConsumerUsage(0), mDqFailure(0), mLastDqTs(0),
- mLastDqLogTs(0), mAllocator(allocator) {
+ mLastDqLogTs(0), mAllocator(allocator), mIgbpValidityToken(std::make_shared<int>(0)) {
}
~Impl() {
+ mIgbpValidityToken.reset();
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
mBuffers[i].clear();
}
@@ -618,7 +619,7 @@
}
std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
std::make_shared<C2BufferQueueBlockPoolData>(
- 0, (uint64_t)0, ~0, nullptr, nullptr, 0);
+ 0, (uint64_t)0, ~0, nullptr, nullptr, nullptr);
*block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
ALOGV("allocated a buffer successfully");
@@ -694,8 +695,7 @@
mProducer = nullptr;
mProducerId = 0;
mGeneration = 0;
- ALOGW("invalid producer producer(%d), generation(%d)",
- (bool)producer, bqInformation);
+ ALOGD("configuring null producer: igbp_information(%d)", bqInformation);
}
oldMem = mSyncMem; // preven destruction while locked.
mSyncMem = c2SyncMem;
@@ -720,6 +720,10 @@
}
}
}
+ } else {
+ // old buffers should not be cancelled since the associated IGBP
+ // is no longer valid.
+ mIgbpValidityToken = std::make_shared<int>(0);
}
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
mBuffers[i] = buffers[i];
@@ -761,6 +765,20 @@
std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
+
+ // IGBP invalidation notification token.
+ // The buffers(C2BufferQueueBlockPoolData) has the reference to the IGBP where
+ // they belong in order to call IGBP::cancelBuffer() when they are of no use.
+ //
+ // In certain cases, IGBP is no longer used by this class(actually MediaCodec)
+ // any more and the situation needs to be addressed quickly. In order to
+ // achieve those, std::shared_ptr<> is used as a token for quick IGBP invalidation
+ // notification from the buffers.
+ //
+ // The buffer side will have the reference of the token as std::weak_ptr<>.
+ // if the token has been expired, the buffers will not call IGBP::cancelBuffer()
+ // when they are no longer used.
+ std::shared_ptr<int> mIgbpValidityToken;
};
C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
@@ -776,14 +794,14 @@
C2BufferQueueBlockPoolData::C2BufferQueueBlockPoolData(
uint32_t generation, uint64_t bqId, int32_t bqSlot,
+ const std::shared_ptr<int>& owner,
const android::sp<HGraphicBufferProducer>& producer,
- std::shared_ptr<C2SurfaceSyncMemory> syncMem, int noUse) :
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem) :
mLocal(true), mHeld(true),
mGeneration(generation), mBqId(bqId), mBqSlot(bqSlot),
mCurrentGeneration(generation), mCurrentBqId(bqId),
mTransfer(false), mAttach(false), mDisplay(false),
- mIgbp(producer), mSyncMem(syncMem) {
- (void)noUse;
+ mOwner(owner), mIgbp(producer), mSyncMem(syncMem) {
}
C2BufferQueueBlockPoolData::~C2BufferQueueBlockPoolData() {
@@ -792,7 +810,7 @@
}
if (mLocal) {
- if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId) {
+ if (mGeneration == mCurrentGeneration && mBqId == mCurrentBqId && !mOwner.expired()) {
C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
if (syncVar) {
syncVar->lock();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 36f8e10..6ab8339 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -728,11 +728,13 @@
// (b) we can support re-creation of offloaded tracks
if (offloadInfo != NULL) {
mOffloadInfoCopy = *offloadInfo;
- mOffloadInfo = &mOffloadInfoCopy;
} else {
- mOffloadInfo = NULL;
memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
mOffloadInfoCopy = AUDIO_INFO_INITIALIZER;
+ mOffloadInfoCopy.format = format;
+ mOffloadInfoCopy.sample_rate = sampleRate;
+ mOffloadInfoCopy.channel_mask = channelMask;
+ mOffloadInfoCopy.stream_type = streamType;
}
mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
diff --git a/media/libaudioclient/include/media/AidlConversionUtil.h b/media/libaudioclient/include/media/AidlConversionUtil.h
index 820b7cb..9f294cb 100644
--- a/media/libaudioclient/include/media/AidlConversionUtil.h
+++ b/media/libaudioclient/include/media/AidlConversionUtil.h
@@ -20,6 +20,7 @@
#include <type_traits>
#include <utility>
+#include <binder/Enums.h>
#include <binder/Status.h>
#include <error/Result.h>
@@ -270,6 +271,15 @@
namespace aidl_utils {
/**
+ * Return true if the value is valid for the AIDL enumeration.
+ */
+template <typename T>
+bool isValidEnum(T value) {
+ constexpr android::enum_range<T> er{};
+ return std::find(er.begin(), er.end(), value) != er.end();
+}
+
+/**
* Return the equivalent Android status_t from a binder exception code.
*
* Generally one should use statusTFromBinderStatus() instead.
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 1cf6ef9..9f540e6 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1344,7 +1344,6 @@
sp<IMemory> mSharedBuffer;
transfer_type mTransfer;
audio_offload_info_t mOffloadInfoCopy;
- const audio_offload_info_t* mOffloadInfo;
audio_attributes_t mAttributes;
size_t mFrameSize; // frame size in bytes
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 40a1eaa..8eefe77 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -571,12 +571,6 @@
lHalConfig.offload_info.channel_mask = lHalConfig.channel_mask;
lHalConfig.offload_info.format = lHalConfig.format;
lHalConfig.offload_info.stream_type = stream;
- lHalConfig.offload_info.duration_us = -1;
- lHalConfig.offload_info.has_video = true; // conservative
- lHalConfig.offload_info.is_streaming = true; // likely
- lHalConfig.offload_info.encapsulation_mode = lHalConfig.offload_info.encapsulation_mode;
- lHalConfig.offload_info.content_id = lHalConfig.offload_info.content_id;
- lHalConfig.offload_info.sync_id = lHalConfig.offload_info.sync_id;
}
audio_config_base_t lMixerConfig;
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index ef11072..9baaf93 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -214,21 +214,79 @@
status_t status = getHalParameter<false>(effect, SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED,
&supportsHeadTracking);
if (status != NO_ERROR) {
+ ALOGW("%s: cannot get SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED", __func__);
return status;
}
mSupportsHeadTracking = supportsHeadTracking[0];
- status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_LEVELS, &mLevels);
+ std::vector<media::SpatializationLevel> spatializationLevels;
+ status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_LEVELS,
+ &spatializationLevels);
if (status != NO_ERROR) {
+ ALOGW("%s: cannot get SPATIALIZER_PARAM_SUPPORTED_LEVELS", __func__);
return status;
}
+ bool noneLevelFound = false;
+ bool activeLevelFound = false;
+ for (const auto spatializationLevel : spatializationLevels) {
+ if (!aidl_utils::isValidEnum(spatializationLevel)) {
+ ALOGW("%s: ignoring spatializationLevel:%d", __func__, (int)spatializationLevel);
+ continue;
+ }
+ if (spatializationLevel == media::SpatializationLevel::NONE) {
+ noneLevelFound = true;
+ } else {
+ activeLevelFound = true;
+ }
+ // we don't detect duplicates.
+ mLevels.emplace_back(spatializationLevel);
+ }
+ if (!noneLevelFound || !activeLevelFound) {
+ ALOGW("%s: SPATIALIZER_PARAM_SUPPORTED_LEVELS must include NONE"
+ " and another valid level", __func__);
+ return BAD_VALUE;
+ }
+
+ std::vector<media::SpatializationMode> spatializationModes;
status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES,
- &mSpatializationModes);
+ &spatializationModes);
if (status != NO_ERROR) {
+ ALOGW("%s: cannot get SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES", __func__);
return status;
}
- return getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
- &mChannelMasks);
+ for (const auto spatializationMode : spatializationModes) {
+ if (!aidl_utils::isValidEnum(spatializationMode)) {
+ ALOGW("%s: ignoring spatializationMode:%d", __func__, (int)spatializationMode);
+ continue;
+ }
+ // we don't detect duplicates.
+ mSpatializationModes.emplace_back(spatializationMode);
+ }
+ if (mSpatializationModes.empty()) {
+ ALOGW("%s: SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES reports empty", __func__);
+ return BAD_VALUE;
+ }
+
+ std::vector<audio_channel_mask_t> channelMasks;
+ status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
+ &channelMasks);
+ if (status != NO_ERROR) {
+ ALOGW("%s: cannot get SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS", __func__);
+ return status;
+ }
+ for (const auto channelMask : channelMasks) {
+ if (!audio_is_channel_mask_spatialized(channelMask)) {
+ ALOGW("%s: ignoring channelMask:%#x", __func__, channelMask);
+ continue;
+ }
+ // we don't detect duplicates.
+ mChannelMasks.emplace_back(channelMask);
+ }
+ if (mChannelMasks.empty()) {
+ ALOGW("%s: SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS reports empty", __func__);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
}
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
@@ -238,8 +296,10 @@
// For now use highest supported channel count
uint32_t maxCount = 0;
for ( auto mask : mChannelMasks) {
- if (audio_channel_count_from_out_mask(mask) > maxCount) {
+ const size_t count = audio_channel_count_from_out_mask(mask);
+ if (count > maxCount) {
config.channel_mask = mask;
+ maxCount = count;
}
}
return config;
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 493696b..e98975e 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -92,9 +92,9 @@
"gui/RingBufferConsumer.cpp",
"hidl/AidlCameraDeviceCallbacks.cpp",
"hidl/AidlCameraServiceListener.cpp",
- "hidl/Convert.cpp",
"hidl/HidlCameraDeviceUser.cpp",
"hidl/HidlCameraService.cpp",
+ "hidl/Utils.cpp",
"utils/CameraServiceProxyWrapper.cpp",
"utils/CameraThreadState.cpp",
"utils/CameraTraces.cpp",
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index b5d0746..add1483 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -89,9 +89,10 @@
if (strlen(camera_stream::physical_camera_id) > 0) {
lines.appendFormat(" Physical camera id: %s\n", camera_stream::physical_camera_id);
}
- lines.appendFormat(" Dynamic Range Profile: 0x%" PRIx64,
+ lines.appendFormat(" Dynamic Range Profile: 0x%" PRIx64 "\n",
camera_stream::dynamic_range_profile);
lines.appendFormat(" Stream use case: %" PRId64 "\n", camera_stream::use_case);
+ lines.appendFormat(" Timestamp base: %d\n", getTimestampBase());
lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n",
mFrameCount, mLastTimestamp);
lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n",
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index b21322c..1ce7108 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -460,8 +460,8 @@
}
if (mPreviewFrameSpacer != nullptr) {
- res = mPreviewFrameSpacer->queuePreviewBuffer(timestamp - mTimestampOffset, transform,
- anwBuffer, anwReleaseFence);
+ res = mPreviewFrameSpacer->queuePreviewBuffer(timestamp - mTimestampOffset,
+ readoutTimestamp - mTimestampOffset, transform, anwBuffer, anwReleaseFence);
if (res != OK) {
ALOGE("%s: Stream %d: Error queuing buffer to preview buffer spacer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -680,12 +680,15 @@
bool forceChoreographer = (timestampBase ==
OutputConfiguration::TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED);
bool defaultToChoreographer = (isDefaultTimeBase &&
- isConsumedByHWComposer() &&
- !property_get_bool("camera.disable_preview_scheduler", false));
+ isConsumedByHWComposer());
+ bool defaultToSpacer = (isDefaultTimeBase &&
+ isConsumedByHWTexture() &&
+ !isConsumedByCPU() &&
+ !isVideoStream());
if (forceChoreographer || defaultToChoreographer) {
mSyncToDisplay = true;
mTotalBufferCount += kDisplaySyncExtraBuffer;
- } else if (isConsumedByHWTexture() && !isVideoStream()) {
+ } else if (defaultToSpacer) {
mPreviewFrameSpacer = new PreviewFrameSpacer(*this, mConsumer);
mTotalBufferCount ++;
res = mPreviewFrameSpacer->run(String8::format("PreviewSpacer-%d", mId).string());
@@ -1260,6 +1263,17 @@
return (usage & GRALLOC_USAGE_HW_TEXTURE) != 0;
}
+bool Camera3OutputStream::isConsumedByCPU() const {
+ uint64_t usage = 0;
+ status_t res = getEndpointUsage(&usage);
+ if (res != OK) {
+ ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+ return false;
+ }
+
+ return (usage & GRALLOC_USAGE_SW_READ_MASK) != 0;
+}
+
void Camera3OutputStream::dumpImageToDisk(nsecs_t timestamp,
ANativeWindowBuffer* anwBuffer, int fence) {
// Deriver output file name
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 45e995d..5f2831f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -160,6 +160,11 @@
bool isConsumedByHWTexture() const;
/**
+ * Return if this output stream is consumed by CPU.
+ */
+ bool isConsumedByCPU() const;
+
+ /**
* Return if the consumer configuration of this stream is deferred.
*/
virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
index 9112b93..496580f 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.cpp
@@ -36,12 +36,12 @@
Thread::requestExitAndWait();
}
-status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
- ANativeWindowBuffer* anwBuffer, int releaseFence) {
+status_t PreviewFrameSpacer::queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
+ int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence) {
Mutex::Autolock l(mLock);
- mPendingBuffers.emplace(timestamp, transform, anwBuffer, releaseFence);
- ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64, __FUNCTION__,
- mPendingBuffers.size(), timestamp);
+ mPendingBuffers.emplace(timestamp, readoutTimestamp, transform, anwBuffer, releaseFence);
+ ALOGV("%s: mPendingBuffers size %zu, timestamp %" PRId64 ", readoutTime %" PRId64,
+ __FUNCTION__, mPendingBuffers.size(), timestamp, readoutTimestamp);
mBufferCond.signal();
return OK;
@@ -56,17 +56,17 @@
nsecs_t currentTime = systemTime();
auto buffer = mPendingBuffers.front();
- nsecs_t captureInterval = buffer.timestamp - mLastCameraCaptureTime;
- // If the capture interval exceeds threshold, directly queue
+ nsecs_t readoutInterval = buffer.readoutTimestamp - mLastCameraReadoutTime;
+ // If the readout interval exceeds threshold, directly queue
// cached buffer.
- if (captureInterval >= kFrameIntervalThreshold) {
+ if (readoutInterval >= kFrameIntervalThreshold) {
mPendingBuffers.pop();
queueBufferToClientLocked(buffer, currentTime);
return true;
}
- // Cache the frame to match capture time interval, for up to 33ms
- nsecs_t expectedQueueTime = mLastCameraPresentTime + captureInterval;
+ // Cache the frame to match readout time interval, for up to 33ms
+ nsecs_t expectedQueueTime = mLastCameraPresentTime + readoutInterval;
nsecs_t frameWaitTime = std::min(kMaxFrameWaitTime, expectedQueueTime - currentTime);
if (frameWaitTime > 0 && mPendingBuffers.size() < 2) {
mBufferCond.waitRelative(mLock, frameWaitTime);
@@ -75,8 +75,8 @@
}
currentTime = systemTime();
}
- ALOGV("%s: captureInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
- ", timestamp %" PRId64, __FUNCTION__, captureInterval,
+ ALOGV("%s: readoutInterval %" PRId64 ", queueInterval %" PRId64 ", waited for %" PRId64
+ ", timestamp %" PRId64, __FUNCTION__, readoutInterval,
currentTime - mLastCameraPresentTime, frameWaitTime, buffer.timestamp);
mPendingBuffers.pop();
queueBufferToClientLocked(buffer, currentTime);
@@ -114,7 +114,7 @@
}
mLastCameraPresentTime = currentTime;
- mLastCameraCaptureTime = bufferHolder.timestamp;
+ mLastCameraReadoutTime = bufferHolder.readoutTimestamp;
}
}; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
index 5062553..fb0a563 100644
--- a/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
+++ b/services/camera/libcameraservice/device3/PreviewFrameSpacer.h
@@ -42,8 +42,8 @@
*
* The PreviewFrameSpacer improves the viewfinder user experience by:
* - Cache the frame buffers if the intervals between queueBuffer is shorter
- * than the camera capture intervals.
- * - Queue frame buffers in the same cadence as the camera capture time.
+ * than the camera readout intervals.
+ * - Queue frame buffers in the same cadence as the camera readout time.
* - Maintain at most 1 queue-able buffer. If the 2nd preview buffer becomes
* available, queue the oldest cached buffer to the buffer queue.
*/
@@ -53,8 +53,8 @@
virtual ~PreviewFrameSpacer();
// Queue preview buffer locally
- status_t queuePreviewBuffer(nsecs_t timestamp, int32_t transform,
- ANativeWindowBuffer* anwBuffer, int releaseFence);
+ status_t queuePreviewBuffer(nsecs_t timestamp, nsecs_t readoutTimestamp,
+ int32_t transform, ANativeWindowBuffer* anwBuffer, int releaseFence);
bool threadLoop() override;
void requestExit() override;
@@ -63,12 +63,14 @@
// structure holding cached preview buffer info
struct BufferHolder {
nsecs_t timestamp;
+ nsecs_t readoutTimestamp;
int32_t transform;
sp<ANativeWindowBuffer> anwBuffer;
int releaseFence;
- BufferHolder(nsecs_t t, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
- timestamp(t), transform(tr), anwBuffer(anwb), releaseFence(rf) {}
+ BufferHolder(nsecs_t t, nsecs_t readoutT, int32_t tr, ANativeWindowBuffer* anwb, int rf) :
+ timestamp(t), readoutTimestamp(readoutT), transform(tr), anwBuffer(anwb),
+ releaseFence(rf) {}
};
void queueBufferToClientLocked(const BufferHolder& bufferHolder, nsecs_t currentTime);
@@ -80,7 +82,7 @@
Condition mBufferCond;
std::queue<BufferHolder> mPendingBuffers;
- nsecs_t mLastCameraCaptureTime = 0;
+ nsecs_t mLastCameraReadoutTime = 0;
nsecs_t mLastCameraPresentTime = 0;
static constexpr nsecs_t kWaitDuration = 5000000LL; // 50ms
static constexpr nsecs_t kFrameIntervalThreshold = 80000000LL; // 80ms
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
index f063506..3392db1 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
@@ -16,7 +16,7 @@
#include <hardware/camera.h>
#include <hidl/AidlCameraDeviceCallbacks.h>
-#include <hidl/Convert.h>
+#include <hidl/Utils.h>
namespace android {
namespace frameworks {
@@ -34,7 +34,7 @@
H2BCameraDeviceCallbacks::H2BCameraDeviceCallbacks(const sp<HalInterface>& base) : CBase(base) { }
-bool H2BCameraDeviceCallbacks::initializeLooper() {
+bool H2BCameraDeviceCallbacks::initializeLooper(int vndkVersion) {
mCbLooper = new ALooper;
mCbLooper->setName("cs-looper");
status_t err = mCbLooper->start(/*runOnCallingThread*/ false, /*canCallJava*/ false,
@@ -43,7 +43,7 @@
ALOGE("Unable to start camera device callback looper");
return false;
}
- mHandler = new CallbackHandler(this);
+ mHandler = new CallbackHandler(this, vndkVersion);
mCbLooper->registerHandler(mHandler);
return true;
}
@@ -144,6 +144,12 @@
// Convert Metadata into HCameraMetadata;
FmqSizeOrMetadata hResult;
+ using hardware::cameraservice::utils::conversion::filterVndkKeys;
+ if (filterVndkKeys(mVndkVersion, result, /*isStatic*/false) != OK) {
+ ALOGE("%s: filtering vndk keys from result failed, not sending onResultReceived callback",
+ __FUNCTION__);
+ return;
+ }
const camera_metadata_t *rawMetadata = result.getAndLock();
converter->convertResultMetadataToHidl(rawMetadata, &hResult);
result.unlock(rawMetadata);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
index dbf520a..152002b 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.h
@@ -61,7 +61,7 @@
~H2BCameraDeviceCallbacks();
- bool initializeLooper();
+ bool initializeLooper(int vndkVersion);
virtual binder::Status onDeviceError(int32_t errorCode,
const CaptureResultExtras& resultExtras) override;
@@ -103,10 +103,12 @@
struct CallbackHandler : public AHandler {
public:
void onMessageReceived(const sp<AMessage> &msg) override;
- CallbackHandler(H2BCameraDeviceCallbacks *converter) : mConverter(converter) { }
+ CallbackHandler(H2BCameraDeviceCallbacks *converter, int vndkVersion) :
+ mConverter(converter), mVndkVersion(vndkVersion) { }
private:
void processResultMessage(sp<ResultWrapper> &resultWrapper);
wp<H2BCameraDeviceCallbacks> mConverter = nullptr;
+ int mVndkVersion = -1;
Mutex mMetadataQueueLock;
};
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
index cca3f2e..add9121 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.cpp
@@ -15,7 +15,7 @@
*/
#include <hidl/AidlCameraServiceListener.h>
-#include <hidl/Convert.h>
+#include <hidl/Utils.h>
namespace android {
namespace frameworks {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index 2509e6c..26e813a 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -20,8 +20,8 @@
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <hidl/AidlCameraDeviceCallbacks.h>
-#include <hidl/Convert.h>
#include <hidl/HidlCameraDeviceUser.h>
+#include <hidl/Utils.h>
#include <android/hardware/camera/device/3.2/types.h>
namespace android {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index a812587..65a0300 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#include <hidl/Convert.h>
+#include <android-base/properties.h>
-#include <hidl/HidlCameraService.h>
-
-#include <hidl/HidlCameraDeviceUser.h>
#include <hidl/AidlCameraDeviceCallbacks.h>
#include <hidl/AidlCameraServiceListener.h>
+#include <hidl/HidlCameraService.h>
+#include <hidl/HidlCameraDeviceUser.h>
+#include <hidl/Utils.h>
#include <hidl/HidlTransportSupport.h>
@@ -34,6 +34,7 @@
using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
using hardware::hidl_vec;
using hardware::cameraservice::utils::conversion::convertToHidl;
+using hardware::cameraservice::utils::conversion::filterVndkKeys;
using hardware::cameraservice::utils::conversion::B2HStatus;
using hardware::Void;
@@ -53,6 +54,10 @@
return gHidlCameraService;
}
+HidlCameraService::HidlCameraService(android::CameraService *cs) : mAidlICameraService(cs) {
+ mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
+};
+
Return<void>
HidlCameraService::getCameraCharacteristics(const hidl_string& cameraId,
getCameraCharacteristics_cb _hidl_cb) {
@@ -77,6 +82,11 @@
_hidl_cb(status, hidlMetadata);
return Void();
}
+ if (filterVndkKeys(mVndkVersion, cameraMetadata) != OK) {
+ ALOGE("%s: Unable to filter vndk metadata keys for version %d", __FUNCTION__, mVndkVersion);
+ _hidl_cb(HStatus::UNKNOWN_ERROR, hidlMetadata);
+ return Void();
+ }
const camera_metadata_t *rawMetadata = cameraMetadata.getAndLock();
convertToHidl(rawMetadata, &hidlMetadata);
_hidl_cb(status, hidlMetadata);
@@ -97,7 +107,7 @@
// Create a hardware::camera2::ICameraDeviceCallback object which internally
// calls callback functions passed through hCallback.
sp<H2BCameraDeviceCallbacks> hybridCallbacks = new H2BCameraDeviceCallbacks(hCallback);
- if (!hybridCallbacks->initializeLooper()) {
+ if (!hybridCallbacks->initializeLooper(mVndkVersion)) {
ALOGE("Unable to handle callbacks on device, cannot connect");
_hidl_cb(HStatus::UNKNOWN_ERROR, nullptr);
return Void();
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.h b/services/camera/libcameraservice/hidl/HidlCameraService.h
index 86a7cec..1c8145c 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.h
@@ -75,7 +75,7 @@
static sp<HidlCameraService> getInstance(android::CameraService *cs);
private:
- HidlCameraService(android::CameraService *cs) : mAidlICameraService(cs) { };
+ HidlCameraService(android::CameraService *cs);
sp<hardware::ICameraServiceListener> searchListenerCacheLocked(
sp<HCameraServiceListener> listener, /*removeIfFound*/ bool shouldRemove = false);
@@ -95,6 +95,7 @@
using HIListeners =
std::pair<sp<HCameraServiceListener>, sp<ICameraServiceListener>>;
std::list<HIListeners> mListeners;
+ int mVndkVersion = -1;
};
} // namespace implementation
diff --git a/services/camera/libcameraservice/hidl/Convert.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
similarity index 92%
rename from services/camera/libcameraservice/hidl/Convert.cpp
rename to services/camera/libcameraservice/hidl/Utils.cpp
index 597147b..057a6e9 100644
--- a/services/camera/libcameraservice/hidl/Convert.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#include <hidl/Convert.h>
+#include <hidl/Utils.h>
+#include <hidl/VndkVersionMetadataTags.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <cutils/native_handle.h>
#include <mediautils/AImageReaderUtils.h>
@@ -297,6 +298,31 @@
return hPhysicalCaptureResultInfos;
}
+status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic) {
+ if (vndkVersion == __ANDROID_API_FUTURE__) {
+ // VNDK version in ro.vndk.version is a version code-name that
+ // corresponds to the current version.
+ return OK;
+ }
+ const auto &apiLevelToKeys =
+ isStatic ? static_api_level_to_keys : dynamic_api_level_to_keys;
+ // Find the vndk versions above the given vndk version. All the vndk
+ // versions above the given one, need to have their keys filtered from the
+ // metadata in order to avoid metadata invalidation.
+ auto it = apiLevelToKeys.upper_bound(vndkVersion);
+ while (it != apiLevelToKeys.end()) {
+ for (const auto &key : it->second) {
+ status_t res = metadata.erase(key);
+ if (res != OK) {
+ ALOGE("%s metadata key %d could not be erased", __FUNCTION__, key);
+ return res;
+ }
+ }
+ it++;
+ }
+ return OK;
+}
+
} //conversion
} // utils
} //cameraservice
diff --git a/services/camera/libcameraservice/hidl/Convert.h b/services/camera/libcameraservice/hidl/Utils.h
similarity index 96%
rename from services/camera/libcameraservice/hidl/Convert.h
rename to services/camera/libcameraservice/hidl/Utils.h
index 82ffc48..e6d4393 100644
--- a/services/camera/libcameraservice/hidl/Convert.h
+++ b/services/camera/libcameraservice/hidl/Utils.h
@@ -29,6 +29,7 @@
#include <android/hardware/camera2/ICameraDeviceUser.h>
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
#include <android/hardware/ICameraService.h>
+#include <camera/CameraMetadata.h>
#include <fmq/MessageQueue.h>
#include <hardware/camera.h>
#include <hidl/MQDescriptor.h>
@@ -96,6 +97,8 @@
HStatus B2HStatus(const binder::Status &bStatus);
+status_t filterVndkKeys(int vndk_version, CameraMetadata &metadata, bool isStatic = true);
+
} // conversion
} // utils
} // cameraservice
diff --git a/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h
new file mode 100644
index 0000000..d3377f4
--- /dev/null
+++ b/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <vector>
+#pragma once
+/**
+ * ! Do not edit this file directly !
+ *
+ * Generated automatically from vndk_camera_metadata_tags.mako. To be included in libcameraservice
+ * only by hidl/Utils.cpp.
+ */
+
+/**
+ * API level to static keys mapping. To be used for filtering out keys depending on vndk version
+ * used by vendor clients.
+ */
+std::map<int, std::vector<camera_metadata_tag>> static_api_level_to_keys{
+ {30, {
+ ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES,
+ ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+ ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
+ ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+ } },
+ {31, {
+ ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION,
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED,
+ ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION,
+ ANDROID_SCALER_DEFAULT_SECURE_IMAGE_SIZE,
+ ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION,
+ ANDROID_SENSOR_INFO_BINNING_FACTOR,
+ } },
+ {32, {
+ ANDROID_INFO_DEVICE_STATE_ORIENTATIONS,
+ } },
+ {33, {
+ ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+ ANDROID_AUTOMOTIVE_LENS_FACING,
+ ANDROID_AUTOMOTIVE_LOCATION,
+ ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP,
+ ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
+ } },
+};
+
+/**
+ * API level to dynamic keys mapping. To be used for filtering out keys depending on vndk version
+ * used by vendor clients.
+ */
+std::map<int, std::vector<camera_metadata_tag>> dynamic_api_level_to_keys{
+ {30, {
+ ANDROID_CONTROL_ZOOM_RATIO,
+ ANDROID_SCALER_ROTATE_AND_CROP,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE,
+ } },
+ {31, {
+ ANDROID_SENSOR_PIXEL_MODE,
+ ANDROID_SENSOR_RAW_BINNING_FACTOR_USED,
+ } },
+};