Merge "Camera: Remove flag 'surface_leak_fix'" into main
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index ddfcc43..bdec8c9 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -27,13 +27,6 @@
flag {
namespace: "camera_platform"
- name: "watch_foreground_changes"
- description: "Request AppOps to notify changes in the foreground status of the client"
- bug: "290086710"
-}
-
-flag {
- namespace: "camera_platform"
name: "camera_manual_flash_strength_control"
is_exported: true
description: "Flash brightness level control in manual flash mode"
@@ -42,20 +35,6 @@
flag {
namespace: "camera_platform"
- name: "lazy_aidl_wait_for_service"
- description: "Use waitForService instead of getService with lazy AIDL HALs"
- bug: "285546208"
-}
-
-flag {
- namespace: "camera_platform"
- name: "log_zoom_override_usage"
- description: "Enable measuring how much usage there is for zoom settings overrde"
- bug: "307409002"
-}
-
-flag {
- namespace: "camera_platform"
name: "session_hal_buf_manager"
description: "Enable or disable HAL buffer manager as requested by the camera HAL"
bug: "311263114"
@@ -130,16 +109,6 @@
flag {
namespace: "camera_platform"
- name: "surface_ipc"
- description: "Optimize Surface binder IPC"
- bug: "323292530"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
name: "extension_10_bit"
is_exported: true
description: "Enables 10-bit support in the camera extensions."
@@ -148,16 +117,6 @@
flag {
namespace: "camera_platform"
- name: "single_thread_executor"
- description: "Ensure device logic is run within one thread."
- bug: "305857746"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
name: "single_thread_executor_naming"
description: "Set the device executor thread name."
bug: "359709863"
@@ -213,16 +172,6 @@
flag {
namespace: "camera_platform"
- name: "realtime_priority_bump"
- description: "Bump the scheduling priority of performance critical code paths"
- bug: "336628522"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
name: "use_system_api_for_vndk_version"
description: "ro.board.api_level isn't reliable. Use system api to replace ro.vndk.version"
bug: "312315580"
@@ -269,4 +218,11 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "enable_hal_abort_from_cameraservicewatchdog"
+ description: "Enable CameraServiceWatchdog to abort camera HAL to generate HAL tombstones"
+ bug: "349652177"
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
index 1bb3da6..079e075 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -86,7 +86,7 @@
],
srcs: ["Service.cpp"],
init_rc: ["android.hardware.drm-service.clearkey.rc"],
- vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+ vintf_fragment_modules: ["android.hardware.drm-service.clearkey.xml_vintf"],
}
cc_binary {
@@ -98,7 +98,13 @@
overrides: ["android.hardware.drm-service.clearkey"],
srcs: ["ServiceLazy.cpp"],
init_rc: ["android.hardware.drm-service-lazy.clearkey.rc"],
- vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+ vintf_fragment_modules: ["android.hardware.drm-service.clearkey.xml_vintf"],
+}
+
+vintf_fragment {
+ name: "android.hardware.drm-service.clearkey.xml_vintf",
+ src: "android.hardware.drm-service.clearkey.xml",
+ vendor: true,
}
cc_binary {
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index 356bf72..de9332b 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -153,6 +153,13 @@
mParamReflectors.push_back(paramReflector);
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -240,11 +247,9 @@
// param reflectors. Currently filters work on video domain only,
// and the MultiAccessUnitHelper is only enabled on audio domain;
// thus we pass the component's param reflector, which is mParamReflectors[0].
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index b2158a6..de0f566 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -120,6 +120,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index f09e232..108ba06 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
+
// Retrieve supported parameters from store
using namespace std::placeholders;
mInit = mConfigurable->init(mParameterCache);
@@ -231,12 +239,9 @@
}
}
if (!isComponentSupportsLargeAudioFrame) {
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
-
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index 44b8ec1..847c90c 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -124,6 +124,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index 009a326..84f5d26 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
+
// Retrieve supported parameters from store
using namespace std::placeholders;
mInit = mConfigurable->init(mParameterCache);
@@ -230,13 +238,10 @@
break;
}
}
-
if (!isComponentSupportsLargeAudioFrame) {
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
index 52d2945..9028149 100644
--- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -132,6 +132,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index 89f71a9..5585be8 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
+
// Retrieve supported parameters from store
using namespace std::placeholders;
mInit = mConfigurable->init(mParameterCache);
@@ -231,11 +239,9 @@
}
}
if (!isComponentSupportsLargeAudioFrame) {
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
index 1b209e2..4fd260b 100644
--- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
@@ -139,6 +139,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index 47412b7..34872f0 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -856,21 +856,31 @@
C2String getName() const override { return "android.sample.filter-plugin-store"; }
c2_status_t createComponent(
C2String name, std::shared_ptr<C2Component>* const component) override {
- if (mFactories.count(name) == 0) {
+ auto it = std::find_if(
+ mFactories.begin(), mFactories.end(),
+ [&name](const std::unique_ptr<ComponentFactory> &factory) {
+ return name == factory->getTraits()->name;
+ });
+ if (it == mFactories.end()) {
return C2_BAD_VALUE;
}
- return mFactories.at(name)->createComponent(++mNodeId, component);
+ return (*it)->createComponent(++mNodeId, component);
}
c2_status_t createInterface(
C2String name, std::shared_ptr<C2ComponentInterface>* const interface) override {
- if (mFactories.count(name) == 0) {
+ auto it = std::find_if(
+ mFactories.begin(), mFactories.end(),
+ [&name](const std::unique_ptr<ComponentFactory> &factory) {
+ return name == factory->getTraits()->name;
+ });
+ if (it == mFactories.end()) {
return C2_BAD_VALUE;
}
- return mFactories.at(name)->createInterface(++mNodeId, interface);
+ return (*it)->createInterface(++mNodeId, interface);
}
std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override {
std::vector<std::shared_ptr<const C2Component::Traits>> ret;
- for (const auto &[name, factory] : mFactories) {
+ for (const auto &factory : mFactories) {
ret.push_back(factory->getTraits());
}
return ret;
@@ -951,20 +961,18 @@
template <class T>
static void AddFactory(
- std::map<C2String, std::unique_ptr<ComponentFactory>> *factories,
+ std::vector<std::unique_ptr<ComponentFactory>> *factories,
const std::shared_ptr<C2ReflectorHelper> &reflector) {
std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0, reflector)};
std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
<< "Failed to fill traits from interface";
- factories->emplace(
- traits->name,
- new ComponentFactoryImpl<T>(traits, reflector));
+ factories->emplace_back(new ComponentFactoryImpl<T>(traits, reflector));
}
- static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
+ static std::vector<std::unique_ptr<ComponentFactory>> CreateFactories(
const std::shared_ptr<C2ReflectorHelper> &reflector) {
- std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
+ std::vector<std::unique_ptr<ComponentFactory>> factories;
AddFactory<SampleToneMappingFilter>(&factories, reflector);
return factories;
}
@@ -977,7 +985,7 @@
}
} mIntf;
- const std::map<C2String, std::unique_ptr<ComponentFactory>> mFactories;
+ const std::vector<std::unique_ptr<ComponentFactory>> mFactories;
std::atomic_int32_t mNodeId{0};
};
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index d829523..1cbfc75 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -228,17 +228,23 @@
status_t CCodecBufferChannel::setInputSurface(
const std::shared_ptr<InputSurfaceWrapper> &surface) {
ALOGV("[%s] setInputSurface", mName);
- Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
- *inputSurface = surface;
- return (*inputSurface)->connect(mComponent);
+ if (!surface) {
+ ALOGE("[%s] setInputSurface: surface must not be null", mName);
+ return BAD_VALUE;
+ }
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ inputSurface->numProcessingBuffersBalance = 0;
+ inputSurface->surface = surface;
+ mHasInputSurface = true;
+ return inputSurface->surface->connect(mComponent);
}
status_t CCodecBufferChannel::signalEndOfInputStream() {
- Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
- if ((*inputSurface) == nullptr) {
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ if (inputSurface->surface == nullptr) {
return INVALID_OPERATION;
}
- return (*inputSurface)->signalEndOfInputStream();
+ return inputSurface->surface->signalEndOfInputStream();
}
status_t CCodecBufferChannel::queueInputBufferInternal(
@@ -1063,19 +1069,36 @@
if (mInputMetEos) {
return;
}
- {
+ int64_t numOutputSlots = 0;
+ bool outputFull = [this, &numOutputSlots]() {
Mutexed<Output>::Locked output(mOutput);
- if (!output->buffers ||
- output->buffers->hasPending() ||
+ if (!output->buffers) {
+ ALOGV("[%s] feedInputBufferIfAvailableInternal: "
+ "return because output buffers are null", mName);
+ return true;
+ }
+ numOutputSlots = int64_t(output->numSlots);
+ if (output->buffers->hasPending() ||
(!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
- return;
+ ALOGV("[%s] feedInputBufferIfAvailableInternal: "
+ "return because there are no room for more output buffers", mName);
+ return true;
+ }
+ return false;
+ }();
+ if (android::media::codec::provider_->input_surface_throttle()) {
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ if (inputSurface->surface) {
+ if (inputSurface->numProcessingBuffersBalance <= numOutputSlots) {
+ ++inputSurface->numProcessingBuffersBalance;
+ ALOGV("[%s] feedInputBufferIfAvailableInternal: numProcessingBuffersBalance = %lld",
+ mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
+ inputSurface->surface->onInputBufferEmptied();
+ }
}
}
- if (android::media::codec::provider_->input_surface_throttle()) {
- Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
- if ((*inputSurface) != nullptr) {
- (*inputSurface)->onInputBufferEmptied();
- }
+ if (outputFull) {
+ return;
}
size_t numActiveSlots = 0;
while (!mPipelineWatcher.lock()->pipelineFull()) {
@@ -1704,7 +1727,7 @@
&& (hasCryptoOrDescrambler() || conforming)) {
input->buffers.reset(new SlotInputBuffers(mName));
} else if (graphic) {
- if (mInputSurface.lock()->get()) {
+ if (mHasInputSurface) {
input->buffers.reset(new DummyInputBuffers(mName));
} else if (mMetaMode == MODE_ANW) {
input->buffers.reset(new GraphicMetadataInputBuffers(mName));
@@ -1987,7 +2010,7 @@
status_t CCodecBufferChannel::prepareInitialInputBuffers(
std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
- if (mInputSurface.lock()->get()) {
+ if (mHasInputSurface) {
return OK;
}
@@ -2113,9 +2136,13 @@
void CCodecBufferChannel::reset() {
stop();
- mInputSurface.lock()->reset();
mPipelineWatcher.lock()->flush();
{
+ mHasInputSurface = false;
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ inputSurface->surface.reset();
+ }
+ {
Mutexed<Input>::Locked input(mInput);
input->buffers.reset(new DummyInputBuffers(""));
input->extraBuffers.flush();
@@ -2208,9 +2235,6 @@
void CCodecBufferChannel::onInputBufferDone(
uint64_t frameIndex, size_t arrayIndex) {
- if (mInputSurface.lock()->get()) {
- return;
- }
std::shared_ptr<C2Buffer> buffer =
mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
bool newInputSlotAvailable = false;
@@ -2265,8 +2289,7 @@
notifyClient = false;
}
- bool hasInputSurface = (mInputSurface.lock()->get() != nullptr);
- if (!hasInputSurface && (work->worklets.size() != 1u
+ if (!mHasInputSurface && (work->worklets.size() != 1u
|| !work->worklets.front()
|| !(work->worklets.front()->output.flags &
C2FrameData::FLAG_INCOMPLETE))) {
@@ -2475,7 +2498,7 @@
c2_cntr64_t timestamp =
worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
- work->input.ordinal.timestamp;
- if (hasInputSurface) {
+ if (mHasInputSurface) {
// When using input surface we need to restore the original input timestamp.
timestamp = work->input.ordinal.customOrdinal;
}
@@ -2625,14 +2648,20 @@
bufferMetadata->m.values[nMeta];
flag = convertFlags(bufferMetadataStruct.flags, false);
accessUnitInfos.emplace_back(flag,
- static_cast<size_t>(bufferMetadataStruct.size),
- static_cast<size_t>(bufferMetadataStruct.timestamp));
+ bufferMetadataStruct.size,
+ bufferMetadataStruct.timestamp);
}
sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
outBuffer->meta()->setObject("accessUnitInfo", obj);
}
}
+ if (mHasInputSurface && android::media::codec::provider_->input_surface_throttle()) {
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ --inputSurface->numProcessingBuffersBalance;
+ ALOGV("[%s] onOutputBufferAvailable: numProcessingBuffersBalance = %lld",
+ mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
+ }
mCallback->onOutputBufferAvailable(index, outBuffer);
break;
}
@@ -2802,7 +2831,7 @@
}
void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
- if (mInputSurface.lock()->get() == nullptr) {
+ if (!mHasInputSurface) {
mInfoBuffers.push_back(buffer);
} else {
std::list<std::unique_ptr<C2Work>> items;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index f5e268a..4d296fd 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -391,7 +391,21 @@
};
Mutexed<BlockPools> mBlockPools;
- Mutexed<std::shared_ptr<InputSurfaceWrapper>> mInputSurface;
+ std::atomic_bool mHasInputSurface;
+ struct InputSurface {
+ std::shared_ptr<InputSurfaceWrapper> surface;
+ // This variable tracks the number of buffers processing
+ // in the input surface and codec by counting the # of buffers to
+ // be filled in and queued from the input surface and the # of
+ // buffers generated from the codec.
+ //
+ // Note that this variable can go below 0, because it does not take
+ // account the number of buffers initially in the buffer queue at
+ // start. This is okay, as we only track how many more we allow
+ // from the initial state.
+ int64_t numProcessingBuffersBalance;
+ };
+ Mutexed<InputSurface> mInputSurface;
MetaMode mMetaMode;
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index a13903b..f719d97 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -532,5 +532,13 @@
AudioChannelLayout::LAYOUT_HAPTIC_AB /* mask */);
}
+size_t EffectConversionHelperAidl::getInputChannelCount() const {
+ return getChannelCount(mCommon.input.base.channelMask);
+}
+
+size_t EffectConversionHelperAidl::getOutputChannelCount() const {
+ return getChannelCount(mCommon.output.base.channelMask);
+}
+
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 50b47a9..e9e9fc2 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -51,6 +51,8 @@
size_t getAudioChannelCount() const;
size_t getHapticChannelCount() const;
+ size_t getInputChannelCount() const;
+ size_t getOutputChannelCount() const;
uint8_t mOutputAccessMode = EFFECT_BUFFER_ACCESS_WRITE;
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index ea4dbf6..f68dd8a 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -75,7 +75,12 @@
mEffect(effect),
mSessionId(sessionId),
mIoId(ioId),
- mIsProxyEffect(isProxyEffect) {
+ mIsProxyEffect(isProxyEffect),
+ mHalVersion([factory]() {
+ int version = 0;
+ // use factory HAL version because effect can be an EffectProxy instance
+ return factory->getInterfaceVersion(&version).isOk() ? version : 0;
+ }()) {
assert(mFactory != nullptr);
assert(mEffect != nullptr);
createAidlConversion(effect, sessionId, ioId, desc);
@@ -159,6 +164,7 @@
mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
effect, sessionId, ioId, desc, mIsProxyEffect);
}
+ mEffectName = mConversion->getDescriptor().common.name;
return OK;
}
@@ -174,100 +180,155 @@
// write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
status_t EffectHalAidl::process() {
- const std::string effectName = mConversion->getDescriptor().common.name;
State state = State::INIT;
if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
state != State::PROCESSING) {
- ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
+ ALOGI("%s skipping process because it's %s", mEffectName.c_str(),
mConversion->isBypassing()
? "bypassing"
: aidl::android::hardware::audio::effect::toString(state).c_str());
return -ENODATA;
}
- // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
- auto efGroup = mConversion->getEventFlagGroup();
+ const std::shared_ptr<android::hardware::EventFlag> efGroup = mConversion->getEventFlagGroup();
if (!efGroup) {
- ALOGE("%s invalid efGroup", __func__);
+ ALOGE("%s invalid efGroup", mEffectName.c_str());
return INVALID_OPERATION;
}
- // use IFactory HAL version because IEffect can be an EffectProxy instance
- static const int halVersion = [&]() {
- int version = 0;
- return mFactory->getInterfaceVersion(&version).isOk() ? version : 0;
- }();
+ // reopen if halVersion >= kReopenSupportedVersion and receive kEventFlagDataMqUpdate
+ RETURN_STATUS_IF_ERROR(maybeReopen(efGroup));
+ const size_t samplesWritten = writeToHalInputFmqAndSignal(efGroup);
+ if (0 == samplesWritten) {
+ return INVALID_OPERATION;
+ }
- if (uint32_t efState = 0; halVersion >= kReopenSupportedVersion &&
- ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
+ RETURN_STATUS_IF_ERROR(waitHalStatusFmq(samplesWritten));
+ RETURN_STATUS_IF_ERROR(readFromHalOutputFmq(samplesWritten));
+ return OK;
+}
+
+status_t EffectHalAidl::maybeReopen(
+ const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
+ if (mHalVersion < kReopenSupportedVersion) {
+ return OK;
+ }
+
+ // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
+ if (uint32_t efState = 0; ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
1 /* ns */, true /* retry */) &&
efState & kEventFlagDataMqUpdate) {
- ALOGD("%s %s V%d receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str(),
- halVersion);
-
- mConversion->reopen();
+ ALOGD("%s V%d receive dataMQUpdate eventFlag from HAL", mEffectName.c_str(), mHalVersion);
+ return mConversion->reopen();
}
- auto statusQ = mConversion->getStatusMQ();
- auto inputQ = mConversion->getInputMQ();
- auto outputQ = mConversion->getOutputMQ();
- if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
- !outputQ->isValid()) {
- ALOGE("%s invalid FMQ [Status %d I %d O %d]", __func__, statusQ ? statusQ->isValid() : 0,
- inputQ ? inputQ->isValid() : 0, outputQ ? outputQ->isValid() : 0);
- return INVALID_OPERATION;
+ return OK;
+}
+
+size_t EffectHalAidl::writeToHalInputFmqAndSignal(
+ const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
+ const auto inputQ = mConversion->getInputMQ();
+ if (!inputQ || !inputQ->isValid()) {
+ ALOGE("%s invalid input FMQ", mEffectName.c_str());
+ return 0;
}
- size_t available = inputQ->availableToWrite();
- const size_t floatsToWrite = std::min(available, mInBuffer->getSize() / sizeof(float));
- if (floatsToWrite == 0) {
- ALOGE("%s not able to write, floats in buffer %zu, space in FMQ %zu", __func__,
- mInBuffer->getSize() / sizeof(float), available);
- return INVALID_OPERATION;
+ const size_t fmqSpaceSamples = inputQ->availableToWrite();
+ const size_t samplesInBuffer =
+ mInBuffer->audioBuffer()->frameCount * mConversion->getInputChannelCount();
+ const size_t samplesToWrite = std::min(fmqSpaceSamples, samplesInBuffer);
+ if (samplesToWrite == 0) {
+ ALOGE("%s not able to write, samplesInBuffer %zu, fmqSpaceSamples %zu", mEffectName.c_str(),
+ samplesInBuffer, fmqSpaceSamples);
+ return 0;
}
- if (!mInBuffer->audioBuffer() ||
- !inputQ->write((float*)mInBuffer->audioBuffer()->f32, floatsToWrite)) {
- ALOGE("%s failed to write %zu floats from audiobuffer %p to inputQ [avail %zu]", __func__,
- floatsToWrite, mInBuffer->audioBuffer(), inputQ->availableToWrite());
- return INVALID_OPERATION;
+
+ const float* const inputRawBuffer = static_cast<const float*>(mInBuffer->audioBuffer()->f32);
+ if (!inputQ->write(inputRawBuffer, samplesToWrite)) {
+ ALOGE("%s failed to write %zu samples to inputQ [avail %zu]", mEffectName.c_str(),
+ samplesToWrite, inputQ->availableToWrite());
+ return 0;
}
// for V2 audio effect HAL, expect different EventFlag to avoid bit conflict with FMQ_NOT_EMPTY
- efGroup->wake(halVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
- : kEventFlagNotEmpty);
+ efGroup->wake(mHalVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
+ : kEventFlagNotEmpty);
+ return samplesToWrite;
+}
+
+void EffectHalAidl::writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
+ float* const fmqOutputBuffer) const {
+ const auto audioChNum = mConversion->getAudioChannelCount();
+ const auto audioSamples =
+ totalSamples * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
+
+ static constexpr float kHalFloatSampleLimit = 2.0f;
+ // for HapticGenerator, the input data buffer will be updated
+ float* const inputRawBuffer = static_cast<float*>(mInBuffer->audioBuffer()->f32);
+ // accumulate or copy input to output, haptic samples remains all zero
+ if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ accumulate_float(outputRawBuffer, inputRawBuffer, audioSamples);
+ } else {
+ memcpy_to_float_from_float_with_clamping(outputRawBuffer, inputRawBuffer, audioSamples,
+ kHalFloatSampleLimit);
+ }
+ // append the haptic sample at the end of input audio samples
+ memcpy_to_float_from_float_with_clamping(inputRawBuffer + audioSamples,
+ fmqOutputBuffer + audioSamples,
+ totalSamples - audioSamples, kHalFloatSampleLimit);
+}
+
+status_t EffectHalAidl::waitHalStatusFmq(size_t samplesWritten) const {
+ const auto statusQ = mConversion->getStatusMQ();
+ if (const bool statusValid = statusQ && statusQ->isValid(); !statusValid) {
+ ALOGE("%s statusFMQ %s", mEffectName.c_str(), statusValid ? "valid" : "invalid");
+ return INVALID_OPERATION;
+ }
IEffect::Status retStatus{};
if (!statusQ->readBlocking(&retStatus, 1)) {
- ALOGE("%s %s V%d read status from status FMQ failed", __func__, effectName.c_str(),
- halVersion);
+ ALOGE("%s V%d read status from status FMQ failed", mEffectName.c_str(), mHalVersion);
return INVALID_OPERATION;
}
- if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != floatsToWrite ||
+ if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != samplesWritten ||
retStatus.fmqProduced == 0) {
- ALOGE("%s read status failed: %s, consumed %d (of %zu) produced %d", __func__,
- retStatus.toString().c_str(), retStatus.fmqConsumed, floatsToWrite,
- retStatus.fmqProduced);
+ ALOGE("%s read status failed: %s, FMQ consumed %d (of %zu) produced %d",
+ mEffectName.c_str(), retStatus.toString().c_str(), retStatus.fmqConsumed,
+ samplesWritten, retStatus.fmqProduced);
return INVALID_OPERATION;
}
- available = outputQ->availableToRead();
- const size_t floatsToRead = std::min(available, mOutBuffer->getSize() / sizeof(float));
- if (floatsToRead == 0) {
- ALOGE("%s not able to read, buffer space %zu, floats in FMQ %zu", __func__,
- mOutBuffer->getSize() / sizeof(float), available);
+ return OK;
+}
+
+status_t EffectHalAidl::readFromHalOutputFmq(size_t samplesWritten) const {
+ const auto outputQ = mConversion->getOutputMQ();
+ if (const bool outputValid = outputQ && outputQ->isValid(); !outputValid) {
+ ALOGE("%s outputFMQ %s", mEffectName.c_str(), outputValid ? "valid" : "invalid");
return INVALID_OPERATION;
}
- float *outputRawBuffer = mOutBuffer->audioBuffer()->f32;
+ const size_t fmqProducedSamples = outputQ->availableToRead();
+ const size_t bufferSpaceSamples =
+ mOutBuffer->audioBuffer()->frameCount * mConversion->getOutputChannelCount();
+ const size_t samplesToRead = std::min(fmqProducedSamples, bufferSpaceSamples);
+ if (samplesToRead == 0) {
+ ALOGE("%s unable to read, bufferSpace %zu, fmqProduced %zu samplesWritten %zu",
+ mEffectName.c_str(), bufferSpaceSamples, fmqProducedSamples, samplesWritten);
+ return INVALID_OPERATION;
+ }
+
+ float* const outputRawBuffer = static_cast<float*>(mOutBuffer->audioBuffer()->f32);
+ float* fmqOutputBuffer = outputRawBuffer;
std::vector<float> tempBuffer;
// keep original data in the output buffer for accumulate mode or HapticGenerator effect
if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE || mIsHapticGenerator) {
- tempBuffer.resize(floatsToRead);
- outputRawBuffer = tempBuffer.data();
+ tempBuffer.resize(samplesToRead, 0);
+ fmqOutputBuffer = tempBuffer.data();
}
// always read floating point data for AIDL
- if (!outputQ->read(outputRawBuffer, floatsToRead)) {
- ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", __func__, floatsToRead,
- mOutBuffer->audioBuffer());
+ if (!outputQ->read(fmqOutputBuffer, samplesToRead)) {
+ ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", mEffectName.c_str(),
+ samplesToRead, fmqOutputBuffer);
return INVALID_OPERATION;
}
@@ -276,26 +337,10 @@
// offset as input buffer, here we skip the audio samples in output FMQ and append haptic
// samples to the end of input buffer
if (mIsHapticGenerator) {
- static constexpr float kHalFloatSampleLimit = 2.0f;
- assert(floatsToRead == floatsToWrite);
- const auto audioChNum = mConversion->getAudioChannelCount();
- const auto audioSamples =
- floatsToWrite * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
- // accumulate or copy input to output, haptic samples remains all zero
- if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- accumulate_float(mOutBuffer->audioBuffer()->f32, mInBuffer->audioBuffer()->f32,
- audioSamples);
- } else {
- memcpy_to_float_from_float_with_clamping(mOutBuffer->audioBuffer()->f32,
- mInBuffer->audioBuffer()->f32, audioSamples,
- kHalFloatSampleLimit);
- }
- // append the haptic sample at the end of input audio samples
- memcpy_to_float_from_float_with_clamping(mInBuffer->audioBuffer()->f32 + audioSamples,
- outputRawBuffer + audioSamples,
- floatsToRead - audioSamples, kHalFloatSampleLimit);
+ assert(samplesRead == samplesWritten);
+ writeHapticGeneratorData(samplesToRead, outputRawBuffer, fmqOutputBuffer);
} else if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- accumulate_float(mOutBuffer->audioBuffer()->f32, outputRawBuffer, floatsToRead);
+ accumulate_float(outputRawBuffer, fmqOutputBuffer, samplesToRead);
}
return OK;
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
index 4f7de7c..c3982a7 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -73,7 +73,9 @@
const int32_t mSessionId;
const int32_t mIoId;
const bool mIsProxyEffect;
+ const int mHalVersion;
bool mIsHapticGenerator = false;
+ std::string mEffectName;
std::unique_ptr<EffectConversionHelperAidl> mConversion;
@@ -93,6 +95,14 @@
bool setEffectReverse(bool reverse);
bool needUpdateReturnParam(uint32_t cmdCode);
+ status_t maybeReopen(const std::shared_ptr<android::hardware::EventFlag>& efGroup) const;
+ void writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
+ float* const fmqOutputBuffer) const;
+ size_t writeToHalInputFmqAndSignal(
+ const std::shared_ptr<android::hardware::EventFlag>& efGroup) const;
+ status_t waitHalStatusFmq(size_t samplesWritten) const;
+ status_t readFromHalOutputFmq(size_t samplesWritten) const;
+
// The destructor automatically releases the effect.
virtual ~EffectHalAidl();
};
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index ab6a8b6..8f60d29 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -347,6 +347,7 @@
[6] = AUDIO_CHANNEL_OUT_5POINT1,
[7] = AUDIO_CHANNEL_OUT_6POINT1,
[8] = AUDIO_CHANNEL_OUT_7POINT1,
+ [10] = AUDIO_CHANNEL_OUT_5POINT1POINT4,
[12] = AUDIO_CHANNEL_OUT_7POINT1POINT4,
[14] = AUDIO_CHANNEL_OUT_9POINT1POINT4,
[16] = AUDIO_CHANNEL_OUT_9POINT1POINT6,
diff --git a/media/libaudioprocessing/tests/mixerops_tests.cpp b/media/libaudioprocessing/tests/mixerops_tests.cpp
index 2500ba9..235129f 100644
--- a/media/libaudioprocessing/tests/mixerops_tests.cpp
+++ b/media/libaudioprocessing/tests/mixerops_tests.cpp
@@ -154,6 +154,9 @@
TEST(mixerops, stereovolume_8) {
MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 8>::testStereoVolume();
}
+TEST(mixerops, stereovolume_10) {
+ MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 10>::testStereoVolume();
+}
TEST(mixerops, stereovolume_12) {
if constexpr (FCC_LIMIT >= 12) { // NOTE: FCC_LIMIT is an enum, so can't #if
MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 12>::testStereoVolume();
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
index 55e07fb..dd29e86 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -55,6 +55,17 @@
namespace aidl::android::hardware::audio::effect {
+const std::vector<Range::HapticGeneratorRange> kHapticRange = {
+ MAKE_RANGE(HapticGenerator, vibratorInfo,
+ HapticGenerator::VibratorInformation(
+ {.resonantFrequencyHz = 1, .qFactor = 1, .maxAmplitude = -1}),
+ HapticGenerator::VibratorInformation(
+ {.resonantFrequencyHz = std::numeric_limits<float>::max(),
+ .qFactor = std::numeric_limits<float>::max(),
+ .maxAmplitude = 1}))};
+
+static const Capability kHapticCap = {.range = kHapticRange};
+
const std::string HapticGeneratorImpl::kEffectName = "Haptic Generator";
const Descriptor HapticGeneratorImpl::kDescriptor = {
.common = {.id = {.type = getEffectTypeUuidHapticGenerator(),
@@ -62,7 +73,8 @@
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
.name = HapticGeneratorImpl::kEffectName,
- .implementor = "The Android Open Source Project"}};
+ .implementor = "The Android Open Source Project"},
+ .capability = kHapticCap};
ndk::ScopedAStatus HapticGeneratorImpl::getDescriptor(Descriptor* _aidl_return) {
RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
@@ -76,6 +88,8 @@
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+ RETURN_IF(!inRange(hgParam, kHapticRange), EX_ILLEGAL_ARGUMENT, "outOfRange");
+
auto tag = hgParam.getTag();
switch (tag) {
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
index 535b886..d8f9093 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -353,7 +353,7 @@
std::string HapticGeneratorContext::paramToString(const struct HapticGeneratorParam& param) const {
std::stringstream ss;
- ss << "\t\ttHapticGenerator Parameters:\n";
+ ss << "\t\tHapticGenerator Parameters:\n";
ss << "\t\t- mHapticChannelCount: " << param.mHapticChannelCount << '\n';
ss << "\t\t- mAudioChannelCount: " << param.mAudioChannelCount << '\n';
ss << "\t\t- mHapticChannelSource: " << param.mHapticChannelSource[0] << ", "
@@ -378,7 +378,7 @@
ss << "\t\t- distortion input gain: " << DEFAULT_DISTORTION_INPUT_GAIN << '\n';
ss << "\t\t- distortion cube threshold: " << DEFAULT_DISTORTION_CUBE_THRESHOLD << '\n';
ss << "\t\t- distortion output gain: " << getDistortionOutputGain() << '\n';
- ss << "\t\tHapticGenerator Parameters:\n" << paramToString(mParams) << "\n";
+ ss << paramToString(mParams) << "\n";
return ss.str();
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 794c7c0..b193cb8 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,10 +16,10 @@
#pragma once
+#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
-#include <vector>
#include <DeviceDescriptor.h>
#include <HwModule.h>
@@ -141,6 +141,12 @@
void setDefault();
+ void setUseDeepBufferForMediaOverrideForTests(bool useDeepBufferForMedia)
+ {
+ mUseDeepBufferForMediaOverride = useDeepBufferForMedia;
+ }
+ bool useDeepBufferForMedia() const;
+
private:
friend class sp<AudioPolicyConfig>;
@@ -158,6 +164,7 @@
sp<DeviceDescriptor> mDefaultOutputDevice;
bool mIsCallScreenModeSupported = false;
SurroundFormats mSurroundFormats;
+ std::optional<bool> mUseDeepBufferForMediaOverride;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index abeaaf8..f5e135e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "APM_Config"
+#include <android-base/properties.h>
#include <AudioPolicyConfig.h>
#include <IOProfile.h>
#include <Serializer.h>
@@ -344,4 +345,9 @@
{AUDIO_FORMAT_AC4, {}}};
}
+bool AudioPolicyConfig::useDeepBufferForMedia() const {
+ if (mUseDeepBufferForMediaOverride.has_value()) return *mUseDeepBufferForMediaOverride;
+ return property_get_bool("audio.deep_buffer.media", false /* default_value */);
+}
+
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 1b53428..796e3c7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1194,8 +1194,7 @@
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
- if (stream == AUDIO_STREAM_MUSIC &&
- property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+ if (stream == AUDIO_STREAM_MUSIC && mConfig->useDeepBufferForMedia()) {
flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
}
const audio_io_handle_t output = selectOutput(outputs, flags);
@@ -1572,6 +1571,13 @@
return NAME_NOT_FOUND;
}
+ // Reject flag combinations that do not make sense. Note that the requested flags might not
+ // have the 'DIRECT' flag set, however once a direct-capable profile is found, it will
+ // combine the requested flags with its own flags, yielding an unsupported combination.
+ if ((flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+ return NAME_NOT_FOUND;
+ }
+
// Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
// This prevents creating an offloaded track and tearing it down immediately after start
// when audioflinger detects there is an active non offloadable effect.
@@ -1720,8 +1726,7 @@
if (stream != AUDIO_STREAM_MUSIC) {
*flags = (audio_output_flags_t)(*flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
} else if (/* stream == AUDIO_STREAM_MUSIC && */
- *flags == AUDIO_OUTPUT_FLAG_NONE &&
- property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+ *flags == AUDIO_OUTPUT_FLAG_NONE && mConfig->useDeepBufferForMedia()) {
// use DEEP_BUFFER as default output for music stream type
*flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
}
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 45643f7..a120649 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -17,6 +17,7 @@
#include <map>
#include <set>
+#include <media/TypeConverter.h>
#include <system/audio.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -37,11 +38,11 @@
status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
- audio_config_t * /*halConfig*/,
- audio_config_base_t * /*mixerConfig*/,
+ audio_config_t *halConfig,
+ audio_config_base_t *mixerConfig,
const sp<DeviceDescriptorBase>& /*device*/,
uint32_t * /*latencyMs*/,
- audio_output_flags_t /*flags*/,
+ audio_output_flags_t flags,
audio_attributes_t /*attributes*/) override {
if (module >= mNextModuleHandle) {
ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
@@ -49,6 +50,13 @@
return BAD_VALUE;
}
*output = mNextIoHandle++;
+ mOpenedOutputs[*output] = flags;
+ ALOGD("%s: opened output %d: HAL(%s %s %d) Mixer(%s %s %d) %s", __func__, *output,
+ audio_channel_out_mask_to_string(halConfig->channel_mask),
+ audio_format_to_string(halConfig->format), halConfig->sample_rate,
+ audio_channel_out_mask_to_string(mixerConfig->channel_mask),
+ audio_format_to_string(mixerConfig->format), mixerConfig->sample_rate,
+ android::toString(flags).c_str());
return NO_ERROR;
}
@@ -58,6 +66,16 @@
return id;
}
+ status_t closeOutput(audio_io_handle_t output) override {
+ if (auto iter = mOpenedOutputs.find(output); iter != mOpenedOutputs.end()) {
+ mOpenedOutputs.erase(iter);
+ return NO_ERROR;
+ } else {
+ ALOGE("%s: Unknown output %d", __func__, output);
+ return BAD_VALUE;
+ }
+ }
+
status_t openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t * /*config*/,
@@ -276,6 +294,13 @@
return mOpenInputCallsCount;
}
+ std::optional<audio_output_flags_t> getOpenOutputFlags(audio_io_handle_t output) const {
+ if (auto iter = mOpenedOutputs.find(output); iter != mOpenedOutputs.end()) {
+ return iter->second;
+ }
+ return std::nullopt;
+ }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
@@ -292,6 +317,7 @@
std::set<audio_io_handle_t> mOpenedInputs;
size_t mOpenInputCallsCount = 0;
size_t mCloseInputCallsCount = 0;
+ std::map<audio_io_handle_t, audio_output_flags_t> mOpenedOutputs;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 34ceeab..bf45bb2 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,9 +24,11 @@
explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyTestManager(AudioPolicyConfig::createDefault(), clientInterface) {}
AudioPolicyTestManager(const sp<const AudioPolicyConfig>& config,
- AudioPolicyClientInterface *clientInterface)
+ AudioPolicyClientInterface *clientInterface,
+ std::string engineConfig = "")
: AudioPolicyManager(config,
- loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
+ loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix(),
+ engineConfig),
clientInterface) {}
using AudioPolicyManager::getConfig;
using AudioPolicyManager::initialize;
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 79fa157..ad8657c 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -35,6 +35,7 @@
#include <media/AudioPolicy.h>
#include <media/PatchBuilder.h>
#include <media/RecordingActivityTracker.h>
+#include <media/TypeConverter.h>
#include <utils/Log.h>
#include <utils/Vector.h>
#include <cutils/multiuser.h>
@@ -176,6 +177,11 @@
};
class AudioPolicyManagerTest : public testing::Test {
+ public:
+ constexpr static uint32_t k384000SamplingRate = 384000;
+ constexpr static uint32_t k48000SamplingRate = 48000;
+ constexpr static uint32_t k96000SamplingRate = 96000;
+
protected:
void SetUp() override;
void TearDown() override;
@@ -192,7 +198,7 @@
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
audio_io_handle_t *output = nullptr,
audio_port_handle_t *portId = nullptr,
- audio_attributes_t attr = {},
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER,
audio_session_t session = AUDIO_SESSION_NONE,
int uid = 0,
bool* isBitPerfect = nullptr);
@@ -223,13 +229,16 @@
std::unique_ptr<AudioPolicyManagerTestClient> mClient;
std::unique_ptr<AudioPolicyTestManager> mManager;
- constexpr static const uint32_t k48000SamplingRate = 48000;
+ static const std::string sTestEngineConfig;
};
+const std::string AudioPolicyManagerTest::sTestEngineConfig =
+ base::GetExecutableDirectory() + "/engine/test_audio_policy_engine_configuration.xml";
+
void AudioPolicyManagerTest::SetUp() {
mClient.reset(getClient());
ASSERT_NO_FATAL_FAILURE(SetUpManagerConfig()); // Subclasses may want to customize the config.
- mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get()));
+ mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get(), sTestEngineConfig));
ASSERT_EQ(NO_ERROR, mManager->initialize());
ASSERT_EQ(NO_ERROR, mManager->initCheck());
}
@@ -784,27 +793,27 @@
audio_config_base_t directConfig = AUDIO_CONFIG_BASE_INITIALIZER;
directConfig.format = AUDIO_FORMAT_DTS;
- directConfig.sample_rate = 48000;
+ directConfig.sample_rate = k48000SamplingRate;
directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_base_t nonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
- nonDirectConfig.sample_rate = 48000;
+ nonDirectConfig.sample_rate = k48000SamplingRate;
nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_base_t nonExistentConfig = AUDIO_CONFIG_BASE_INITIALIZER;
nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
- nonExistentConfig.sample_rate = 48000;
+ nonExistentConfig.sample_rate = k48000SamplingRate;
nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_base_t msdDirectConfig1 = AUDIO_CONFIG_BASE_INITIALIZER;
msdDirectConfig1.format = AUDIO_FORMAT_AC3;
- msdDirectConfig1.sample_rate = 48000;
+ msdDirectConfig1.sample_rate = k48000SamplingRate;
msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_base_t msdDirectConfig2 = AUDIO_CONFIG_BASE_INITIALIZER;
msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
- msdDirectConfig2.sample_rate = 48000;
+ msdDirectConfig2.sample_rate = k48000SamplingRate;
msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
audio_config_base_t msdNonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
@@ -851,27 +860,27 @@
audio_config_t directConfig = AUDIO_CONFIG_INITIALIZER;
directConfig.format = AUDIO_FORMAT_DTS;
- directConfig.sample_rate = 48000;
+ directConfig.sample_rate = k48000SamplingRate;
directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_t nonDirectConfig = AUDIO_CONFIG_INITIALIZER;
nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
- nonDirectConfig.sample_rate = 48000;
+ nonDirectConfig.sample_rate = k48000SamplingRate;
nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_t nonExistentConfig = AUDIO_CONFIG_INITIALIZER;
nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
- nonExistentConfig.sample_rate = 48000;
+ nonExistentConfig.sample_rate = k48000SamplingRate;
nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_t msdDirectConfig1 = AUDIO_CONFIG_INITIALIZER;
msdDirectConfig1.format = AUDIO_FORMAT_AC3;
- msdDirectConfig1.sample_rate = 48000;
+ msdDirectConfig1.sample_rate = k48000SamplingRate;
msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_t msdDirectConfig2 = AUDIO_CONFIG_INITIALIZER;
msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
- msdDirectConfig2.sample_rate = 48000;
+ msdDirectConfig2.sample_rate = k48000SamplingRate;
msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
audio_config_t msdNonDirectConfig = AUDIO_CONFIG_INITIALIZER;
@@ -1127,12 +1136,12 @@
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
AUDIO_SESSION_NONE, uid);
status_t status = mManager->startOutput(portId);
if (status == DEAD_OBJECT) {
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
AUDIO_SESSION_NONE, uid);
status = mManager->startOutput(portId);
}
@@ -1173,9 +1182,9 @@
audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
audio_config_base_t requestedConfig = {
+ .sample_rate = k48000SamplingRate,
.channel_mask = AUDIO_CHANNEL_IN_STEREO,
.format = AUDIO_FORMAT_PCM_16_BIT,
- .sample_rate = 48000
};
audio_config_base_t config = requestedConfig;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -3182,6 +3191,259 @@
"low latency");
}
+class AudioPolicyManagerPhoneTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ std::string getConfigFile() override { return sPhoneConfig; }
+ void testOutputMixPortSelectionForAttr(audio_output_flags_t flags, audio_format_t format,
+ int samplingRate, bool isMusic, const char* expectedMixPortName);
+ void testOutputMixPortSelectionForStream(
+ audio_stream_type_t stream, const char* expectedMixPortName);
+ void verifyMixPortNameAndFlags(audio_io_handle_t output, const char* expectedMixPortName);
+
+ static const std::string sPhoneConfig;
+ static const std::map<std::string, audio_output_flags_t> sMixPortFlags;
+};
+
+const std::string AudioPolicyManagerPhoneTest::sPhoneConfig =
+ AudioPolicyManagerPhoneTest::sExecutableDir + "test_phone_apm_configuration.xml";
+
+// Must be in sync with the contents of the sPhoneConfig file.
+const std::map<std::string, audio_output_flags_t> AudioPolicyManagerPhoneTest::sMixPortFlags = {
+ {"primary output",
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_PRIMARY | AUDIO_OUTPUT_FLAG_FAST)},
+ {"direct", AUDIO_OUTPUT_FLAG_DIRECT},
+ {"deep buffer", AUDIO_OUTPUT_FLAG_DEEP_BUFFER},
+ {"compressed_offload",
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING |
+ AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD)},
+ {"raw", (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_FAST)},
+ {"mmap_no_irq_out",
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)},
+ {"voip_rx", AUDIO_OUTPUT_FLAG_VOIP_RX},
+};
+
+void AudioPolicyManagerPhoneTest::testOutputMixPortSelectionForAttr(
+ audio_output_flags_t flags, audio_format_t format, int samplingRate, bool isMusic,
+ const char* expectedMixPortName) {
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ if (isMusic) {
+ attr.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+ attr.usage = AUDIO_USAGE_MEDIA;
+ }
+ getOutputForAttr(&selectedDeviceId, format, AUDIO_CHANNEL_OUT_STEREO, samplingRate, flags,
+ &output, &portId, attr);
+ EXPECT_NO_FATAL_FAILURE(verifyMixPortNameAndFlags(output, expectedMixPortName));
+ mManager->releaseOutput(portId);
+}
+
+void AudioPolicyManagerPhoneTest::testOutputMixPortSelectionForStream(
+ audio_stream_type_t stream, const char* expectedMixPortName) {
+ audio_io_handle_t output = mManager->getOutput(stream);
+ EXPECT_NO_FATAL_FAILURE(verifyMixPortNameAndFlags(output, expectedMixPortName));
+}
+
+void AudioPolicyManagerPhoneTest::verifyMixPortNameAndFlags(audio_io_handle_t output,
+ const char* expectedMixPortName) {
+ ALOGI("%s: checking output %d", __func__, output);
+ sp<SwAudioOutputDescriptor> outDesc = mManager->getOutputs().valueFor(output);
+ ASSERT_NE(nullptr, outDesc.get());
+ audio_port_v7 port = {};
+ outDesc->toAudioPort(&port);
+ EXPECT_EQ(AUDIO_PORT_TYPE_MIX, port.type);
+ EXPECT_EQ(AUDIO_PORT_ROLE_SOURCE, port.role);
+ ASSERT_STREQ(expectedMixPortName, port.name);
+
+ auto iter = sMixPortFlags.find(port.name);
+ ASSERT_NE(iter, sMixPortFlags.end()) << "\"" << port.name << "\" is not in sMixPortFlags";
+ auto actualFlags = mClient->getOpenOutputFlags(output);
+ ASSERT_TRUE(actualFlags.has_value()) << "\"" << port.name << "\" was not opened via client";
+ EXPECT_EQ(*actualFlags, iter->second);
+}
+
+TEST_F(AudioPolicyManagerPhoneTest, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+enum {
+ MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER,
+ MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER,
+ MIX_PORT_ATTR_FLAGS_PARAMETER,
+ MIX_PORT_ATTR_FORMAT_PARAMETER,
+ MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER,
+};
+using MixPortSelectionForAttr =
+ std::tuple<const char*, const char*, audio_output_flags_t, audio_format_t, int>;
+
+class AudioPolicyManagerOutputMixPortForAttrSelectionTest
+ : public AudioPolicyManagerPhoneTest,
+ public testing::WithParamInterface<MixPortSelectionForAttr> {
+};
+
+// There is no easy way to create a flat tuple from tuples via ::testing::Combine.
+// Instead, just run the same selection twice while altering the deep buffer for media setting.
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForAttr(
+ std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ false /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_Music) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForAttr(
+ std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ true /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_DeepMedia) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+ const char* fallbackName = std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam());
+ ASSERT_NO_FATAL_FAILURE(
+ testOutputMixPortSelectionForAttr(std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ false /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+ GetParam()) ?: fallbackName));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_DeepMedia_Music) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+ const char* fallbackName = std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam());
+ ASSERT_NO_FATAL_FAILURE(
+ testOutputMixPortSelectionForAttr(std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ true /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+ GetParam()) ?: fallbackName));
+}
+
+INSTANTIATE_TEST_CASE_P(AudioPolicyManagerOutputMixPortForAttrSelection,
+ AudioPolicyManagerOutputMixPortForAttrSelectionTest,
+ ::testing::Values(
+ std::make_tuple("primary output", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("primary output", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k48000SamplingRate),
+ // Note: this goes to "direct" because 384000 > SAMPLE_RATE_HZ_MAX (192000)
+ std::make_tuple("direct", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("primary output", nullptr, AUDIO_OUTPUT_FLAG_FAST,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("direct", nullptr, AUDIO_OUTPUT_FLAG_DIRECT,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k96000SamplingRate),
+ std::make_tuple("direct", nullptr, AUDIO_OUTPUT_FLAG_DIRECT,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("deep buffer", nullptr, AUDIO_OUTPUT_FLAG_DEEP_BUFFER,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("deep buffer", nullptr, AUDIO_OUTPUT_FLAG_DEEP_BUFFER,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("compressed_offload", nullptr,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+ AUDIO_FORMAT_MP3, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("raw", nullptr,
+ AUDIO_OUTPUT_FLAG_RAW, AUDIO_FORMAT_PCM_32_BIT,
+ AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("mmap_no_irq_out", nullptr,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT |
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("mmap_no_irq_out", nullptr,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT |
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("voip_rx", nullptr, AUDIO_OUTPUT_FLAG_VOIP_RX,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate)),
+ [](const ::testing::TestParamInfo<MixPortSelectionForAttr>& info) {
+ static const std::string flagPrefix = "AUDIO_OUTPUT_FLAG_";
+ static const std::string formatPrefix = "AUDIO_FORMAT_";
+ std::string flags;
+ TypeConverter<OutputFlagTraits>::maskToString(
+ std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(info.param), flags, "__");
+ size_t index = 0;
+ while (true) {
+ index = flags.rfind(flagPrefix);
+ if (index == std::string::npos) break;
+ flags.erase(index, flagPrefix.length());
+ }
+ std::string format;
+ TypeConverter<FormatTraits>::toString(
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(info.param), format);
+ if (size_t index = format.find(formatPrefix); index != std::string::npos) {
+ format.erase(index, formatPrefix.length());
+ }
+ return flags + "__" + format + "__" +
+ std::to_string(std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(info.param));
+ }
+);
+
+
+enum {
+ MIX_PORT_STRM_EXPECTED_NAME_PARAMETER,
+ MIX_PORT_STRM_EXPECTED_NAME_WITH_DBFM_PARAMETER,
+ MIX_PORT_STRM_STREAM_PARAMETER,
+};
+using MixPortSelectionForStream =
+ std::tuple<const char*, const char*, audio_stream_type_t>;
+
+class AudioPolicyManagerOutputMixPortForStreamSelectionTest
+ : public AudioPolicyManagerPhoneTest,
+ public testing::WithParamInterface<MixPortSelectionForStream> {
+};
+
+// There is no easy way to create a flat tuple from tuples via ::testing::Combine.
+// Instead, just run the same selection twice while altering the deep buffer for media setting.
+TEST_P(AudioPolicyManagerOutputMixPortForStreamSelectionTest, SelectPort_NoDBFM) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForStream(
+ std::get<MIX_PORT_STRM_STREAM_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_STRM_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForStreamSelectionTest, SelectPort_WithDBFM) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+ const char* fallbackName = std::get<MIX_PORT_STRM_EXPECTED_NAME_PARAMETER>(GetParam());
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForStream(
+ std::get<MIX_PORT_STRM_STREAM_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_STRM_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+ GetParam()) ?: fallbackName));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AudioPolicyManagerOutputMixPortForStreamSelection,
+ AudioPolicyManagerOutputMixPortForStreamSelectionTest,
+ ::testing::Values(std::make_tuple("primary output", nullptr, AUDIO_STREAM_DEFAULT),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_SYSTEM),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_RING),
+ std::make_tuple("primary output", "deep buffer", AUDIO_STREAM_MUSIC),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ALARM),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_NOTIFICATION),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_BLUETOOTH_SCO),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ENFORCED_AUDIBLE),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_DTMF),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_TTS),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ACCESSIBILITY),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ASSISTANT)),
+ [](const ::testing::TestParamInfo<MixPortSelectionForStream>& info) {
+ static const std::string streamPrefix = "AUDIO_STREAM_";
+ std::string stream;
+ TypeConverter<StreamTraits>::toString(
+ std::get<MIX_PORT_STRM_STREAM_PARAMETER>(info.param), stream);
+ if (size_t index = stream.find(streamPrefix); index != std::string::npos) {
+ stream.erase(index, streamPrefix.length());
+ }
+ return stream;
+ }
+);
+
class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void SetUpManagerConfig() override;
@@ -3334,7 +3596,7 @@
audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
auto selectedDevice = availableDevices.getDeviceFromId(selectedDeviceId);
ASSERT_NE(nullptr, selectedDevice);
@@ -3355,7 +3617,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
ASSERT_EQ(preferredDevice, availableDevices.getDeviceFromId(selectedDeviceId));
// After clearing preferred device for capture preset, the selected device for input should be
@@ -3366,7 +3628,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
ASSERT_EQ(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
@@ -3392,7 +3654,7 @@
audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
auto selectedDevice = availableDevices.getDeviceFromId(selectedDeviceId);
ASSERT_NE(nullptr, selectedDevice);
@@ -3405,7 +3667,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1,
&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_IN_STEREO, 48000));
+ AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate));
ASSERT_NE(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
// After clearing disabled device for capture preset, the selected device for input should be
@@ -3416,7 +3678,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
ASSERT_EQ(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
@@ -3519,7 +3781,7 @@
// effect attached again
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &inputClientHandle, session, 1, &routedPortId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
// unregister effect should succeed since effect shall have been restore on the client session
ASSERT_EQ(NO_ERROR, mManager->unregisterEffect(effectId));
@@ -3536,7 +3798,7 @@
const audio_format_t mBitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
const audio_channel_mask_t mBitPerfectChannelMask = AUDIO_CHANNEL_OUT_STEREO;
- const uint32_t mBitPerfectSampleRate = 48000;
+ const uint32_t mBitPerfectSampleRate = k48000SamplingRate;
const uid_t mUid = 1234;
audio_port_handle_t mUsbPortId = AUDIO_PORT_HANDLE_NONE;
@@ -3812,8 +4074,8 @@
ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
audio_attributes_t attr = {
+ .content_type = AUDIO_CONTENT_TYPE_UNKNOWN,
.usage = GetParam(),
- .content_type = AUDIO_CONTENT_TYPE_UNKNOWN
};
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -3854,14 +4116,14 @@
audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
EXPECT_EQ(0, mClient->getCloseInputCallsCount());
@@ -3882,7 +4144,7 @@
audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
@@ -3890,7 +4152,7 @@
attr.source = AUDIO_SOURCE_VOICE_RECOGNITION;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
EXPECT_EQ(0, mClient->getCloseInputCallsCount());
@@ -3911,7 +4173,7 @@
audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
@@ -3919,7 +4181,7 @@
attr.source = AUDIO_SOURCE_CAMCORDER;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(2, mClient->getOpenInputCallsCount());
EXPECT_EQ(1, mClient->getCloseInputCallsCount());
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 1c191f5..8e7a697 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -11,11 +11,16 @@
filegroup {
name: "audiopolicytest_configuration_files",
srcs: [
+ "engine/test_audio_policy_engine_configuration.xml",
+ "engine/test_audio_policy_engine_default_stream_volumes.xml",
+ "engine/test_audio_policy_engine_product_strategies.xml",
+ "engine/test_audio_policy_engine_stream_volumes.xml",
"test_audio_policy_configuration.xml",
"test_audio_policy_configuration_bluetooth.xml",
"test_audio_policy_primary_only_configuration.xml",
"test_car_ap_atmos_offload_configuration.xml",
"test_invalid_audio_policy_configuration.xml",
+ "test_phone_apm_configuration.xml",
"test_settop_box_surround_configuration.xml",
"test_tv_apm_configuration.xml",
],
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml
new file mode 100644
index 0000000..dc2e7af
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+ -->
+
+<configuration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <xi:include href="test_audio_policy_engine_product_strategies.xml"/>
+ <xi:include href="test_audio_policy_engine_stream_volumes.xml"/>
+ <xi:include href="test_audio_policy_engine_default_stream_volumes.xml"/>
+
+</configuration>
+
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml
new file mode 100644
index 0000000..d184cb5
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- Default Volume Tables included by Audio Policy Configuration file -->
+<!-- Full Default Volume table for all device category -->
+<volumes>
+ <reference name="FULL_SCALE_VOLUME_CURVE">
+ <!-- Full Scale reference Volume Curve -->
+ <point>0,0</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="SILENT_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,-9600</point>
+ </reference>
+ <reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
+ <!-- Default System reference Volume Curve -->
+ <point>1,-2400</point>
+ <point>33,-1800</point>
+ <point>66,-1200</point>
+ <point>100,-600</point>
+ </reference>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <!-- Default Media reference Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
+ <!--Default Volume Curve -->
+ <point>1,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
+ <!-- Default is Speaker Media Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE">
+ <!-- Default is Speaker System Volume Curve -->
+ <point>1,-4680</point>
+ <point>42,-2070</point>
+ <point>85,-540</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
+ <!--Default Volume Curve -->
+ <point>1,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
+ <!-- Default is Ext Media System Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-2100</point>
+ <point>100,-1000</point>
+ </reference>
+ <reference name="DEFAULT_HEARING_AID_VOLUME_CURVE">
+ <!-- Default Hearing Aid Volume Curve -->
+ <point>1,-12700</point>
+ <point>20,-8000</point>
+ <point>60,-4000</point>
+ <point>100,0</point>
+ </reference>
+ <!-- **************************************************************** -->
+ <!-- Non-mutable default volume curves: -->
+ <!-- * first point is always for index 0 -->
+ <!-- * attenuation is small enough that stream can still be heard -->
+ <reference name="DEFAULT_NON_MUTABLE_VOLUME_CURVE">
+ <!-- Default non-mutable reference Volume Curve -->
+ <!-- based on DEFAULT_MEDIA_VOLUME_CURVE -->
+ <point>0,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE">
+ <!--Default non-mutable Volume Curve for headset -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE -->
+ <point>0,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE">
+ <!-- Default non-mutable Speaker Volume Curve -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE -->
+ <point>0,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE">
+ <!--Default non-mutable Volume Curve -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE -->
+ <point>0,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE">
+ <!-- Default non-mutable Ext Media System Volume Curve -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE -->
+ <point>0,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-2100</point>
+ <point>100,-1000</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE">
+ <!-- Default non-mutable Hearing Aid Volume Curve -->
+ <!-- based on DEFAULT_HEARING_AID_VOLUME_CURVE -->
+ <point>0,-12700</point>
+ <point>20,-8000</point>
+ <point>60,-4000</point>
+ <point>100,0</point>
+ </reference>
+</volumes>
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml
new file mode 100644
index 0000000..58e7152
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+ -->
+
+<ProductStrategies>
+
+ <!-- "hidden strategies" like TTS, enforced audible:
+ Shall we expose them here or keep it hard coded -->
+
+ <!-- Used to identify the volume of audio streams for enforced system sounds in certain
+ countries (e.g. camera in Japan)
+ This strategy will only have higher priority than phone if force for system is set to
+ enforced. -->
+
+ <ProductStrategy name="STRATEGY_PHONE">
+ <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
+ <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
+ <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_SONIFICATION">
+ <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/> </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="alarm">
+ <Attributes> <Usage value="AUDIO_USAGE_ALARM"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_ENFORCED_AUDIBLE">
+ <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE" volumeGroup="enforced_audible">
+ <Attributes> <Flags value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_ACCESSIBILITY">
+ <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY" volumeGroup="accessibility">
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_SONIFICATION_RESPECTFUL">
+ <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="notification">
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_MEDIA">
+ <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+ <Attributes>
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANT"/>
+ </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="music">
+ <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
+ <Attributes></Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_DTMF">
+ <AttributesGroup streamType="AUDIO_STREAM_DTMF" volumeGroup="dtmf">
+ <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Used to identify the volume of audio streams exclusively transmitted through the speaker
+ (TTS) of the device -->
+ <ProductStrategy name="STRATEGY_TRANSMITTED_THROUGH_SPEAKER">
+ <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
+ <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+</ProductStrategies>
+
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml
new file mode 100644
index 0000000..af517cf
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- Volume section defines a volume curve for a given use case and device category.
+It contains a list of points of this curve expressing the attenuation in Millibels for a given
+volume index from 0 to 100.
+<volume deviceCategory=””>
+<point>0,-9600</point>
+<point>100,0</point>
+</volume>
+-->
+
+<volumeGroups>
+ <volumeGroup>
+ <name>voice_call</name>
+ <indexMin>1</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-2700</point>
+ <point>33,-1800</point>
+ <point>66,-900</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>system</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-5100</point>
+ <point>57,-2800</point>
+ <point>71,-2500</point>
+ <point>85,-2300</point>
+ <point>100,-2100</point>
+ </volume>
+ <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>ring</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>music</name>
+ <indexMin>0</indexMin>
+ <indexMax>25</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>alarm</name>
+ <indexMin>1</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>notification</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>bluetooth_sco</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>enforced_audible</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-3400</point>
+ <point>71,-2400</point>
+ <point>100,-2000</point>
+ </volume>
+ <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>dtmf</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-4000</point>
+ <point>71,-2400</point>
+ <point>100,-1400</point>
+ </volume>
+ <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>tts</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="SILENT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="SILENT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="SILENT_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>accessibility</name>
+ <indexMin>1</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>assistant</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+</volumeGroups>
+
diff --git a/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
new file mode 100644
index 0000000..efe1400
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="false" call_screen_mode_supported="true" />
+ <modules>
+ <!-- Primary Audio HAL -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Speaker Safe</item>
+ <item>Earpiece</item>
+ <item>Built-In Mic</item>
+ <item>Built-In Back Mic</item>
+ <item>Telephony Tx</item>
+ <item>Voice Call And Telephony Rx</item>
+ <item>Echo Ref In</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY AUDIO_OUTPUT_FLAG_FAST"
+ recommendedMuteDurationMs="40">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="direct" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT"
+ recommendedMuteDurationMs="40">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="deep buffer" role="source" flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="compressed_offload" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD">
+ <profile name="" format="AUDIO_FORMAT_MP3"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_LC"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_HE_V1"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_HE_V2"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_OPUS"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="haptic" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB" />
+ </mixPort>
+ <mixPort name="raw" role="source" flags="AUDIO_OUTPUT_FLAG_RAW AUDIO_OUTPUT_FLAG_FAST">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="incall playback" role="source"
+ flags="AUDIO_OUTPUT_FLAG_INCALL_MUSIC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
+ </mixPort>
+ <mixPort name="voice call tx" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
+ </mixPort>
+ <mixPort name="voip_rx" role="source"
+ flags="AUDIO_OUTPUT_FLAG_VOIP_RX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_INDEX_MASK_3"/>
+ </mixPort>
+ <mixPort name="hotword input" role="sink" flags="AUDIO_INPUT_FLAG_HW_HOTWORD" maxActiveCount="0" >
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="incall capture" role="sink" maxActiveCount="2" maxOpenCount="2">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voice call rx" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voip_tx" role="sink"
+ flags="AUDIO_INPUT_FLAG_VOIP_TX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="fast input" role="sink" flags="AUDIO_INPUT_FLAG_RAW AUDIO_INPUT_FLAG_FAST">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="hifi_playback" role="source" />
+ <mixPort name="hifi_input" role="sink" />
+ <mixPort name="echo_ref_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
+ <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
+ </devicePort>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Speaker Safe" type="AUDIO_DEVICE_OUT_SPEAKER_SAFE" role="sink">
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
+ </devicePort>
+ <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
+ </devicePort>
+ <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
+ </devicePort>
+ <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink">
+ </devicePort>
+ <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink">
+ </devicePort>
+ <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+ </devicePort>
+ <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+ </devicePort>
+ <!-- Input devices declaration, i.e. Source DEVICE PORT -->
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
+ </devicePort>
+ <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"
+ encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink"
+ encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink"
+ encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT BLE Headset" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"
+ encodedFormats="AUDIO_FORMAT_LC3">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT BLE Speaker" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"
+ encodedFormats="AUDIO_FORMAT_LC3">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT BLE Broadcast" type="AUDIO_DEVICE_OUT_BLE_BROADCAST" role="sink"
+ encodedFormats="AUDIO_FORMAT_LC3">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BLE Headset Mic" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source">
+ </devicePort>
+ <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source">
+ </devicePort>
+ <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source">
+ </devicePort>
+ <!-- AUDIO_DEVICE_IN_VOICE_CALL and AUDIO_DEVICE_IN_TELEPHONY_RX are in the same value -->
+ <devicePort tagName="Voice Call And Telephony Rx" type="AUDIO_DEVICE_IN_VOICE_CALL" role="source">
+ </devicePort>
+ <devicePort tagName="Echo Ref In" type="AUDIO_DEVICE_IN_ECHO_REFERENCE" role="source">
+ </devicePort>
+ </devicePorts>
+ <!-- route declaration, i.e. list all available sources for a given sink -->
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="Speaker Safe"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="Earpiece"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="BT A2DP Out"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT A2DP Headphones"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT A2DP Speaker"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT BLE Headset"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT BLE Speaker"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT BLE Broadcast"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="USB Device Out"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,hifi_playback,compressed_offload,immersive_out"/>
+ <route type="mix" sink="USB Headset Out"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,hifi_playback,compressed_offload,immersive_out"/>
+ <route type="mix" sink="HDMI Out"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="BT SCO"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+ <route type="mix" sink="BT SCO Headset"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+ <route type="mix" sink="BT SCO Car Kit"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+ <route type="mix" sink="Telephony Tx" sources="incall playback,voice call tx" />
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="hotword input"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="incall capture" sources="Voice Call And Telephony Rx" />
+ <route type="mix" sink="voice call rx" sources="Voice Call And Telephony Rx" />
+ <route type="mix" sink="voip_tx"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="fast input"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="mmap_no_irq_in"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="hifi_input" sources="USB Device In,USB Headset In" />
+ <route type="mix" sink="echo_ref_input" sources="Echo Ref In"/>
+ </routes>
+ </module>
+ <!-- Usb Audio HAL -->
+ <module name="usbv2" halVersion="2.0">
+ <mixPorts>
+ <mixPort name="usb_accessory output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="USB Host Out"
+ sources="usb_accessory output"/>
+ </routes>
+ </module>
+ </modules>
+ <!-- End of Modules section -->
+</audioPolicyConfiguration>
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 84a3d26..eb8708e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -4340,14 +4340,9 @@
// Notify app ops that the camera is not available
mOpsCallback = new OpsCallback(this);
- if (flags::watch_foreground_changes()) {
- mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
- toString16(mClientPackageName),
- AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
- } else {
- mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
- toString16(mClientPackageName), mOpsCallback);
- }
+ mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
+ toString16(mClientPackageName),
+ AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
// Just check for camera acccess here on open - delay startOp until
// camera frames start streaming in startCameraStreamingOps
@@ -4530,19 +4525,10 @@
// (WAR for b/175320666)the AppOpsManager could return MODE_IGNORED. Do not treat such
// cases as error.
if (!mUidIsTrusted) {
- if (flags::watch_foreground_changes()) {
- if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
- setCameraMute(true);
- } else {
- block();
- }
+ if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
+ setCameraMute(true);
} else {
- if (isUidActive && isCameraPrivacyEnabled && supportsCameraMute()) {
- setCameraMute(true);
- } else if (!isUidActive
- || (isCameraPrivacyEnabled && !supportsCameraMute())) {
- block();
- }
+ block();
}
}
} else if (res == AppOpsManager::MODE_ALLOWED) {
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.cpp b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
index 1c1bd24..ad1a84f 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.cpp
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
@@ -17,11 +17,14 @@
#define LOG_TAG "CameraServiceWatchdog"
#include "CameraServiceWatchdog.h"
+#include "com_android_internal_camera_flags.h"
#include "android/set_abort_message.h"
#include "utils/CameraServiceProxyWrapper.h"
namespace android {
+namespace flags = com::android::internal::camera::flags;
+
bool CameraServiceWatchdog::threadLoop()
{
{
@@ -51,6 +54,12 @@
true /*deviceError*/);
// We use abort here so we can get a tombstone for better
// debugging.
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ for (pid_t pid : mProviderPids) {
+ kill(pid, SIGABRT);
+ }
+ }
+
abort();
}
}
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
index 165dece..691a274 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.h
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -30,6 +30,7 @@
*/
#pragma once
#include <chrono>
+#include <set>
#include <thread>
#include <time.h>
#include <utils/Thread.h>
@@ -57,16 +58,17 @@
};
public:
- explicit CameraServiceWatchdog(const std::string &cameraId,
+
+ explicit CameraServiceWatchdog(const std::set<pid_t> &pids, const std::string &cameraId,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
- mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
+ mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
mCycleLengthMs(kCycleLengthMs), mEnabled(true),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
- explicit CameraServiceWatchdog (const std::string &cameraId, size_t maxCycles,
- uint32_t cycleLengthMs, bool enabled,
+ explicit CameraServiceWatchdog (const std::set<pid_t> &pids, const std::string &cameraId,
+ size_t maxCycles, uint32_t cycleLengthMs, bool enabled,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
- mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
+ mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
mCycleLengthMs(cycleLengthMs), mEnabled(enabled),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
@@ -90,7 +92,8 @@
// Lock for mEnabled
mEnabledLock.lock();
sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog(
- mCameraId, cycles, cycleLength, mEnabled, mCameraServiceProxyWrapper);
+ mProviderPids, mCameraId, cycles, cycleLength, mEnabled,
+ mCameraServiceProxyWrapper);
mEnabledLock.unlock();
status_t status = tempWatchdog->run("CameraServiceWatchdog");
@@ -150,6 +153,7 @@
Mutex mWatchdogLock; // Lock for condition variable
Mutex mEnabledLock; // Lock for enabled status
Condition mWatchdogCondition; // Condition variable for stop/start
+ std::set<pid_t> mProviderPids; // Process ID set of camera providers
std::string mCameraId; // Camera Id the watchdog belongs to
bool mPause; // True if tid map is empty
uint32_t mMaxCycles; // Max cycles
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 4270ce2..8c44e35 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -553,7 +553,7 @@
mRunningSessionStats.mUsedUltraWide = true;
}
}
- if (!mRunningSessionStats.mUsedSettingsOverrideZoom && flags::log_zoom_override_usage()) {
+ if (!mRunningSessionStats.mUsedSettingsOverrideZoom) {
entry = physicalSettingsList.begin()->metadata.find(
ANDROID_CONTROL_SETTINGS_OVERRIDE);
if (entry.count == 1 && entry.data.i32[0] ==
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 2440c37..db39b39 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -34,6 +34,7 @@
#include <inttypes.h>
#include <android_companion_virtualdevice_flags.h>
#include <android_companion_virtualdevice_build_flags.h>
+#include <android/binder_libbinder.h>
#include <android/binder_manager.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
@@ -148,11 +149,7 @@
using aidl::android::hardware::camera::provider::ICameraProvider;
AIBinder* binder = nullptr;
- if (flags::lazy_aidl_wait_for_service()) {
- binder = AServiceManager_waitForService(serviceName.c_str());
- } else {
- binder = AServiceManager_checkService(serviceName.c_str());
- }
+ binder = AServiceManager_waitForService(serviceName.c_str());
if (binder == nullptr) {
ALOGE("%s: AIDL Camera provider HAL '%s' is not actually available, despite waiting "
@@ -2135,7 +2132,19 @@
}
AidlProviderInfo *aidlProviderInfo = static_cast<AidlProviderInfo *>(providerInfo.get());
- return aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
+ status_t res = aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
+
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ pid_t pid = 0;
+
+ if (AIBinder_toPlatformBinder(interface->asBinder().get())->getDebugPid(&pid) == OK
+ && res == OK) {
+ std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+ mProviderPidMap[providerInfo->mProviderInstance] = pid;
+ }
+ }
+
+ return res;
}
status_t CameraProviderManager::tryToInitializeHidlProviderLocked(
@@ -2152,7 +2161,23 @@
}
HidlProviderInfo *hidlProviderInfo = static_cast<HidlProviderInfo *>(providerInfo.get());
- return hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+ status_t res = hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ pid_t pid = 0;
+
+ auto ret = interface->getDebugInfo([&pid](
+ const ::android::hidl::base::V1_0::DebugInfo& info) {
+ pid = info.pid;
+ });
+
+ if (ret.isOk() && res == OK) {
+ std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+ mProviderPidMap[providerInfo->mProviderInstance] = pid;
+ }
+ }
+
+ return res;
}
status_t CameraProviderManager::addAidlProviderLocked(const std::string& newProvider) {
@@ -2163,14 +2188,11 @@
bool preexisting =
(mAidlProviderWithBinders.find(newProvider) != mAidlProviderWithBinders.end());
using aidl::android::hardware::camera::provider::ICameraProvider;
- std::string providerNameUsed =
- newProvider.substr(std::string(ICameraProvider::descriptor).size() + 1);
- if (flags::lazy_aidl_wait_for_service()) {
- // 'newProvider' has the fully qualified name of the provider service in case of AIDL.
- // ProviderInfo::mProviderName also has the fully qualified name - so we just compare them
- // here.
- providerNameUsed = newProvider;
- }
+
+ // 'newProvider' has the fully qualified name of the provider service in case of AIDL.
+ // ProviderInfo::mProviderName also has the fully qualified name - so we just compare them
+ // here.
+ std::string providerNameUsed = newProvider;
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == providerNameUsed) {
@@ -2264,20 +2286,23 @@
ALOGW("%s: Camera provider HAL with name '%s' is not registered", __FUNCTION__,
provider.c_str());
} else {
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ {
+ std::lock_guard<std::mutex> pidLock(mProviderPidMapLock);
+ mProviderPidMap.erase(provider);
+ }
+ }
+
// Check if there are any newer camera instances from the same provider and try to
// initialize.
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == removedProviderName) {
IPCTransport providerTransport = providerInfo->getIPCTransport();
- std::string removedAidlProviderName = getFullAidlProviderName(removedProviderName);
- if (flags::lazy_aidl_wait_for_service()) {
- removedAidlProviderName = removedProviderName;
- }
switch(providerTransport) {
case IPCTransport::HIDL:
return tryToInitializeHidlProviderLocked(removedProviderName, providerInfo);
case IPCTransport::AIDL:
- return tryToInitializeAidlProviderLocked(removedAidlProviderName,
+ return tryToInitializeAidlProviderLocked(removedProviderName,
providerInfo);
default:
ALOGE("%s Unsupported Transport %d", __FUNCTION__, eToI(providerTransport));
@@ -2443,7 +2468,7 @@
bool CameraProviderManager::ProviderInfo::isExternalLazyHAL() const {
std::string providerName = mProviderName;
- if (flags::lazy_aidl_wait_for_service() && getIPCTransport() == IPCTransport::AIDL) {
+ if (getIPCTransport() == IPCTransport::AIDL) {
using aidl::android::hardware::camera::provider::ICameraProvider;
providerName =
mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1);
@@ -2451,6 +2476,20 @@
return kEnableLazyHal && (providerName == kExternalProviderName);
}
+std::set<pid_t> CameraProviderManager::getProviderPids() {
+ std::set<pid_t> pids;
+
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+
+ std::transform(mProviderPidMap.begin(), mProviderPidMap.end(),
+ std::inserter(pids, pids.begin()),
+ [](std::pair<const std::string, pid_t>& entry) { return entry.second; });
+ }
+
+ return pids;
+}
+
status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
mProviderInstance.c_str(),
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 4a64b44..b686a58 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -431,6 +431,11 @@
// LocalRegistrationCallback::onServiceRegistration
virtual void onServiceRegistration(const String16& name, const sp<IBinder> &binder) override;
+ /*
+ * Return list of provider pid
+ */
+ std::set<pid_t> getProviderPids();
+
/**
* Dump out information about available providers and devices
*/
@@ -914,6 +919,9 @@
// Provider names of AIDL providers with retrieved binders.
std::set<std::string> mAidlProviderWithBinders;
+ std::mutex mProviderPidMapLock;
+ std::map<std::string, pid_t> mProviderPidMap;
+
static const char* deviceStatusToString(
const hardware::camera::common::V1_0::CameraDeviceStatus&);
static const char* torchStatusToString(
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 5c0e2c6..45a31ee 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -109,11 +109,8 @@
std::shared_ptr<ICameraProvider>& interface, int64_t currentDeviceState) {
using aidl::android::hardware::camera::provider::ICameraProvider;
- std::string parsedProviderName = mProviderName;
- if (flags::lazy_aidl_wait_for_service()) {
- parsedProviderName =
+ std::string parsedProviderName =
mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1);
- }
status_t res = parseProviderName(parsedProviderName, &mType, &mId);
if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 11891e9..0cb9b1d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -133,7 +133,7 @@
return mId;
}
-status_t Camera3Device::initializeCommonLocked() {
+status_t Camera3Device::initializeCommonLocked(sp<CameraProviderManager> manager) {
/** Start up status tracker thread */
mStatusTracker = new StatusTracker(this);
@@ -251,7 +251,8 @@
mInjectionMethods = createCamera3DeviceInjectionMethods(this);
/** Start watchdog thread */
- mCameraServiceWatchdog = new CameraServiceWatchdog(mId, mCameraServiceProxyWrapper);
+ mCameraServiceWatchdog = new CameraServiceWatchdog(
+ manager->getProviderPids(), mId, mCameraServiceProxyWrapper);
res = mCameraServiceWatchdog->run("CameraServiceWatchdog");
if (res != OK) {
SET_ERR_L("Unable to start camera service watchdog thread: %s (%d)",
@@ -1835,10 +1836,7 @@
mSessionStatsBuilder.stopCounter();
}
- // Calculate expected duration for flush with additional buffer time in ms for watchdog
- uint64_t maxExpectedDuration = ns2ms(getExpectedInFlightDuration() + kBaseGetBufferWait);
- status_t res = mCameraServiceWatchdog->WATCH_CUSTOM_TIMER(mRequestThread->flush(),
- maxExpectedDuration / kCycleLengthMs, kCycleLengthMs);
+ status_t res = mCameraServiceWatchdog->WATCH(mRequestThread->flush());
return res;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index e5ccbae..3cfe3c9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -726,7 +726,7 @@
*
* Must be called with mLock and mInterfaceLock held.
*/
- status_t initializeCommonLocked();
+ status_t initializeCommonLocked(sp<CameraProviderManager> manager);
/**
* Update capture request list so that each batch size honors the batch_size_max report from
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 04867b9..83c8a38 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -687,11 +687,7 @@
}
}
- if (flags::surface_ipc()) {
- res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
- } else {
- res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount);
- }
+ res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
if (res != OK) {
ALOGE("%s: Unable to set buffer count for stream %d",
__FUNCTION__, mId);
@@ -1035,7 +1031,7 @@
status_t Camera3OutputStream::getEndpointUsageForSurface(uint64_t *usage,
const sp<Surface>& surface) {
bool internalConsumer = (mConsumer.get() != nullptr) && (mConsumer == surface);
- if (mConsumerUsageCachedValue.has_value() && flags::surface_ipc() && internalConsumer) {
+ if (mConsumerUsageCachedValue.has_value() && internalConsumer) {
*usage = mConsumerUsageCachedValue.value();
return OK;
}
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 57297bc..868b7ef 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -349,7 +349,7 @@
readoutSupported.data.u8[0] == ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
}
- return initializeCommonLocked();
+ return initializeCommonLocked(manager);
}
::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::processCaptureResult(
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 09299e6..f507df9 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -303,7 +303,7 @@
}
mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
- return initializeCommonLocked();
+ return initializeCommonLocked(manager);
}
hardware::Return<void> HidlCamera3Device::requestStreamBuffers(
diff --git a/services/camera/libcameraservice/utils/Utils.cpp b/services/camera/libcameraservice/utils/Utils.cpp
index 76517dc..e9810c6 100644
--- a/services/camera/libcameraservice/utils/Utils.cpp
+++ b/services/camera/libcameraservice/utils/Utils.cpp
@@ -77,28 +77,26 @@
RunThreadWithRealtimePriority::RunThreadWithRealtimePriority(int tid)
: mTid(tid), mPreviousPolicy(sched_getscheduler(tid)) {
- if (flags::realtime_priority_bump()) {
- auto res = sched_getparam(mTid, &mPreviousParams);
- if (res != OK) {
- ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
- return;
- }
+ auto res = sched_getparam(mTid, &mPreviousParams);
+ if (res != OK) {
+ ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
+ return;
+ }
- struct sched_param param = {0};
- param.sched_priority = kRequestThreadPriority;
+ struct sched_param param = {0};
+ param.sched_priority = kRequestThreadPriority;
- res = sched_setscheduler(mTid, SCHED_FIFO, ¶m);
- if (res != OK) {
- ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
- } else {
- ALOGD("Set real time priority for thread (tid %d)", mTid);
- mPolicyBumped = true;
- }
+ res = sched_setscheduler(mTid, SCHED_FIFO, ¶m);
+ if (res != OK) {
+ ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
+ } else {
+ ALOGD("Set real time priority for thread (tid %d)", mTid);
+ mPolicyBumped = true;
}
}
RunThreadWithRealtimePriority::~RunThreadWithRealtimePriority() {
- if (mPolicyBumped && flags::realtime_priority_bump()) {
+ if (mPolicyBumped) {
auto res = sched_setscheduler(mTid, mPreviousPolicy, &mPreviousParams);
if (res != OK) {
ALOGE("Can't set regular priority for thread: %s (%d)", strerror(-res), res);
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index 7ece0cb..dd64daa 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -25,6 +25,7 @@
"libEGL",
"libGLESv2",
"libGLESv3",
+ "android.companion.virtualdevice.flags-aconfig-cc",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 40a96e4..bf4a45d 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
#define LOG_TAG "VirtualCameraRenderThread"
#include "VirtualCameraRenderThread.h"
+#include <android_companion_virtualdevice_flags.h>
+
#include <chrono>
#include <cstdint>
#include <cstring>
@@ -46,13 +49,11 @@
#include "android-base/thread_annotations.h"
#include "android/binder_auto_utils.h"
#include "android/hardware_buffer.h"
-#include "hardware/gralloc.h"
#include "system/camera_metadata.h"
#include "ui/GraphicBuffer.h"
#include "ui/Rect.h"
#include "util/EglFramebuffer.h"
#include "util/JpegUtil.h"
-#include "util/MetadataUtil.h"
#include "util/Util.h"
#include "utils/Errors.h"
@@ -91,6 +92,8 @@
using namespace std::chrono_literals;
+namespace flags = ::android::companion::virtualdevice::flags;
+
static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024; // 32 KiB
@@ -117,12 +120,12 @@
NotifyMsg createRequestErrorNotifyMsg(int frameNumber) {
NotifyMsg msg;
- msg.set<NotifyMsg::Tag::error>(ErrorMsg{
- .frameNumber = frameNumber,
- // errorStreamId needs to be set to -1 for ERROR_REQUEST
- // (not tied to specific stream).
- .errorStreamId = -1,
- .errorCode = ErrorCode::ERROR_REQUEST});
+ msg.set<NotifyMsg::Tag::error>(
+ ErrorMsg{.frameNumber = frameNumber,
+ // errorStreamId needs to be set to -1 for ERROR_REQUEST
+ // (not tied to specific stream).
+ .errorStreamId = -1,
+ .errorCode = ErrorCode::ERROR_REQUEST});
return msg;
}
@@ -413,29 +416,8 @@
std::memory_order_relaxed));
if (request.getRequestSettings().fpsRange) {
- const int maxFps =
- std::max(1, request.getRequestSettings().fpsRange->maxFps);
- const std::chrono::nanoseconds minFrameDuration(
- static_cast<uint64_t>(1e9 / maxFps));
- const std::chrono::nanoseconds frameDuration =
- timestamp - lastAcquisitionTimestamp;
- if (frameDuration < minFrameDuration) {
- // We're too fast for the configured maxFps, let's wait a bit.
- const std::chrono::nanoseconds sleepTime =
- minFrameDuration - frameDuration;
- ALOGV("Current frame duration would be %" PRIu64
- " ns corresponding to, "
- "sleeping for %" PRIu64
- " ns before updating texture to match maxFps %d",
- static_cast<uint64_t>(frameDuration.count()),
- static_cast<uint64_t>(sleepTime.count()), maxFps);
-
- std::this_thread::sleep_for(sleepTime);
- timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::steady_clock::now().time_since_epoch());
- mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
- std::memory_order_relaxed);
- }
+ int maxFps = std::max(1, request.getRequestSettings().fpsRange->maxFps);
+ timestamp = throttleRendering(maxFps, lastAcquisitionTimestamp, timestamp);
}
// Calculate the maximal amount of time we can afford to wait for next frame.
@@ -463,6 +445,17 @@
}
// Acquire new (most recent) image from the Surface.
mEglSurfaceTexture->updateTexture();
+ std::chrono::nanoseconds captureTimestamp = timestamp;
+
+ if (flags::camera_timestamp_from_surface()) {
+ std::chrono::nanoseconds surfaceTimestamp =
+ getSurfaceTimestamp(elapsedDuration);
+ if (surfaceTimestamp.count() > 0) {
+ captureTimestamp = surfaceTimestamp;
+ }
+ ALOGV("%s captureTimestamp:%lld timestamp:%lld", __func__,
+ captureTimestamp.count(), timestamp.count());
+ }
CaptureResult captureResult;
captureResult.fmqResultSize = 0;
@@ -472,7 +465,7 @@
captureResult.inputBuffer.streamId = -1;
captureResult.physicalCameraMetadata.resize(0);
captureResult.result = createCaptureResultMetadata(
- timestamp, request.getRequestSettings(), mReportedSensorSize);
+ captureTimestamp, request.getRequestSettings(), mReportedSensorSize);
const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
captureResult.outputBuffers.resize(buffers.size());
@@ -506,7 +499,7 @@
}
std::vector<NotifyMsg> notifyMsg{
- createShutterNotifyMsg(request.getFrameNumber(), timestamp)};
+ createShutterNotifyMsg(request.getFrameNumber(), captureTimestamp)};
for (const StreamBuffer& resBuffer : captureResult.outputBuffers) {
if (resBuffer.status != BufferStatus::OK) {
notifyMsg.push_back(createBufferErrorNotifyMsg(request.getFrameNumber(),
@@ -535,6 +528,51 @@
ALOGV("%s: Successfully called processCaptureResult", __func__);
}
+std::chrono::nanoseconds VirtualCameraRenderThread::throttleRendering(
+ int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
+ std::chrono::nanoseconds timestamp) {
+ const std::chrono::nanoseconds minFrameDuration(
+ static_cast<uint64_t>(1e9 / maxFps));
+ const std::chrono::nanoseconds frameDuration =
+ timestamp - lastAcquisitionTimestamp;
+ if (frameDuration < minFrameDuration) {
+ // We're too fast for the configured maxFps, let's wait a bit.
+ const std::chrono::nanoseconds sleepTime = minFrameDuration - frameDuration;
+ ALOGV("Current frame duration would be %" PRIu64
+ " ns corresponding to, "
+ "sleeping for %" PRIu64
+ " ns before updating texture to match maxFps %d",
+ static_cast<uint64_t>(frameDuration.count()),
+ static_cast<uint64_t>(sleepTime.count()), maxFps);
+
+ std::this_thread::sleep_for(sleepTime);
+ timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+ mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
+ std::memory_order_relaxed);
+ }
+ return timestamp;
+}
+
+std::chrono::nanoseconds VirtualCameraRenderThread::getSurfaceTimestamp(
+ std::chrono::nanoseconds timeSinceLastFrame) {
+ std::chrono::nanoseconds surfaceTimestamp = mEglSurfaceTexture->getTimestamp();
+ if (surfaceTimestamp.count() < 0) {
+ uint64_t lastSurfaceTimestamp = mLastSurfaceTimestampNanoseconds.load();
+ if (lastSurfaceTimestamp > 0) {
+ // The timestamps were provided by the producer but we are
+ // repeating the last frame, so we increase the previous timestamp by
+ // the elapsed time sinced its capture, otherwise the camera framework
+ // will discard the frame.
+ surfaceTimestamp = std::chrono::nanoseconds(lastSurfaceTimestamp +
+ timeSinceLastFrame.count());
+ }
+ }
+ mLastSurfaceTimestampNanoseconds.store(surfaceTimestamp.count(),
+ std::memory_order_relaxed);
+ return surfaceTimestamp;
+}
+
void VirtualCameraRenderThread::flushCaptureRequest(
const ProcessCaptureRequestTask& request) {
CaptureResult captureResult;
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index aafed44..a35eea1 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -18,6 +18,7 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERARENDERTHREAD_H
#include <atomic>
+#include <chrono>
#include <cstdint>
#include <deque>
#include <future>
@@ -188,6 +189,22 @@
EglFrameBuffer& framebuffer, sp<Fence> fence = nullptr,
std::optional<Rect> viewport = std::nullopt);
+ // Throttle the current thread to ensure that we are not rendering faster than
+ // the provided maxFps.
+ // maxFps: The maximum fps in the capture request
+ // lastAcquisitionTimestamp: timestamp of the previous frame
+ // timestamp: the current capture time
+ // Returns the time at which the capture has happened after throttling.
+ std::chrono::nanoseconds throttleRendering(
+ int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
+ std::chrono::nanoseconds timestamp);
+
+ // Fetch the timestamp of the latest buffer from the EGL Surface
+ // timeSinceLastFrame: The elapsed time since the last captured frame.
+ // Return 0 if no timestamp has been associated to this surface by the producer.
+ std::chrono::nanoseconds getSurfaceTimestamp(
+ std::chrono::nanoseconds timeSinceLastFrame);
+
// Camera callback
const std::shared_ptr<
::aidl::android::hardware::camera::device::ICameraDeviceCallback>
@@ -209,6 +226,7 @@
// Acquisition timestamp of last frame.
std::atomic<uint64_t> mLastAcquisitionTimestampNanoseconds;
+ std::atomic<uint64_t> mLastSurfaceTimestampNanoseconds;
// EGL helpers - constructed and accessed only from rendering thread.
std::unique_ptr<EglDisplayContext> mEglDisplayContext;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 98bf62a..be36ec4 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -15,6 +15,8 @@
*/
// #define LOG_NDEBUG 0
+#include <chrono>
+
#include "utils/Timers.h"
#define LOG_TAG "EglSurfaceTexture"
@@ -99,6 +101,10 @@
static_cast<nsecs_t>(timeout.count()));
}
+std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() {
+ return std::chrono::nanoseconds(mGlConsumer->getTimestamp());
+}
+
GLuint EglSurfaceTexture::updateTexture() {
int previousFrameId;
int framesAdvance = 0;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index a46af8f..c1f1169 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -82,6 +82,10 @@
// See SurfaceTexture.getTransformMatrix for more details.
std::array<float, 16> getTransformMatrix();
+ // Retrieves the timestamp associated with the texture image
+ // set by the most recent call to updateTexture.
+ std::chrono::nanoseconds getTimestamp();
+
private:
#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<IGraphicBufferProducer> mBufferProducer;