Merge "CCodecBufferChannel: remove rendering depth" into main
diff --git a/camera/Android.bp b/camera/Android.bp
index 9e1efae..b6241f4 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -54,7 +54,13 @@
cc_aconfig_library {
name: "camera_platform_flags_c_lib",
aconfig_declarations: "camera_platform_flags",
+}
+
+cc_aconfig_library {
+ name: "camera_platform_flags_c_lib_for_test",
+ aconfig_declarations: "camera_platform_flags",
host_supported: true,
+ mode: "test",
}
java_aconfig_library {
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 6862cb1..d0df90b 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -22,6 +22,11 @@
default_applicable_licenses: ["frameworks_av_camera_license"],
}
+vintf_fragment {
+ name: "manifest_android.frameworks.cameraservice.service.xml",
+ src: "manifest_android.frameworks.cameraservice.service.xml",
+}
+
cc_binary {
name: "cameraserver",
@@ -61,7 +66,7 @@
init_rc: ["cameraserver.rc"],
- vintf_fragments: [
+ vintf_fragment_modules: [
"manifest_android.frameworks.cameraservice.service.xml",
],
}
diff --git a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
index f046785..97a8cc4 100644
--- a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
+++ b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
@@ -35,7 +35,8 @@
class DrmRemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
public:
DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm, std::string drmVendor,
- std::string drmDesc, std::vector<uint8_t> bcc);
+ std::string drmDesc, std::vector<uint8_t> bcc,
+ std::vector<uint8_t> bcc_signature);
ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
@@ -60,6 +61,7 @@
std::string mDrmVendor;
std::string mDrmDesc;
std::vector<uint8_t> mBcc;
+ std::vector<uint8_t> mBccSignature;
};
} // namespace android::mediadrm
diff --git a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
index 440be79..65054b0 100644
--- a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
+++ b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
@@ -28,11 +28,13 @@
DrmRemotelyProvisionedComponent::DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm,
std::string drmVendor,
std::string drmDesc,
- std::vector<uint8_t> bcc)
+ std::vector<uint8_t> bcc,
+ std::vector<uint8_t> bcc_signature)
: mDrm(std::move(drm)),
mDrmVendor(std::move(drmVendor)),
mDrmDesc(std::move(drmDesc)),
- mBcc(std::move(bcc)) {}
+ mBcc(std::move(bcc)),
+ mBccSignature(std::move(bcc_signature)) {}
ScopedAStatus DrmRemotelyProvisionedComponent::getHardwareInfo(RpcHardwareInfo* info) {
info->versionNumber = 3;
@@ -107,7 +109,7 @@
for (auto i : keyToProp) {
auto key = i.first;
auto prop = i.second;
- const auto& val= deviceInfoMap.get(key);
+ const auto& val = deviceInfoMap.get(key);
if (val == nullptr || val->asTstr()->value().empty()) {
std::string propValue = android::base::GetProperty(prop, "");
if (propValue.empty()) {
@@ -161,12 +163,16 @@
}
// assemble AuthenticatedRequest (definition in IRemotelyProvisionedComponent.aidl)
- *out = cppbor::Array()
- .add(1 /* version */)
- .add(cppbor::Map() /* UdsCerts */)
- .add(cppbor::EncodedItem(mBcc))
- .add(cppbor::EncodedItem(std::move(deviceSignedCsrPayload)))
- .encode();
+ cppbor::Array request_array = cppbor::Array().add(1 /* version */);
+ if (!mBccSignature.empty()) {
+ request_array.add(cppbor::EncodedItem(mBccSignature) /* UdsCerts */);
+ } else {
+ request_array.add(cppbor::Map() /* empty UdsCerts */);
+ }
+ request_array.add(cppbor::EncodedItem(mBcc))
+ .add(cppbor::EncodedItem(std::move(deviceSignedCsrPayload)));
+ *out = request_array.encode();
+
return ScopedAStatus::ok();
}
} // namespace android::mediadrm
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
index 515d157..750b51e 100644
--- a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
+++ b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
@@ -87,13 +87,21 @@
status.getDescription().c_str());
return;
}
-
+ std::vector<uint8_t> bcc_signature;
+ status =
+ mDrm->getPropertyByteArray("bootCertificateChainSignature", &bcc_signature);
+ if (!status.isOk()) {
+ ALOGW("mDrm->getPropertyByteArray(\"bootCertificateChainSignature\") failed."
+ "Detail: [%s].",
+ status.getDescription().c_str());
+ // bcc signature is optional, no need to return when it is unavailable.
+ }
std::string compName(instance);
auto comps = static_cast<
std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>>*>(
context);
(*comps)[compName] = ::ndk::SharedRefBase::make<DrmRemotelyProvisionedComponent>(
- mDrm, drmVendor, drmDesc, bcc);
+ mDrm, drmVendor, drmDesc, bcc, bcc_signature);
});
return comps;
}
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 1a637ac..695cad6 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -45,6 +45,32 @@
"file_patterns": ["(?i)drm|crypto"]
}
],
+ "postsubmit": [
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-filter": "android.media.codec.cts.EncodeDecodeTest"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-filter": "android.media.codec.cts.DecodeEditEncodeTest"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-filter": "android.media.codec.cts.ExtractDecodeEditEncodeMuxTest"
+ }
+ ]
+ }
+ ],
// Postsubmit tests for TV devices
"tv-postsubmit": [
{
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index c0ebcd5..14540b7 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -13,6 +13,16 @@
}
flag {
+ name: "codec_buffer_state_cleanup"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for more buffer state cleanup in MediaCodec"
+ bug: "343502509"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "dataspace_v0_partial"
namespace: "codec_fwk"
description: "Bugfix flag for using V0 dataspace in some cases"
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index de8aca7..a5aeff2 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -50,6 +50,23 @@
}
cc_aconfig_library {
+ name: "com.android.media.audioserver-aconfig-cc-ro",
+ aconfig_declarations: "com.android.media.audioserver-aconfig",
+ defaults: ["audio-aconfig-cc-defaults"],
+ double_loadable: true,
+ host_supported: true,
+ product_available: true,
+ vendor_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
+ mode: "force-read-only",
+}
+
+cc_aconfig_library {
name: "com.android.media.audio-aconfig-cc",
aconfig_declarations: "com.android.media.audio-aconfig",
defaults: ["audio-aconfig-cc-defaults"],
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 0209e28..ea5f26d 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -40,6 +40,14 @@
bug: "316414750"
}
+flag {
+ name: "dolby_ac4_level4_encoding_api"
+ namespace: "media_audio"
+ description: "Feature flag for Dolby AC-4 level 4 AudioFormat encoding."
+ is_fixed_read_only: true
+ bug: "266537650"
+}
+
# TODO remove
flag {
name: "foreground_audio_control"
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 01b6e42..90996a3 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -741,6 +741,8 @@
{// Note: not in the IANA registry.
AUDIO_FORMAT_APTX_HD, make_AudioFormatDescription("audio/vnd.qcom.aptx.hd")},
{AUDIO_FORMAT_AC4, make_AudioFormatDescription(::android::MEDIA_MIMETYPE_AUDIO_AC4)},
+ {AUDIO_FORMAT_AC4_L4, make_AudioFormatDescription(
+ std::string(::android::MEDIA_MIMETYPE_AUDIO_AC4) + ";version=02.01.04")},
{// Note: not in the IANA registry.
AUDIO_FORMAT_LDAC, make_AudioFormatDescription("audio/vnd.sony.ldac")},
{AUDIO_FORMAT_MAT,
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 722b13a..93009c4 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -466,6 +466,7 @@
aom_codec_err_t C2SoftAomEnc::setupCodecParameters() {
aom_codec_err_t codec_return = AOM_CODEC_OK;
+ const int maxIntraBitratePct = mBitrateControlMode == AOM_CBR ? 300 : 450;
codec_return = aom_codec_control(mCodecContext, AV1E_SET_TARGET_SEQ_LEVEL_IDX, mAV1EncLevel);
if (codec_return != AOM_CODEC_OK) goto BailOut;
@@ -492,6 +493,10 @@
codec_return = aom_codec_control(mCodecContext, AV1E_SET_AQ_MODE, 3);
if (codec_return != AOM_CODEC_OK) goto BailOut;
+ codec_return = aom_codec_control(mCodecContext, AOME_SET_MAX_INTRA_BITRATE_PCT,
+ maxIntraBitratePct);
+ if (codec_return != AOM_CODEC_OK) goto BailOut;
+
codec_return = aom_codec_control(mCodecContext, AV1E_SET_COEFF_COST_UPD_FREQ, 3);
if (codec_return != AOM_CODEC_OK) goto BailOut;
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 149c6ee..aed5e68 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -114,7 +114,9 @@
c2_status_t C2SoftMP3::onStop() {
// Make sure that the next buffer output does not still
// depend on fragments from the last one decoded.
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ if (mDecoderBuf) {
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ }
mSignalledError = false;
mIsFirst = true;
mSignalledOutputEos = false;
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..bb4c596 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -52,6 +52,13 @@
using ::aidl::android::hardware::media::bufferpool2::IClientManager;
struct ComponentStore : public BnComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -120,6 +127,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/common/include/codec2/common/BqPoolInvalidateHelper.h b/media/codec2/hal/common/include/codec2/common/BqPoolInvalidateHelper.h
new file mode 100644
index 0000000..859f703
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/BqPoolInvalidateHelper.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <C2BqBufferPriv.h>
+#include <C2PlatformSupport.h>
+
+namespace android {
+
+// filter fn from component's blockpool container to bqpool conatainer
+static inline bool BqPoolFilterFn(
+ std::pair<const uint64_t, std::shared_ptr<C2BlockPool>> pool) {
+ return (pool.second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE);
+}
+
+// convert fn from component's blockpool container to bqpool container
+static inline std::shared_ptr<C2BufferQueueBlockPool> BqPoolConvertFn(
+ std::pair<const uint64_t, std::shared_ptr<C2BlockPool>> pool) {
+ return std::static_pointer_cast<C2BufferQueueBlockPool>(pool.second);
+}
+
+// This is similar to std::transform excpet there is \pred functor parameter.
+// The elements with \pred function value \true only will be transformed and
+// added to the dest container. (For portability std::ranges are not used.)
+template <class InputIt, class OutputIt, class Pred, class Fct>
+void transform_if(InputIt first, InputIt last, OutputIt dest, Pred pred, Fct transform)
+{
+ while (first != last) {
+ if (pred(*first)) {
+ *dest++ = transform(*first);
+ }
+ ++first;
+ }
+}
+
+} // namespace android
diff --git a/media/codec2/hal/hidl/1.0/utils/Component.cpp b/media/codec2/hal/hidl/1.0/utils/Component.cpp
index 62f0e25..162a80e 100644
--- a/media/codec2/hal/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/Component.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "Codec2-Component"
#include <android-base/logging.h>
+#include <codec2/common/BqPoolInvalidateHelper.h>
#include <codec2/hidl/1.0/Component.h>
#include <codec2/hidl/1.0/ComponentStore.h>
#include <codec2/hidl/1.0/InputBufferManager.h>
@@ -30,6 +31,7 @@
#include <utils/Timers.h>
#include <C2BqBufferPriv.h>
+#include <C2BqPoolInvalidator.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
@@ -270,16 +272,17 @@
}
void Component::onDeathReceived() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mClientDied = true;
- for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
- if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
- std::shared_ptr<C2BufferQueueBlockPool> bqPool =
- std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
- bqPool->invalidate();
- }
- }
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ if (!bqPools.empty()) {
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
+ std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ bqInvalidateItem->invalidate();
}
release();
}
@@ -549,7 +552,26 @@
}
Return<Status> Component::release() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ if (!mClientDied) {
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ }
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem;
+ if (!bqPools.empty()) {
+ // handling rare cases of process death just after release() called.
+ bqInvalidateItem = std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
+ }
Status status = static_cast<Status>(mComponent->release());
+ if (bqInvalidateItem) {
+ // If release is not blocked,
+ // skip invalidation and finish ASAP.
+ bqInvalidateItem->skip();
+ }
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
@@ -637,6 +659,18 @@
}
Component::~Component() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ if (!bqPools.empty()) {
+ LOG(ERROR) << "blockpools are not cleared yet at dtor";
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
+ std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
+ }
InputBufferManager::unregisterFrameData(mListener);
mStore->reportComponentDeath(this);
}
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..028238b 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
@@ -55,6 +55,13 @@
using ::android::sp;
struct ComponentStore : public IComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -124,6 +131,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/Component.cpp b/media/codec2/hal/hidl/1.1/utils/Component.cpp
index 7f2c4dd..1c2a49a 100644
--- a/media/codec2/hal/hidl/1.1/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/Component.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "Codec2-Component@1.1"
#include <android-base/logging.h>
+#include <codec2/common/BqPoolInvalidateHelper.h>
#include <codec2/hidl/1.1/Component.h>
#include <codec2/hidl/1.1/ComponentStore.h>
#include <codec2/hidl/1.1/InputBufferManager.h>
@@ -32,6 +33,7 @@
#include <codec2/common/MultiAccessUnitHelper.h>
#include <C2BqBufferPriv.h>
+#include <C2BqPoolInvalidator.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
@@ -274,16 +276,17 @@
}
void Component::onDeathReceived() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mClientDied = true;
- for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
- if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
- std::shared_ptr<C2BufferQueueBlockPool> bqPool =
- std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
- bqPool->invalidate();
- }
- }
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ if (!bqPools.empty()) {
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
+ std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ bqInvalidateItem->invalidate();
}
release();
}
@@ -555,7 +558,26 @@
}
Return<Status> Component::release() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ if (!mClientDied) {
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ }
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem;
+ if (!bqPools.empty()) {
+ // handling rare cases of process death just after release() called.
+ bqInvalidateItem = std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
+ }
Status status = static_cast<Status>(mComponent->release());
+ if (bqInvalidateItem) {
+ // If release is not blocked,
+ // skip invalidation and finish ASAP.
+ bqInvalidateItem->skip();
+ }
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
@@ -649,6 +671,18 @@
}
Component::~Component() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ if (!bqPools.empty()) {
+ LOG(ERROR) << "blockpools are not cleared yet at dtor";
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
+ std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
+ }
InputBufferManager::unregisterFrameData(mListener);
mStore->reportComponentDeath(this);
}
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..b023115 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
@@ -56,6 +56,13 @@
using ::android::sp;
struct ComponentStore : public IComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -132,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/hidl/1.2/utils/Component.cpp b/media/codec2/hal/hidl/1.2/utils/Component.cpp
index 7b0aa9b..a15febe 100644
--- a/media/codec2/hal/hidl/1.2/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/Component.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "Codec2-Component@1.2"
#include <android-base/logging.h>
+#include <codec2/common/BqPoolInvalidateHelper.h>
#include <codec2/hidl/1.2/Component.h>
#include <codec2/hidl/1.2/ComponentStore.h>
#include <codec2/hidl/1.2/InputBufferManager.h>
@@ -30,6 +31,7 @@
#include <utils/Timers.h>
#include <C2BqBufferPriv.h>
+#include <C2BqPoolInvalidator.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
@@ -272,16 +274,17 @@
}
void Component::onDeathReceived() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mClientDied = true;
- for (auto it = mBlockPools.begin(); it != mBlockPools.end(); ++it) {
- if (it->second->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
- std::shared_ptr<C2BufferQueueBlockPool> bqPool =
- std::static_pointer_cast<C2BufferQueueBlockPool>(it->second);
- bqPool->invalidate();
- }
- }
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ if (!bqPools.empty()) {
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
+ std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ bqInvalidateItem->invalidate();
}
release();
}
@@ -551,7 +554,26 @@
}
Return<Status> Component::release() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ if (!mClientDied) {
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ }
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem;
+ if (!bqPools.empty()) {
+ // handling rare cases of process death just after release() called.
+ bqInvalidateItem = std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
+ }
Status status = static_cast<Status>(mComponent->release());
+ if (bqInvalidateItem) {
+ // If release is not blocked,
+ // skip invalidation and finish ASAP.
+ bqInvalidateItem->skip();
+ }
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
@@ -676,6 +698,18 @@
}
Component::~Component() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> bqPools;
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ transform_if(mBlockPools.begin(), mBlockPools.end(), std::back_inserter(bqPools),
+ BqPoolFilterFn, BqPoolConvertFn);
+ }
+ if (!bqPools.empty()) {
+ LOG(ERROR) << "blockpools are not cleared yet at dtor";
+ std::shared_ptr<C2BqPoolInvalidateItem> bqInvalidateItem =
+ std::make_shared<C2BqPoolInvalidateItem>(std::move(bqPools));
+ C2BqPoolInvalidator::getInstance().queue(bqInvalidateItem);
+ }
InputBufferManager::unregisterFrameData(mListener);
mStore->reportComponentDeath(this);
}
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..a7e043b 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
@@ -56,6 +56,13 @@
using ::android::sp;
struct ComponentStore : public IComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -139,6 +146,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 f90363b..5c46d99 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -2063,6 +2063,14 @@
status_t CCodecBufferChannel::requestInitialInputBuffers(
std::map<size_t, sp<MediaCodecBuffer>> &&clientInputBuffers) {
+ std::optional<QueueGuard> guard;
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ guard.emplace(mSync);
+ if (!guard->isRunning()) {
+ ALOGD("[%s] skip requestInitialInputBuffers when not running", mName);
+ return OK;
+ }
+ }
C2StreamBufferTypeSetting::output oStreamFormat(0u);
C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
@@ -2639,8 +2647,6 @@
switch (action) {
case OutputBuffers::SKIP:
return;
- case OutputBuffers::DISCARD:
- break;
case OutputBuffers::NOTIFY_CLIENT:
{
// TRICKY: we want popped buffers reported in order, so sending
@@ -2667,13 +2673,16 @@
outBuffer->meta()->setObject("accessUnitInfo", obj);
}
}
+ mCallback->onOutputBufferAvailable(index, outBuffer);
+ [[fallthrough]];
+ }
+ case OutputBuffers::DISCARD: {
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));
+ ALOGV("[%s] onWorkDone: numProcessingBuffersBalance = %lld",
+ mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
}
- mCallback->onOutputBufferAvailable(index, outBuffer);
break;
}
case OutputBuffers::REALLOCATE:
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index dc06ee6..9d1cbff 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -53,7 +53,7 @@
],
defaults: [
- "aconfig_lib_cc_static_link.defaults",
+ "aconfig_lib_cc_static_link.defaults",
"libcodec2_hal_selection",
],
@@ -68,6 +68,7 @@
"C2PlatformStorePluginLoader.cpp",
"C2Store.cpp",
"platform/C2BqBuffer.cpp",
+ "platform/C2BqPoolInvalidator.cpp",
"platform/C2SurfaceSyncObj.cpp",
"platform/C2IgbaBuffer.cpp",
"types.cpp",
diff --git a/media/codec2/vndk/include/C2BqPoolInvalidator.h b/media/codec2/vndk/include/C2BqPoolInvalidator.h
new file mode 100644
index 0000000..612d023
--- /dev/null
+++ b/media/codec2/vndk/include/C2BqPoolInvalidator.h
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/no_destructor.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#include <condition_variable>
+#include <deque>
+#include <list>
+#include <memory>
+#include <thread>
+
+class C2BufferQueueBlockPool;
+
+namespace android {
+
+/**
+ * Container class in order to invalidate C2BufferQueueBlockPool(s) and their resources
+ * when the client process is dead abruptly.
+ */
+class C2BqPoolInvalidateItem {
+public:
+
+ /**
+ * invalidate contained C2BufferQueueBlockPool(s) and their resources
+ */
+ void invalidate();
+
+ /**
+ * skip invalidate(), if it is scheduled and not yet invalidated.
+ */
+ void skip();
+
+ /**
+ * returns whether invalidate() is reuqired or not.
+ */
+ bool needsInvalidate();
+
+ C2BqPoolInvalidateItem(std::list<std::shared_ptr<C2BufferQueueBlockPool>> &&pools);
+
+ ~C2BqPoolInvalidateItem() = default;
+private:
+
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> mPools;
+ bool mNeedsInvalidate;
+ std::mutex mLock;
+
+ DISALLOW_EVIL_CONSTRUCTORS(C2BqPoolInvalidateItem);
+};
+
+/**
+ * Asynchronous C2BufferQueueBlockPool invalidator.
+ *
+ * this has C2BqPoolInvalidateItem inside. and call invalidate() from a separate
+ * thread asynchronously.
+ */
+class C2BqPoolInvalidator {
+public:
+ /**
+ * This gets the singleton instance of the class.
+ */
+ static C2BqPoolInvalidator &getInstance();
+
+ /**
+ * queue invalidation items. the item will be invalidated after certain
+ * amount of delay from a separate thread.
+ */
+ void queue(std::shared_ptr<C2BqPoolInvalidateItem> &item);
+
+ ~C2BqPoolInvalidator();
+private:
+
+ C2BqPoolInvalidator();
+
+ void run();
+
+ std::thread mThread;
+ bool mDone;
+
+ std::mutex mMutex;
+ std::condition_variable mCv;
+
+ std::deque<std::pair<int64_t, std::shared_ptr<C2BqPoolInvalidateItem>>> mItems;
+
+ friend class ::android::base::NoDestructor<C2BqPoolInvalidator>;
+
+ DISALLOW_EVIL_CONSTRUCTORS(C2BqPoolInvalidator);
+};
+
+} // namespace android
diff --git a/media/codec2/vndk/platform/C2BqPoolInvalidator.cpp b/media/codec2/vndk/platform/C2BqPoolInvalidator.cpp
new file mode 100644
index 0000000..2666cd3
--- /dev/null
+++ b/media/codec2/vndk/platform/C2BqPoolInvalidator.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2BqPoolInvalidator"
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2BqPoolInvalidator.h>
+
+namespace android {
+
+namespace {
+ static constexpr int64_t kBqPoolInvalidateDelayMs = 1000;
+} // anonymous namespace
+
+C2BqPoolInvalidateItem::C2BqPoolInvalidateItem(
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> &&pools) : mPools(std::move(pools)) {
+ if (!mPools.empty()) {
+ mNeedsInvalidate = true;
+ } else {
+ mNeedsInvalidate = false;
+ }
+}
+
+void C2BqPoolInvalidateItem::invalidate() {
+ std::list<std::shared_ptr<C2BufferQueueBlockPool>> pools;
+ {
+ std::unique_lock<std::mutex> l(mLock);
+ if (!mNeedsInvalidate) {
+ return;
+ }
+ pools = std::move(mPools);
+ mNeedsInvalidate = false;
+ }
+ for(auto it = pools.begin(); it != pools.end(); ++it) {
+ (*it)->invalidate();
+ }
+}
+
+void C2BqPoolInvalidateItem::skip() {
+ std::unique_lock<std::mutex> l(mLock);
+ mNeedsInvalidate = false;
+ mPools.clear();
+}
+
+bool C2BqPoolInvalidateItem::needsInvalidate() {
+ std::unique_lock<std::mutex> l(mLock);
+ return mNeedsInvalidate;
+}
+
+C2BqPoolInvalidator &C2BqPoolInvalidator::getInstance() {
+ static android::base::NoDestructor<C2BqPoolInvalidator> sInvalidator;
+ return *sInvalidator;
+}
+
+C2BqPoolInvalidator::C2BqPoolInvalidator() : mDone(false) {
+ mThread = std::thread(&C2BqPoolInvalidator::run, this);
+}
+
+C2BqPoolInvalidator::~C2BqPoolInvalidator() {
+ {
+ std::unique_lock<std::mutex> l(mMutex);
+ mDone = true;
+ mCv.notify_one();
+ }
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void C2BqPoolInvalidator::queue(std::shared_ptr<C2BqPoolInvalidateItem> &item) {
+ std::unique_lock<std::mutex> l(mMutex);
+ std::pair<int64_t, std::shared_ptr<C2BqPoolInvalidateItem>> p =
+ std::make_pair(::android::elapsedRealtime() + kBqPoolInvalidateDelayMs, item);
+ mItems.push_back(p);
+ mCv.notify_one();
+}
+
+void C2BqPoolInvalidator::run() {
+ while(true) {
+ int64_t nowMs = ::android::elapsedRealtime();
+ std::unique_lock<std::mutex> l(mMutex);
+ if (mDone) {
+ break;
+ }
+ std::list<std::shared_ptr<C2BqPoolInvalidateItem>> items;
+ while (!mItems.empty()) {
+ if (mItems.front().first <= nowMs) {
+ items.push_back(mItems.front().second);
+ mItems.pop_front();
+ } else {
+ break;
+ }
+ }
+ if (items.empty()) {
+ if (mItems.empty()) {
+ mCv.wait(l);
+ } else {
+ int64_t nextMs = mItems.front().first;
+ if (nextMs > nowMs) {
+ mCv.wait_for(l, std::chrono::milliseconds(nextMs - nowMs));
+ }
+ }
+ } else {
+ l.unlock();
+ int invalidated = 0;
+ for (auto it = items.begin(); it != items.end(); ++it, ++invalidated) {
+ (*it)->invalidate();
+ }
+ ALOGD("invalidated %d bqpool items", invalidated);
+ }
+ }
+}
+
+} // android
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index ba231c1..b369a62 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -66,6 +66,7 @@
"libmedia_helper",
"libmediametrics",
"libprocessgroup",
+ "libprocessgroup_util",
"mediametricsservice-aidl-cpp",
"shared-file-region-aidl-cpp",
],
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index b1517bb..61204ae 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -158,6 +158,7 @@
"framework-permission-aidl-cpp",
"libbinder",
"libmediametrics",
+ "libmediautils",
"spatializer-aidl-cpp",
],
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index f92103b..ecf7436 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -2209,11 +2209,10 @@
{ // start of lock scope
AutoMutex lock(mLock);
- uint32_t newSequence = mSequence;
// did previous obtainBuffer() fail due to media server death or voluntary invalidation?
if (status == DEAD_OBJECT) {
// re-create track, unless someone else has already done so
- if (newSequence == oldSequence) {
+ if (mSequence == oldSequence) {
status = restoreTrack_l("obtainBuffer");
if (status != NO_ERROR) {
buffer.mFrameCount = 0;
@@ -2223,7 +2222,7 @@
}
}
}
- oldSequence = newSequence;
+ oldSequence = mSequence;
if (status == NOT_ENOUGH_DATA) {
restartIfDisabled();
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index 68dba34..29b876c 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -47,12 +47,7 @@
"name": "audioeffect_analysis"
},
{
- "name": "CtsVirtualDevicesTestCases",
- "options" : [
- {
- "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases"
}
]
}
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
index 4fc1c44..bc38251 100644
--- a/media/libaudioclient/TrackPlayerBase.cpp
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -38,12 +38,12 @@
player_type_t playerType, audio_usage_t usage,
audio_session_t sessionId) {
PlayerBase::init(playerType, usage, sessionId);
- mAudioTrack = pat;
- if (mAudioTrack != 0) {
+ mAudioTrack.store(pat);
+ if (pat != 0) {
mCallbackHandle = callback;
mSelfAudioDeviceCallback = new SelfAudioDeviceCallback(*this);
- mAudioTrack->addAudioDeviceCallback(mSelfAudioDeviceCallback);
- mAudioTrack->setPlayerIId(mPIId); // set in PlayerBase::init().
+ pat->addAudioDeviceCallback(mSelfAudioDeviceCallback);
+ pat->setPlayerIId(mPIId); // set in PlayerBase::init().
}
}
@@ -65,12 +65,15 @@
}
void TrackPlayerBase::doDestroy() {
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
- mAudioTrack->removeAudioDeviceCallback(mSelfAudioDeviceCallback);
+ sp<AudioTrack> audioTrack = getAudioTrack();
+
+ // Note that there may still be another reference in post-unlock phase of SetPlayState
+ clearAudioTrack();
+
+ if (audioTrack != 0) {
+ audioTrack->stop();
+ audioTrack->removeAudioDeviceCallback(mSelfAudioDeviceCallback);
mSelfAudioDeviceCallback.clear();
- // Note that there may still be another reference in post-unlock phase of SetPlayState
- mAudioTrack.clear();
}
}
@@ -87,16 +90,16 @@
// Implementation of IPlayer
status_t TrackPlayerBase::playerStart() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
- status = mAudioTrack->start();
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+ status = audioTrack->start();
}
return status;
}
status_t TrackPlayerBase::playerPause() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
- mAudioTrack->pause();
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+ audioTrack->pause();
status = NO_ERROR;
}
return status;
@@ -105,8 +108,8 @@
status_t TrackPlayerBase::playerStop() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+ audioTrack->stop();
status = NO_ERROR;
}
return status;
@@ -118,10 +121,10 @@
status_t TrackPlayerBase::doSetVolume() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
float tl = mPlayerVolumeL * mPanMultiplierL * mVolumeMultiplierL;
float tr = mPlayerVolumeR * mPanMultiplierR * mVolumeMultiplierR;
- mAudioTrack->setVolume(tl, tr);
+ audioTrack->setVolume(tl, tr);
status = NO_ERROR;
}
return status;
@@ -140,10 +143,9 @@
if (s != OK) {
return binderStatusFromStatusT(s);
}
-
- if (mAudioTrack != 0) {
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
- VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+ VolumeShaper::Status status = audioTrack->applyVolumeShaper(spConfiguration, spOperation);
if (status < 0) { // a non-negative value is the volume shaper id.
ALOGE("TrackPlayerBase::applyVolumeShaper() failed with status %d", status);
}
diff --git a/media/libaudioclient/aidl/fuzzer/Android.bp b/media/libaudioclient/aidl/fuzzer/Android.bp
index 61d5ccd..a215c0b 100644
--- a/media/libaudioclient/aidl/fuzzer/Android.bp
+++ b/media/libaudioclient/aidl/fuzzer/Android.bp
@@ -30,6 +30,7 @@
"libjsoncpp",
"libmediametricsservice",
"libprocessgroup",
+ "libprocessgroup_util",
"shared-file-region-aidl-cpp",
],
shared_libs: [
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index a95c700..8bca8df 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -46,6 +46,7 @@
"libmediametrics",
"libmediametricsservice",
"libprocessgroup",
+ "libprocessgroup_util",
"shared-file-region-aidl-cpp",
],
shared_libs: [
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
index fe88116..8df9ff8 100644
--- a/media/libaudioclient/include/media/TrackPlayerBase.h
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -19,6 +19,7 @@
#include <media/AudioTrack.h>
#include <media/PlayerBase.h>
+#include <mediautils/Synchronization.h>
namespace android {
@@ -37,10 +38,11 @@
const media::VolumeShaperConfiguration& configuration,
const media::VolumeShaperOperation& operation);
- //FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
- sp<AudioTrack> mAudioTrack;
+ sp<AudioTrack> getAudioTrack() { return mAudioTrack.load(); }
- void setPlayerVolume(float vl, float vr);
+ void clearAudioTrack() { mAudioTrack.store(nullptr); }
+
+ void setPlayerVolume(float vl, float vr);
protected:
@@ -68,6 +70,7 @@
float mPlayerVolumeL, mPlayerVolumeR;
sp<AudioTrack::IAudioTrackCallback> mCallbackHandle;
sp<SelfAudioDeviceCallback> mSelfAudioDeviceCallback;
+ mediautils::atomic_sp<AudioTrack> mAudioTrack;
};
} // namespace android
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 8151d39..a3ab9d2 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -86,7 +86,18 @@
}
}
-TEST(AudioTrackTest, DefaultRoutingTest) {
+class AudioTrackTest
+ : public ::testing::TestWithParam<int> {
+
+public:
+ AudioTrackTest()
+ : mSampleRate(GetParam()){};
+
+ const uint32_t mSampleRate;
+
+};
+
+TEST_P(AudioTrackTest, DefaultRoutingTest) {
audio_port_v7 port;
if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
@@ -95,7 +106,8 @@
// create record instance
sp<AudioCapture> capture = sp<AudioCapture>::make(
- AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
+ AUDIO_SOURCE_REMOTE_SUBMIX, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_IN_STEREO);
ASSERT_NE(nullptr, capture);
ASSERT_EQ(OK, capture->create()) << "record creation failed";
sp<OnAudioDeviceUpdateNotifier> cbCapture = sp<OnAudioDeviceUpdateNotifier>::make();
@@ -103,7 +115,7 @@
// create playback instance
sp<AudioPlayback> playback = sp<AudioPlayback>::make(
- 48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ mSampleRate, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
ASSERT_NE(nullptr, playback);
ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
@@ -133,6 +145,12 @@
playback->stop();
}
+INSTANTIATE_TEST_SUITE_P(
+ AudioTrackParameterizedTest,
+ AudioTrackTest,
+ ::testing::Values(44100, 48000)
+);
+
class AudioRoutingTest : public ::testing::Test {
public:
void SetUp() override {
diff --git a/media/libaudioclient/tests/trackplayerbase_tests.cpp b/media/libaudioclient/tests/trackplayerbase_tests.cpp
index 7317bf0..a4dba9b 100644
--- a/media/libaudioclient/tests/trackplayerbase_tests.cpp
+++ b/media/libaudioclient/tests/trackplayerbase_tests.cpp
@@ -54,7 +54,7 @@
mPlayer = new TrackPlayer();
mPlayer->init(track.get(), mPlayer, PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA,
AUDIO_SESSION_NONE);
- sp<AudioTrack> playerTrack = mPlayer->mAudioTrack;
+ sp<AudioTrack> playerTrack = mPlayer->getAudioTrack();
ASSERT_EQ(playerTrack->initCheck(), NO_ERROR);
mBufferSize = mFrameCount * playerTrack->frameSize();
@@ -74,7 +74,7 @@
void playBuffer() {
bool blocking = true;
- ssize_t nbytes = mPlayer->mAudioTrack->write(mBuffer.data(), mBufferSize, blocking);
+ ssize_t nbytes = mPlayer->getAudioTrack()->write(mBuffer.data(), mBufferSize, blocking);
EXPECT_EQ(nbytes, mBufferSize) << "Did not write all data in blocking mode";
}
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 3cc923d..629cd7c 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -22,6 +22,7 @@
#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <android/binder_ibinder_platform.h>
#include <error/expected_utils.h>
#include <media/AidlConversionCppNdk.h>
#include <media/AidlConversionNdk.h>
@@ -29,6 +30,8 @@
#include <media/AidlConversionUtil.h>
#include <mediautils/TimeCheck.h>
#include <system/audio.h>
+#include <system/thread_defs.h>
+
#include <Utils.h>
#include <utils/Log.h>
@@ -504,8 +507,15 @@
std::shared_ptr<OutputStreamCallbackAidl> streamCb;
if (isOffload) {
streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
+ ndk::SpAIBinder binder = streamCb->asBinder();
+ AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ AIBinder_setInheritRt(binder.get(), true);
}
auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
+ ndk::SpAIBinder binder = eventCb->asBinder();
+ AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ AIBinder_setInheritRt(binder.get(), true);
+
if (isOffload || isHwAvSync) {
args.offloadInfo = aidlConfig.offloadInfo;
}
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 0a262e4..263ef96 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -619,7 +619,14 @@
result != NO_ERROR) {
return result;
}
- return processReturn("setConnectedState", mDevice->setConnectedState(hidlAddress, connected));
+ Return<Result> ret = mDevice->setConnectedState(hidlAddress, connected);
+ if (ret.isOk() || ret == Result::NOT_SUPPORTED) {
+ // The framework is only interested in errors occurring due to connection state handling,
+ // so it can decide whether retrying is needed. If the HAL does not support this operation,
+ // it's not an error.
+ return NO_ERROR;
+ }
+ return processReturn("setConnectedState", ret);
}
error::Result<audio_hw_sync_t> DeviceHalHidl::getHwAvSync() {
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..9fdde49 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -75,7 +75,14 @@
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;
+ }()),
+ mEventFlagDataMqNotEmpty(mHalVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
+ : kEventFlagNotEmpty) {
assert(mFactory != nullptr);
assert(mEffect != nullptr);
createAidlConversion(effect, sessionId, ioId, desc);
@@ -159,6 +166,7 @@
mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
effect, sessionId, ioId, desc, mIsProxyEffect);
}
+ mEffectName = mConversion->getDescriptor().common.name;
return OK;
}
@@ -174,100 +182,153 @@
// 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;
- }
- 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 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;
}
- // for V2 audio effect HAL, expect different EventFlag to avoid bit conflict with FMQ_NOT_EMPTY
- efGroup->wake(halVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
- : kEventFlagNotEmpty);
+ 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;
+ }
+
+ efGroup->wake(mEventFlagDataMqNotEmpty);
+ 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..a775337 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -73,7 +73,12 @@
const int32_t mSessionId;
const int32_t mIoId;
const bool mIsProxyEffect;
+ const int32_t mHalVersion;
+ // Audio effect HAL v2+ changes flag to kEventFlagDataMqNotEmpty to avoid conflict from using
+ // kEventFlagNotEmpty
+ const uint32_t mEventFlagDataMqNotEmpty;
bool mIsHapticGenerator = false;
+ std::string mEffectName;
std::unique_ptr<EffectConversionHelperAidl> mConversion;
@@ -93,6 +98,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/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index f352849..0cdf0f2 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -368,16 +368,21 @@
const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
AudioSource source, const std::set<int32_t>& destinationPortIds,
AudioPortConfig* portConfig, bool* created) {
- // These flags get removed one by one in this order when retrying port finding.
- static const std::vector<AudioInputFlags> kOptionalInputFlags{
- AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
if (auto portConfigIt = findPortConfig(config, flags, ioHandle);
portConfigIt == mPortConfigs.end() && flags.has_value()) {
- auto optionalInputFlagsIt = kOptionalInputFlags.begin();
+ // These input flags get removed one by one in this order when retrying port finding.
+ std::vector<AudioInputFlags> optionalInputFlags {
+ AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
+ // For remote submix input, retry with direct input flag removed as the remote submix
+ // input is not expected to manipulate the contents of the audio stream.
+ if (mRemoteSubmixIn.has_value()) {
+ optionalInputFlags.push_back(AudioInputFlags::DIRECT);
+ }
+ auto optionalInputFlagsIt = optionalInputFlags.begin();
AudioIoFlags matchFlags = flags.value();
auto portsIt = findPort(config, matchFlags, destinationPortIds);
while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
- && optionalInputFlagsIt != kOptionalInputFlags.end()) {
+ && optionalInputFlagsIt != optionalInputFlags.end()) {
if (!isBitPositionFlagSet(
matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
++optionalInputFlagsIt;
@@ -392,6 +397,36 @@
config.toString().c_str(), flags.value().toString().c_str(),
matchFlags.toString().c_str());
}
+ // These output flags get removed one by one in this order when retrying port finding.
+ std::vector<AudioOutputFlags> optionalOutputFlags { };
+ // For remote submix output, retry with these output flags removed one by one:
+ // 1. DIRECT: remote submix outputs are expected not to manipulate the contents of the
+ // audio stream.
+ // 2. IEC958_NONAUDIO: remote submix outputs are not connected to ALSA and do not require
+ // non audio signalling.
+ if (mRemoteSubmixOut.has_value()) {
+ optionalOutputFlags.push_back(AudioOutputFlags::DIRECT);
+ optionalOutputFlags.push_back(AudioOutputFlags::IEC958_NONAUDIO);
+ }
+ auto optionalOutputFlagsIt = optionalOutputFlags.begin();
+ matchFlags = flags.value();
+ while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::output
+ && optionalOutputFlagsIt != optionalOutputFlags.end()) {
+ if (!isBitPositionFlagSet(
+ matchFlags.get<AudioIoFlags::Tag::output>(),*optionalOutputFlagsIt)) {
+ ++optionalOutputFlagsIt;
+ continue;
+ }
+ matchFlags.set<AudioIoFlags::Tag::output>(matchFlags.get<AudioIoFlags::Tag::output>() &
+ ~makeBitPositionFlagMask(*optionalOutputFlagsIt++));
+ portsIt = findPort(config, matchFlags, destinationPortIds);
+ AUGMENT_LOG(I,
+ "mix port for config %s, flags %s was not found"
+ "retried with flags %s",
+ config.toString().c_str(), flags.value().toString().c_str(),
+ matchFlags.toString().c_str());
+ }
+
if (portsIt == mPorts.end()) {
AUGMENT_LOG(E, "mix port for config %s, flags %s is not found",
config.toString().c_str(), matchFlags.toString().c_str());
@@ -792,7 +827,8 @@
status_t status = prepareToOpenStreamHelper(ioHandle, devicePortConfig.portId,
devicePortConfig.id, flags, source, initialConfig, cleanups, config,
mixPortConfig, patch);
- if (status != OK) {
+ if (status != OK && !(mRemoteSubmixOut.has_value() &&
+ initialConfig.base.format.type != AudioFormatType::PCM)) {
// If using the client-provided config did not work out for establishing a mix port config
// or patching, try with the device port config. Note that in general device port config and
// mix port config are not required to be the same, however they must match if the HAL
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 63be1bc..c4e4ae8 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -59,6 +59,16 @@
template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
return HalCommand::make<cmd>(data);
}
+
+template <typename MQTypeError>
+auto fmqErrorHandler(const char* mqName) {
+ return [m = std::string(mqName)](MQTypeError fmqError, std::string&& errorMessage) {
+ mediautils::TimeCheck::signalAudioHals();
+ LOG_ALWAYS_FATAL_IF(fmqError != MQTypeError::NONE, "%s: %s",
+ m.c_str(), errorMessage.c_str());
+ };
+}
+
} // namespace
// static
@@ -103,6 +113,17 @@
StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
}
+
+ if (mStream != nullptr) {
+ mContext.getCommandMQ()->setErrorHandler(
+ fmqErrorHandler<StreamContextAidl::CommandMQ::Error>("CommandMQ"));
+ mContext.getReplyMQ()->setErrorHandler(
+ fmqErrorHandler<StreamContextAidl::ReplyMQ::Error>("ReplyMQ"));
+ if (mContext.getDataMQ() != nullptr) {
+ mContext.getDataMQ()->setErrorHandler(
+ fmqErrorHandler<StreamContextAidl::DataMQ::Error>("DataMQ"));
+ }
+ }
}
StreamHalAidl::~StreamHalAidl() {
@@ -388,11 +409,8 @@
return INVALID_OPERATION;
}
}
- StreamContextAidl::DataMQ::Error fmqError = StreamContextAidl::DataMQ::Error::NONE;
- std::string fmqErrorMsg;
if (!mIsInput) {
- bytes = std::min(bytes,
- mContext.getDataMQ()->availableToWrite(&fmqError, &fmqErrorMsg));
+ bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
}
StreamDescriptor::Command burst =
StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
@@ -409,14 +427,12 @@
LOG_ALWAYS_FATAL_IF(*transferred > bytes,
"%s: HAL module read %zu bytes, which exceeds requested count %zu",
__func__, *transferred, bytes);
- if (auto toRead = mContext.getDataMQ()->availableToRead(&fmqError, &fmqErrorMsg);
+ if (auto toRead = mContext.getDataMQ()->availableToRead();
toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
AUGMENT_LOG(E, "failed to read %zu bytes to data MQ", toRead);
return NOT_ENOUGH_DATA;
}
}
- LOG_ALWAYS_FATAL_IF(fmqError != StreamContextAidl::DataMQ::Error::NONE,
- "%s", fmqErrorMsg.c_str());
mStreamPowerLog.log(buffer, *transferred);
return OK;
}
@@ -427,9 +443,29 @@
if (!mStream) return NO_INIT;
if (const auto state = getState(); isInPlayOrRecordState(state)) {
- return sendCommand(
- makeHalCommand<HalCommand::Tag::pause>(), reply,
+ StreamDescriptor::Reply localReply{};
+ StreamDescriptor::Reply* innerReply = reply ?: &localReply;
+ auto status = sendCommand(
+ makeHalCommand<HalCommand::Tag::pause>(), innerReply,
true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
+ if (status == STATUS_INVALID_OPERATION &&
+ !isInPlayOrRecordState(innerReply->state)) {
+ /**
+ * In case of transient states like DRAINING, the HAL may change its
+ * StreamDescriptor::State on its own and may not be in synchronization with client.
+ * Thus, client can send the unexpected command and HAL returns failure. such failure is
+ * natural. The client handles it gracefully.
+ * Example where HAL change its state,
+ * 1) DRAINING -> IDLE (on empty buffer)
+ * 2) DRAINING -> IDLE (on IStreamCallback::onDrainReady)
+ **/
+ AUGMENT_LOG(D,
+ "HAL failed to handle the 'pause' command, but stream state is in one of"
+ " the PAUSED kind of states, current state: %s",
+ toString(state).c_str());
+ return OK;
+ }
+ return status;
} else {
AUGMENT_LOG(D, "already stream in one of the PAUSED kind of states, current state: %s",
toString(state).c_str());
@@ -457,13 +493,9 @@
return INVALID_OPERATION;
}
return OK;
- } else if (state == StreamDescriptor::State::PAUSED ||
- state == StreamDescriptor::State::TRANSFER_PAUSED ||
- state == StreamDescriptor::State::DRAIN_PAUSED) {
+ } else if (isInPausedState(state)) {
return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
- } else if (state == StreamDescriptor::State::ACTIVE ||
- state == StreamDescriptor::State::TRANSFERRING ||
- state == StreamDescriptor::State::DRAINING) {
+ } else if (isInPlayOrRecordState(state)) {
AUGMENT_LOG(D, "already in stream state: %s", toString(state).c_str());
return OK;
} else {
@@ -512,7 +544,14 @@
}
void StreamHalAidl::onAsyncTransferReady() {
- if (auto state = getState(); state == StreamDescriptor::State::TRANSFERRING) {
+ StreamDescriptor::State state;
+ {
+ // Use 'mCommandReplyLock' to ensure that 'sendCommand' has finished updating the state
+ // after the reply from the 'burst' command.
+ std::lock_guard l(mCommandReplyLock);
+ state = getState();
+ }
+ if (state == StreamDescriptor::State::TRANSFERRING) {
// Retrieve the current state together with position counters unconditionally
// to ensure that the state on our side gets updated.
sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(),
@@ -523,7 +562,14 @@
}
void StreamHalAidl::onAsyncDrainReady() {
- if (auto state = getState(); state == StreamDescriptor::State::DRAINING) {
+ StreamDescriptor::State state;
+ {
+ // Use 'mCommandReplyLock' to ensure that 'sendCommand' has finished updating the state
+ // after the reply from the 'drain' command.
+ std::lock_guard l(mCommandReplyLock);
+ state = getState();
+ }
+ if (state == StreamDescriptor::State::DRAINING) {
// Retrieve the current state together with position counters unconditionally
// to ensure that the state on our side gets updated.
sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), nullptr,
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/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 116ed9a..d76ed25 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -122,6 +122,10 @@
static sp<IMediaPlayerService> sService;
Mutex mLock;
+ // Static lock was added to the client in order to consume at most
+ // one service thread from image extraction requests of the same
+ // client process(See also b/21277449).
+ static Mutex sLock;
sp<IMediaMetadataRetriever> mRetriever;
};
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 40fd022..9196f9f 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -35,6 +35,8 @@
sp<IMediaPlayerService> MediaMetadataRetriever::sService;
sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
+Mutex MediaMetadataRetriever::sLock;
+
const sp<IMediaPlayerService> MediaMetadataRetriever::getService()
{
Mutex::Autolock lock(sServiceLock);
@@ -143,6 +145,7 @@
ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d) colorFormat(%d) metaOnly(%d)",
timeUs, option, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -155,6 +158,7 @@
ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -167,6 +171,7 @@
ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
index, colorFormat, left, top, right, bottom);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -180,6 +185,7 @@
ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
index, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
diff --git a/media/libmedia/xsd/vts/Android.bp b/media/libmedia/xsd/vts/Android.bp
index 83ab977..add7b51 100644
--- a/media/libmedia/xsd/vts/Android.bp
+++ b/media/libmedia/xsd/vts/Android.bp
@@ -15,6 +15,7 @@
//
package {
+ default_team: "trendy_team_android_kernel",
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_av_media_libmedia_license"
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 718f782..a10c509 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -45,6 +45,7 @@
"android.hardware.media.omx@1.0",
"av-types-aidl-cpp",
"framework-permission-aidl-cpp",
+ "libaconfig_storage_read_api_cc",
"libaudioclient_aidl_conversion",
"libbase",
"libbinder_ndk",
@@ -76,6 +77,7 @@
"libstagefright_httplive",
"libutils",
"packagemanager_aidl-cpp",
+ "server_configurable_flags",
],
header_libs: [
@@ -86,6 +88,7 @@
],
static_libs: [
+ "com.android.media.flags.editing-aconfig-cc",
"libplayerservice_datasource",
"libstagefright_nuplayer",
"libstagefright_rtsp",
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 10a1da7..761137e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2514,6 +2514,15 @@
{
Mutex::Autolock lock(mLock);
track = mTrack;
+ }
+
+ // do not hold lock while joining.
+ if (track) {
+ track->stopAndJoinCallbacks();
+ }
+
+ {
+ Mutex::Autolock lock(mLock);
close_l(); // clears mTrack
}
// destruction of the track occurs outside of mutex.
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index dce6ba8..086baa3 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -68,6 +68,7 @@
#include <system/audio.h>
#include <media/stagefright/rtsp/ARTPWriter.h>
+#include <com_android_media_editing_flags.h>
namespace android {
@@ -2121,7 +2122,8 @@
uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
// TODO(b/341121900): Remove this once B frames are handled correctly in screen recorder
// use case in case of mic only
- if (mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
+ if (!com::android::media::editing::flags::stagefrightrecorder_enable_b_frames()
+ && mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
bLayers = 0;
}
uint32_t pLayers = tsLayers - bLayers;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index ac178aa..d084f10 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -321,6 +321,7 @@
static_libs: [
"android.media.codec-aconfig-cc",
+ "com.android.media.flags.editing-aconfig-cc",
"libstagefright_esds",
"libstagefright_color_conversion",
"libyuv",
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 76b6aa6..3aa0107 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -53,6 +53,8 @@
#include <media/esds/ESDS.h>
#include "include/HevcUtils.h"
+#include <com_android_media_editing_flags.h>
+
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif
@@ -4944,6 +4946,8 @@
// Track with start offset.
ALOGV("Tracks starting > 0");
int32_t editDurationTicks = 0;
+ int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
+ ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
// Video with no B frame or non-video track.
editDurationTicks =
@@ -4952,8 +4956,6 @@
ALOGV("editDuration:%" PRId64 "us", (trackStartOffsetUs + movieStartOffsetBFramesUs));
} else {
// Track with B frame.
- int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
- ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
editDurationTicks =
((trackStartOffsetUs + movieStartOffsetBFramesUs +
trackStartOffsetBFramesUs) * mvhdTimeScale + 5E5) / 1E6;
@@ -4967,7 +4969,15 @@
} else if (editDurationTicks < 0) {
// Only video tracks with B Frames would hit this case.
ALOGV("Edit list entry to negate start offset by B frames in other tracks");
- addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+ if (com::android::media::editing::flags::
+ stagefrightrecorder_enable_b_frames()) {
+ int32_t mediaTimeTicks =
+ ((trackStartOffsetUs + movieStartOffsetBFramesUs +
+ trackStartOffsetBFramesUs) * mTimeScale - 5E5) / 1E6;
+ addOneElstTableEntry(tkhdDurationTicks, std::abs(mediaTimeTicks), 1, 0);
+ } else {
+ addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+ }
} else {
ALOGV("No edit list entry needed for this track");
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index eea5242..7d47837 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2015,6 +2015,7 @@
int32_t flags;
CHECK(buffer->meta()->findInt32("flags", &flags));
if (flags & BUFFER_FLAG_DECODE_ONLY) {
+ ALOGV("discardDecodeOnlyOutputBuffer: mPortBuffers[out][%zu] NOT owned by client", index);
info->mOwnedByClient = false;
info->mData.clear();
mBufferChannel->discardBuffer(buffer);
@@ -4494,9 +4495,16 @@
{
/* size_t index = */updateBuffers(kPortIndexInput, msg);
- if (mState == FLUSHING
- || mState == STOPPING
- || mState == RELEASING) {
+ bool inStateToReturnBuffers =
+ mState == FLUSHING || mState == STOPPING || mState == RELEASING;
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ // Late callbacks from the codec could arrive here
+ // after the codec is already stopped or released.
+ inStateToReturnBuffers = mState == FLUSHING ||
+ mState == STOPPING || mState == INITIALIZED ||
+ mState == RELEASING || mState == UNINITIALIZED;
+ }
+ if (inStateToReturnBuffers) {
returnBuffersToCodecOnPort(kPortIndexInput);
break;
}
@@ -4575,9 +4583,16 @@
/* size_t index = */updateBuffers(kPortIndexOutput, msg);
- if (mState == FLUSHING
- || mState == STOPPING
- || mState == RELEASING) {
+ bool inStateToReturnBuffers =
+ mState == FLUSHING || mState == STOPPING || mState == RELEASING;
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ // Late callbacks from the codec could arrive here
+ // after the codec is already stopped or released.
+ inStateToReturnBuffers = mState == FLUSHING ||
+ mState == STOPPING || mState == INITIALIZED ||
+ mState == RELEASING || mState == UNINITIALIZED;
+ }
+ if (inStateToReturnBuffers) {
returnBuffersToCodecOnPort(kPortIndexOutput);
break;
}
@@ -5943,7 +5958,7 @@
}
updateHdrMetrics(false /* isConfig */);
- }
+}
void MediaCodec::extractCSD(const sp<AMessage> &format) {
mCSD.clear();
@@ -6022,7 +6037,6 @@
return -EINVAL;
}
if (codecInputData->data() == NULL) {
- ALOGV("Input buffer %zu is not properly allocated", bufferIndex);
mErrorLog.log(LOG_TAG, base::StringPrintf(
"Fatal error: input buffer %zu is not properly allocated", bufferIndex));
return -EINVAL;
@@ -6068,6 +6082,10 @@
mInputFormat.clear();
mOutputFormat.clear();
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ mCSD.clear();
+ mLeftover.clear();
+ }
mFlags &= ~kFlagOutputFormatChanged;
mFlags &= ~kFlagOutputBuffersChanged;
mFlags &= ~kFlagStickyError;
@@ -6126,6 +6144,8 @@
ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
portIndex, i);
} else {
+ ALOGV("returnBuffersToCodecOnPort: mPortBuffers[%s][%zu] NOT owned by client",
+ portIndex == kPortIndexInput ? "in" : "out", i);
info->mOwnedByClient = false;
info->mData.clear();
}
@@ -6478,6 +6498,7 @@
// synchronization boundary for getBufferAndFormat
Mutex::Autolock al(mBufferLock);
+ ALOGV("onQueueInputBuffer: mPortBuffers[in][%zu] NOT owned by client", index);
info->mOwnedByClient = false;
info->mData.clear();
@@ -6494,6 +6515,7 @@
sp<AMessage> msg = mLeftover.front();
mLeftover.pop_front();
msg->setSize("index", index);
+ ALOGV("handleLeftover(%zu)", index);
return onQueueInputBuffer(msg);
}
@@ -6562,6 +6584,7 @@
sp<MediaCodecBuffer> buffer;
{
Mutex::Autolock al(mBufferLock);
+ ALOGV("onReleaseOutputBuffer: mPortBuffers[out][%zu] NOT owned by client", index);
info->mOwnedByClient = false;
buffer = info->mData;
info->mData.clear();
@@ -6674,6 +6697,8 @@
{
Mutex::Autolock al(mBufferLock);
+ ALOGV("dequeuePortBuffer: mPortBuffers[%s][%zu] checking if not owned by client",
+ portIndex == kPortIndexInput ? "in" : "out", index);
CHECK(!info->mOwnedByClient);
info->mOwnedByClient = true;
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index b7efbce..354fab0 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -85,13 +85,37 @@
// writerTest fails about 5 out of 66
// { "name": "writerTest" },
{
- "name": "BatteryChecker_test"
+ "name": "BatteryChecker_test"
},
{
"name": "ExtractorFactoryTest"
},
{
"name": "HEVCUtilsUnitTest"
+ },
+ {
+ "name": "MctsMediaDecoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaEncoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
}
]
}
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index 58aa7cd..840c6b3c 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -24,6 +24,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_av_media_libstagefright_license"],
+ default_team: "trendy_team_android_media_solutions_editing",
}
cc_defaults {
@@ -35,14 +36,17 @@
"include",
],
static_libs: [
+ "com.android.media.flags.editing-aconfig-cc",
"liblog",
- "libstagefright_foundation",
"libstagefright",
+ "libstagefright_foundation",
],
shared_libs: [
+ "libaconfig_storage_read_api_cc",
"libbinder",
"libcutils",
"libutils",
+ "server_configurable_flags",
],
}
@@ -96,9 +100,9 @@
}
cc_fuzz {
- name : "mpeg4_writer_fuzzer",
- defaults : ["writer-fuzzer-defaults"],
- srcs : [
+ name: "mpeg4_writer_fuzzer",
+ defaults: ["writer-fuzzer-defaults"],
+ srcs: [
"mpeg4_writer_fuzzer.cpp",
],
static_libs: [
@@ -107,9 +111,9 @@
}
cc_fuzz {
- name : "ogg_writer_fuzzer",
- defaults : ["writer-fuzzer-defaults"],
- srcs : [
+ name: "ogg_writer_fuzzer",
+ defaults: ["writer-fuzzer-defaults"],
+ srcs: [
"ogg_writer_fuzzer.cpp",
],
static_libs: [
@@ -118,9 +122,9 @@
}
cc_fuzz {
- name : "webm_writer_fuzzer",
- defaults : ["writer-fuzzer-defaults"],
- srcs : [
+ name: "webm_writer_fuzzer",
+ defaults: ["writer-fuzzer-defaults"],
+ srcs: [
"webm_writer_fuzzer.cpp",
],
static_libs: [
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 8c1ef3b..bd11326 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -1069,7 +1069,7 @@
codec.rank = rank;
}
- codec.variantSet = variants;
+ codec.variantSet.insert(variants.begin(), variants.end());
// we allow sets of domains...
for (const std::string &domain : domains) {
diff --git a/media/libstagefright/xmlparser/vts/Android.bp b/media/libstagefright/xmlparser/vts/Android.bp
index 1e36c8f..527230c 100644
--- a/media/libstagefright/xmlparser/vts/Android.bp
+++ b/media/libstagefright/xmlparser/vts/Android.bp
@@ -15,6 +15,7 @@
//
package {
+ default_team: "trendy_team_android_media_codec_framework",
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_av_media_libstagefright_license"
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 6ea40e3..b5124d0 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -51,9 +51,16 @@
],
}
+vintf_fragment {
+ name: "manifest_media_c2_software.xml",
+ src: "manifest_media_c2_software.xml",
+}
+
mediaserver_cc_binary {
name: "mediaserver",
+ defaults: ["libcodec2_hal_selection"],
+
srcs: ["main_mediaserver.cpp"],
shared_libs: [
@@ -61,6 +68,7 @@
"libicu",
"libfmq",
"libbinder",
+ "libbinder_ndk",
"libhidlbase",
"liblog",
"libmediaplayerservice",
@@ -85,7 +93,7 @@
"-Wall",
],
- vintf_fragments: ["manifest_media_c2_software.xml"],
+ vintf_fragment_modules: ["manifest_media_c2_software.xml"],
soong_config_variables: {
TARGET_DYNAMIC_64_32_MEDIASERVER: {
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 026847a..8a62f30 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -17,11 +17,12 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
-
+#include <android/binder_process.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
+#include <codec2/common/HalSelection.h>
#include <utils/Log.h>
#include "RegisterExtensions.h"
@@ -30,6 +31,14 @@
using namespace android;
+namespace {
+ constexpr int kCodecThreadPoolCount = 16;
+
+ // This is the default thread count for binder thread pool
+ // if the thread count is not configured.
+ constexpr int kDefaultBinderThreadPoolCount = 15;
+}; // anonymous
+
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
@@ -40,8 +49,14 @@
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
- ::android::hardware::configureRpcThreadpool(16, false);
+
+ bool aidl = ::android::IsCodec2AidlHalSelected();
+ if (!aidl) {
+ ::android::hardware::configureRpcThreadpool(kCodecThreadPoolCount, false);
+ } else {
+ ABinderProcess_setThreadPoolMaxThreadCount(
+ kCodecThreadPoolCount + kDefaultBinderThreadPoolCount);
+ }
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
- ::android::hardware::joinRpcThreadpool();
}
diff --git a/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h b/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
index 8817621..64fdfb9 100644
--- a/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
+++ b/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
@@ -115,7 +115,6 @@
Returns:
L_sum = 32-bit sum of L_var1 and L_var2 (Word32)
*/
- __attribute__((no_sanitize("integer")))
static inline Word32 L_add(Word32 L_var1, Word32 L_var2, Flag *pOverflow)
{
Word32 L_sum;
@@ -454,7 +453,8 @@
{
Word32 result;
- result = L_var3 + L_var1 * L_var2;
+ __builtin_mul_overflow(L_var1, L_var2, &result);
+ __builtin_add_overflow(L_var3, result, &result);
return result;
}
@@ -463,7 +463,8 @@
{
Word32 result;
- result = L_var3 - L_var1 * L_var2;
+ __builtin_mul_overflow(L_var1, L_var2, &result);
+ __builtin_sub_overflow(L_var3, result, &result);
return result;
}
diff --git a/media/module/codecs/amrnb/common/src/az_lsp.cpp b/media/module/codecs/amrnb/common/src/az_lsp.cpp
index f3098f5..a19ddbf 100644
--- a/media/module/codecs/amrnb/common/src/az_lsp.cpp
+++ b/media/module/codecs/amrnb/common/src/az_lsp.cpp
@@ -237,9 +237,6 @@
------------------------------------------------------------------------------
*/
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
static Word16 Chebps(Word16 x,
Word16 f[], /* (n) */
Word16 n,
diff --git a/media/module/codecs/amrnb/common/src/l_abs.cpp b/media/module/codecs/amrnb/common/src/l_abs.cpp
index 7e0ae99..b13a40a 100644
--- a/media/module/codecs/amrnb/common/src/l_abs.cpp
+++ b/media/module/codecs/amrnb/common/src/l_abs.cpp
@@ -186,8 +186,12 @@
; Function body here
----------------------------------------------------------------------------*/
- Word32 y = L_var1 - (L_var1 < 0);
- y = y ^(y >> 31);
- return (y);
+ if (L_var1 >= 0) return L_var1;
+ if (L_var1 != 0x80000000) return -L_var1;
+ // abs(0x80000000) can not be represented in Word32.
+ // we choose to return the closest value we can -- 0x7fffffff
+ // This is acceptable because it keeps the result within the valid 32-bit signed integer range,
+ // consistent with other overflow handling in the code. such as amrnb/enc/src/l_negate.cpp.
+ return 0x7FFFFFFF;
}
diff --git a/media/module/codecs/amrnb/common/src/lsp_az.cpp b/media/module/codecs/amrnb/common/src/lsp_az.cpp
index 495359f..bb8a34d 100644
--- a/media/module/codecs/amrnb/common/src/lsp_az.cpp
+++ b/media/module/codecs/amrnb/common/src/lsp_az.cpp
@@ -281,8 +281,8 @@
t0 += ((Word32)lo * *lsp) >> 15;
*(f) += *(f - 2); /* *f += f[-2] */
- *(f--) -= t0 << 2; /* *f -= t0 */
-
+ __builtin_sub_overflow(*(f), (t0 << 2), f); /* *f -= t0 */
+ f--;
}
*f -= (Word32)(*lsp++) << 10;
diff --git a/media/module/codecs/amrnb/common/src/norm_l.cpp b/media/module/codecs/amrnb/common/src/norm_l.cpp
index d8d1259..b24ebda 100644
--- a/media/module/codecs/amrnb/common/src/norm_l.cpp
+++ b/media/module/codecs/amrnb/common/src/norm_l.cpp
@@ -211,8 +211,7 @@
if (L_var1)
{
- Word32 y = L_var1 - (L_var1 < 0);
- L_var1 = y ^(y >> 31);
+ L_var1 = L_abs(L_var1);
while (!(0x40000000L & L_var1))
diff --git a/media/module/codecs/amrnb/common/src/residu.cpp b/media/module/codecs/amrnb/common/src/residu.cpp
index 2ad132f..9b077e2 100644
--- a/media/module/codecs/amrnb/common/src/residu.cpp
+++ b/media/module/codecs/amrnb/common/src/residu.cpp
@@ -227,22 +227,35 @@
p_input3 = p_input_ptr--;
p_input4 = p_input_ptr--;
+ Word32 tmp;
for (j = M >> 1; j != 0; j--)
{
- s1 += ((Word32) * (p_coef) * *(p_input1++));
- s2 += ((Word32) * (p_coef) * *(p_input2++));
- s3 += ((Word32) * (p_coef) * *(p_input3++));
- s4 += ((Word32) * (p_coef--) * *(p_input4++));
- s1 += ((Word32) * (p_coef) * *(p_input1++));
- s2 += ((Word32) * (p_coef) * *(p_input2++));
- s3 += ((Word32) * (p_coef) * *(p_input3++));
- s4 += ((Word32) * (p_coef--) * *(p_input4++));
+ __builtin_mul_overflow(*p_coef, *(p_input1++), &tmp);
+ __builtin_add_overflow(s1, tmp, &s1);
+ __builtin_mul_overflow(*p_coef, *(p_input2++), &tmp);
+ __builtin_add_overflow(s2, tmp, &s2);
+ __builtin_mul_overflow(*p_coef, *(p_input3++), &tmp);
+ __builtin_add_overflow(s3, tmp, &s3);
+ __builtin_mul_overflow(*(p_coef--), *(p_input4++), &tmp);
+ __builtin_add_overflow(s4, tmp, &s4);
+ __builtin_mul_overflow(*p_coef, *(p_input1++), &tmp);
+ __builtin_add_overflow(s1, tmp, &s1);
+ __builtin_mul_overflow(*p_coef, *(p_input2++), &tmp);
+ __builtin_add_overflow(s2, tmp, &s2);
+ __builtin_mul_overflow(*p_coef, *(p_input3++), &tmp);
+ __builtin_add_overflow(s3, tmp, &s3);
+ __builtin_mul_overflow(*(p_coef--), *(p_input4++), &tmp);
+ __builtin_add_overflow(s4, tmp, &s4);
}
- s1 += (((Word32) * (p_coef)) * *(p_input1));
- s2 += (((Word32) * (p_coef)) * *(p_input2));
- s3 += (((Word32) * (p_coef)) * *(p_input3));
- s4 += (((Word32) * (p_coef)) * *(p_input4));
+ __builtin_mul_overflow(*p_coef, *(p_input1), &tmp);
+ __builtin_add_overflow(s1, tmp, &s1);
+ __builtin_mul_overflow(*p_coef, *(p_input2), &tmp);
+ __builtin_add_overflow(s2, tmp, &s2);
+ __builtin_mul_overflow(*p_coef, *(p_input3), &tmp);
+ __builtin_add_overflow(s3, tmp, &s3);
+ __builtin_mul_overflow(*p_coef, *(p_input4), &tmp);
+ __builtin_add_overflow(s4, tmp, &s4);
*(p_residual_ptr--) = (Word16)(s1 >> 12);
*(p_residual_ptr--) = (Word16)(s2 >> 12);
diff --git a/media/module/codecs/amrnb/common/src/sub.cpp b/media/module/codecs/amrnb/common/src/sub.cpp
index b956912..d936128 100644
--- a/media/module/codecs/amrnb/common/src/sub.cpp
+++ b/media/module/codecs/amrnb/common/src/sub.cpp
@@ -187,9 +187,6 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
Word16 sub(Word16 var1, Word16 var2, Flag *pOverflow)
{
diff --git a/media/module/codecs/amrnb/common/src/syn_filt.cpp b/media/module/codecs/amrnb/common/src/syn_filt.cpp
index 36c1d84..82770f1 100644
--- a/media/module/codecs/amrnb/common/src/syn_filt.cpp
+++ b/media/module/codecs/amrnb/common/src/syn_filt.cpp
@@ -245,9 +245,6 @@
------------------------------------------------------------------------------
*/
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
void Syn_filt(
Word16 a[], /* (i) : a[M+1] prediction coefficients (M=10) */
Word16 x[], /* (i) : input signal */
diff --git a/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp b/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
index af62074..984baf8 100644
--- a/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
+++ b/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
@@ -22,6 +22,7 @@
#include <audio_utils/sndfile.h>
#include <stdio.h>
+#include <fstream>
#include "gsmamr_dec.h"
@@ -40,7 +41,7 @@
static AmrnbDecTestEnvironment *gEnv = nullptr;
-class AmrnbDecoderTest : public ::testing::TestWithParam<string> {
+class AmrnbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
public:
AmrnbDecoderTest() : mFpInput(nullptr) {}
@@ -54,6 +55,7 @@
FILE *mFpInput;
SNDFILE *openOutputFile(SF_INFO *sfInfo);
int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX);
+ bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
};
SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
@@ -97,6 +99,42 @@
return 0;
}
+bool AmrnbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ " but output file size = %td bytes.", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) {
void *amrHandle;
int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
@@ -106,7 +144,7 @@
}
TEST_P(AmrnbDecoderTest, DecodeTest) {
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -126,10 +164,15 @@
sf_close(outFileHandle);
GSMDecodeFrameExit(&amrHandle);
ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+
+ string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
+ << " does not match the reference file " << refFilePath << ".";
}
TEST_P(AmrnbDecoderTest, ResetDecodeTest) {
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -159,8 +202,24 @@
}
INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest,
- ::testing::Values(("bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb"),
- ("sine_amrnb_1ch_12kbps_8000hz.amrnb")));
+ ::testing::Values(std::make_tuple(
+ "bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb",
+ "bbb_8000hz_1ch_8kbps_amrnb_30sec_ref.pcm"),
+ std::make_tuple(
+ "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+ "sine_amrnb_1ch_12kbps_8000hz_ref.pcm"),
+ std::make_tuple(
+ "trim_8000hz_1ch_12kpbs_amrnb_200ms.amrnb",
+ "trim_8000hz_1ch_12kpbs_amrnb_200ms_ref.pcm"),
+ std::make_tuple(
+ "bbb_8kHz_1ch_4.75kbps_amrnb_3sec.amrnb",
+ "bbb_8kHz_1ch_4.75kbps_amrnb_3sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_8kHz_1ch_10kbps_amrnb_1sec.amrnb",
+ "bbb_8kHz_1ch_10kbps_amrnb_1sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_8kHz_1ch_12.2kbps_amrnb_3sec.amrnb",
+ "bbb_8kHz_1ch_12.2kbps_amrnb_3sec_ref.pcm")));
int main(int argc, char **argv) {
gEnv = new AmrnbDecTestEnvironment();
diff --git a/media/module/codecs/amrnb/dec/test/AndroidTest.xml b/media/module/codecs/amrnb/dec/test/AndroidTest.xml
index 539fa5c..7b2ba15 100644
--- a/media/module/codecs/amrnb/dec/test/AndroidTest.xml
+++ b/media/module/codecs/amrnb/dec/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrnbDecoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrnbDecoderTest-1.0" />
+ <option name="media-folder-name" value="AmrnbDecoderTest-2.0" />
<option name="dynamic-config-module" value="AmrnbDecoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrnbDecoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrnbDecoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrnbDecoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrnb/dec/test/DynamicConfig.xml b/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
index 701a752..02b869a 100644
--- a/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
+++ b/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrnb/dec/test/README.md b/media/module/codecs/amrnb/dec/test/README.md
index 41fb80a..ea54975 100644
--- a/media/module/codecs/amrnb/dec/test/README.md
+++ b/media/module/codecs/amrnb/dec/test/README.md
@@ -22,15 +22,15 @@
adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
-adb push AmrnbDecoderTest-1.0 /data/local/tmp/
+adb push AmrnbDecoderTest-2.0 /data/local/tmp/
```
usage: AmrnbDecoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTest-1.0/
+adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecs/amrnb/enc/src/autocorr.cpp b/media/module/codecs/amrnb/enc/src/autocorr.cpp
index c71811d..a078f5a 100644
--- a/media/module/codecs/amrnb/enc/src/autocorr.cpp
+++ b/media/module/codecs/amrnb/enc/src/autocorr.cpp
@@ -312,6 +312,7 @@
Word16 y[L_WINDOW];
Word32 sum;
+ Word32 mul;
Word16 overfl_shft;
@@ -343,7 +344,8 @@
temp = (amrnb_fxp_mac_16_by_16bb((Word32) * (p_x++), (Word32) * (p_wind++), 0x04000)) >> 15;
*(p_y++) = temp;
- sum += ((Word32)temp * temp) << 1;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(sum, mul << 1, &sum);
if (sum < 0)
{
/*
@@ -395,10 +397,12 @@
{
temp = *p_y >> 2;
*(p_y++) = temp;
- sum += ((Word32)temp * temp) << 1;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(sum, mul << 1, &sum);
temp = *p_y >> 2;
*(p_y++) = temp;
- sum += ((Word32)temp * temp) << 1;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(sum, mul << 1, &sum);
}
if (sum > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/c2_9pf.cpp b/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
index b211032..56b4fb8 100644
--- a/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
@@ -610,6 +610,7 @@
Word32 alp1;
Word16 i;
Word32 L_temp;
+ Word32 mul;
Word16 *p_codvec = &codvec[0];
OSCL_UNUSED_ARG(pOverflow);
@@ -693,7 +694,8 @@
L_temp = ((Word32) alp * sq1) << 1;
/* s = L_msu(L_temp, sq, alp_16, pOverflow); */
- s = L_temp - (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(L_temp, (mul << 1), &s);
if (s > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/c3_14pf.cpp b/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
index 58ab2fa..bb4fe36 100644
--- a/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
@@ -403,6 +403,7 @@
Word16 *p_codvec = &codvec[0];
Word32 s;
+ Word32 mul;
Word32 alp0;
Word32 alp1;
@@ -487,7 +488,8 @@
s = ((Word32) alp * sq1) << 1;
/* s = L_msu(s, sq, alp_16, pOverflow); */
- s -= (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/c4_17pf.cpp b/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
index d52b43b..062ee5a 100644
--- a/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
@@ -416,6 +416,7 @@
Word16 *p_codvec = &codvec[0];
Word32 s;
+ Word32 mul;
Word32 alp0;
Word32 alp1;
@@ -497,7 +498,8 @@
s = ((Word32) alp * sq1) << 1;
/* s = L_msu(s, sq, alp_16, pOverflow); */
- s -= (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
@@ -610,7 +612,8 @@
s = ((Word32) alp * sq1) << 1;
/* s = L_msu(s, sq, alp_16, pOverflow); */
- s -= (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
@@ -630,7 +633,8 @@
s = ((Word32) alpk * sq) << 1;
/* s = L_msu(s, psk, alp, pOverflow); */
- s -= (((Word32) psk * alp) << 1);
+ __builtin_mul_overflow(psk, alp, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/cor_h_x.cpp b/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
index c25c026..398c71f 100644
--- a/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
+++ b/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
@@ -254,6 +254,7 @@
Word16 k;
Word32 s;
+ Word32 mul;
Word32 y32[L_CODE];
Word32 max;
Word32 tot;
@@ -275,15 +276,19 @@
for (j = (L_CODE - i - 1) >> 1; j != 0; j--)
{
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
}
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
if (!((L_CODE - i) & 1)) /* if even number of iterations */
{
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
}
y32[i] = s;
@@ -299,7 +304,7 @@
}
}
- tot += (max >> 1);
+ __builtin_add_overflow(tot, (max >> 1), &tot);
}
@@ -310,10 +315,13 @@
for (i = L_CODE >> 1; i != 0; i--)
{
+ Word32 result;
s = L_shl(*(p_y32++), j, pOverflow);
- *(p_ptr++) = (s + 0x00008000) >> 16;
+ __builtin_add_overflow(s, 0x00008000, &result);
+ *(p_ptr++) = result >> 16;
s = L_shl(*(p_y32++), j, pOverflow);
- *(p_ptr++) = (s + 0x00008000) >> 16;
+ __builtin_add_overflow(s, 0x00008000, &result);
+ *(p_ptr++) = result >> 16;
}
return;
diff --git a/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp b/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
index e32eb4a..80ebb73 100644
--- a/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
+++ b/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
@@ -268,7 +268,7 @@
max = s;
}
}
- tot = (tot + (max >> 1));
+ __builtin_add_overflow(tot, (max >> 1), &tot);
}
j = sub(norm_l(tot), sf, pOverflow);
diff --git a/media/module/codecs/amrnb/enc/src/dtx_enc.cpp b/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
index 2ccb777..0d56c9b 100644
--- a/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
+++ b/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
@@ -945,6 +945,7 @@
Word16 i;
Word32 L_frame_en;
+ Word32 mul;
Word32 L_temp;
Word16 log_en_e;
Word16 log_en_m;
@@ -967,7 +968,8 @@
for (i = L_FRAME; i != 0; i--)
{
- L_frame_en += (((Word32) * p_speech) * *(p_speech)) << 1;
+ __builtin_mul_overflow(*p_speech, *p_speech, &mul);
+ __builtin_add_overflow(L_frame_en, mul << 1, &L_frame_en);
p_speech++;
if (L_frame_en < 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/levinson.cpp b/media/module/codecs/amrnb/enc/src/levinson.cpp
index 29cdac6..83dd81e 100644
--- a/media/module/codecs/amrnb/enc/src/levinson.cpp
+++ b/media/module/codecs/amrnb/enc/src/levinson.cpp
@@ -731,7 +731,7 @@
t0 = t0 << 5;
t1 = ((Word32) * (Rh + i) << 16) + ((Word32)(*(Rl + i)) << 1);
- t0 += t1;
+ __builtin_add_overflow(t0, t1, &t0);
/* K = -t0 / Alpha */
diff --git a/media/module/codecs/amrnb/enc/src/pitch_fr.cpp b/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
index 584f79b..ab0a221 100644
--- a/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
+++ b/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
@@ -326,6 +326,7 @@
Word16 norm_h;
Word16 norm_l;
Word32 s;
+ Word32 mul;
Word32 s2;
Word16 excf[L_SUBFR];
Word16 scaling;
@@ -353,10 +354,12 @@
{
temp = *(p_excf++);
*(p_s_excf++) = temp >> 2;
- s += (Word32) temp * temp;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(s, mul, &s);
temp = *(p_excf++);
*(p_s_excf++) = temp >> 2;
- s += (Word32) temp * temp;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(s, mul, &s);
}
@@ -387,20 +390,24 @@
while (j--)
{
- s += (Word32) * (p_x++) * *(p_s_excf);
- s2 += ((Word32)(*(p_s_excf)) * (*(p_s_excf)));
+ __builtin_mul_overflow(*(p_x++), *p_s_excf, &mul);
+ __builtin_add_overflow(s, mul, &s);
+ __builtin_mul_overflow(*p_s_excf, *p_s_excf, &mul);
+ __builtin_add_overflow(s2, mul, &s2);
p_s_excf++;
- s += (Word32) * (p_x++) * *(p_s_excf);
- s2 += ((Word32)(*(p_s_excf)) * (*(p_s_excf)));
+ __builtin_mul_overflow(*(p_x++), *p_s_excf, &mul);
+ __builtin_add_overflow(s, mul, &s);
+ __builtin_mul_overflow(*p_s_excf, *p_s_excf, &mul);
+ __builtin_add_overflow(s2, mul, &s2);
p_s_excf++;
}
s2 = s2 << 1;
s2 = Inv_sqrt(s2, pOverflow);
norm_h = (Word16)(s2 >> 16);
- norm_l = (Word16)((s2 >> 1) - (norm_h << 15));
+ __builtin_sub_overflow((s2 >> 1), (norm_h << 15), &norm_l);
corr_h = (Word16)(s >> 15);
- corr_l = (Word16)((s) - (corr_h << 15));
+ __builtin_sub_overflow(s, (corr_h << 15), &corr_l);
/* Normalize correlation = correlation * (1/sqrt(energy)) */
diff --git a/media/module/codecs/amrnb/enc/src/pitch_ol.cpp b/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
index c039bb0..0e4b74b 100644
--- a/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
+++ b/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
@@ -959,6 +959,7 @@
Word16 p_max3;
Word16 scal_flag = 0;
Word32 t0;
+ Word32 mul;
#ifdef VAD2
Word32 r01;
@@ -1002,7 +1003,8 @@
for (i = -pit_max; i < L_frame; i++)
{
- t0 += (((Word32) * (p_signal)) * *(p_signal)) << 1;
+ __builtin_mul_overflow(*p_signal, *p_signal, &mul);
+ __builtin_add_overflow(t0, mul << 1, &t0);
p_signal++;
if (t0 < 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/pre_proc.cpp b/media/module/codecs/amrnb/enc/src/pre_proc.cpp
index 042920e..0e2be41 100644
--- a/media/module/codecs/amrnb/enc/src/pre_proc.cpp
+++ b/media/module/codecs/amrnb/enc/src/pre_proc.cpp
@@ -576,7 +576,7 @@
*(p_signal++) = (Word16)((L_tmp + 0x0000800L) >> 12);
st->y1_hi = (Word16)(L_tmp >> 12);
- st->y1_lo = (Word16)((L_tmp << 3) - ((Word32)(st->y1_hi) << 15));
+ __builtin_sub_overflow((Word16)(L_tmp << 3), (st->y1_hi) << 15, &st->y1_lo);
}
diff --git a/media/module/codecs/amrnb/enc/src/s10_8pf.cpp b/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
index 352b611..97d0318 100644
--- a/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
@@ -746,11 +746,13 @@
for (i5 = ipos[5]; i5 < L_CODE; i5 += step)
{
- ps2 = ps1 + *(p_temp1++);
+ __builtin_add_overflow(ps1, *(p_temp1++), &ps2);
- alp2 = alp1 + ((Word32) * (p_temp2 + i5) << 12);
+ __builtin_add_overflow(alp1, *(p_temp2 + i5) << 12, &alp2);
- alp_16 = (Word16)((alp2 + ((Word32) * (p_temp1++) << 14)) >> 16);
+ Word32 result;
+ __builtin_add_overflow(alp2, *(p_temp1++) << 14, &result);
+ alp_16 = (Word16)(result >> 16);
sq2 = (Word16)(((Word32) ps2 * ps2) >> 15);
if (((Word32) sq2 * alp) > ((Word32) sq * alp_16))
diff --git a/media/module/codecs/amrnb/enc/src/set_sign.cpp b/media/module/codecs/amrnb/enc/src/set_sign.cpp
index fa43f78..55658a4 100644
--- a/media/module/codecs/amrnb/enc/src/set_sign.cpp
+++ b/media/module/codecs/amrnb/enc/src/set_sign.cpp
@@ -505,6 +505,7 @@
Word16 en[L_CODE]; /* correlation vector */
Word32 s;
Word32 t;
+ Word32 mul;
Word32 L_temp;
Word16 *p_cn;
Word16 *p_dn;
@@ -525,7 +526,8 @@
val = *(p_cn++);
s = L_mac(s, val, val, pOverflow);
val = *(p_dn++);
- t += ((Word32) val * val) << 1;
+ __builtin_mul_overflow(val, val, &mul);
+ __builtin_add_overflow(t, mul << 1, &t);
}
s = Inv_sqrt(s, pOverflow);
k_cn = (Word16)((L_shl(s, 5, pOverflow)) >> 16);
diff --git a/media/module/codecs/amrnb/enc/src/spstproc.cpp b/media/module/codecs/amrnb/enc/src/spstproc.cpp
index b9574aa..5210a39 100644
--- a/media/module/codecs/amrnb/enc/src/spstproc.cpp
+++ b/media/module/codecs/amrnb/enc/src/spstproc.cpp
@@ -192,6 +192,7 @@
Word16 i;
Word16 j;
Word16 temp;
+ Word32 mul;
Word32 L_temp;
Word32 L_temp2;
Word16 tempShift;
@@ -262,8 +263,10 @@
*/
L_temp = ((Word32) * (p_exc++) * pitch_fac) << 1;
L_temp2 = ((Word32) * (p_exc--) * pitch_fac) << 1;
- L_temp += ((Word32) * (p_code++) * gain_code) << 1;
- L_temp2 += ((Word32) * (p_code++) * gain_code) << 1;
+ __builtin_mul_overflow(*(p_code++), gain_code, &mul);
+ __builtin_add_overflow(L_temp, mul << 1, &L_temp);
+ __builtin_mul_overflow(*(p_code++), gain_code, &mul);
+ __builtin_add_overflow(L_temp2, mul << 1, &L_temp2);
L_temp <<= tempShift;
L_temp2 <<= tempShift;
*(p_exc++) = (Word16)((L_temp + 0x08000L) >> 16);
diff --git a/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp b/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
index fb72998..e3bd0e0 100644
--- a/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
+++ b/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
@@ -21,6 +21,7 @@
#include <audio_utils/sndfile.h>
#include <stdio.h>
+#include <fstream>
#include "gsmamr_enc.h"
@@ -39,7 +40,7 @@
static AmrnbEncTestEnvironment *gEnv = nullptr;
-class AmrnbEncoderTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+class AmrnbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, string>> {
public:
AmrnbEncoderTest() : mAmrEncHandle(nullptr) {}
@@ -53,6 +54,7 @@
AmrNbEncState *mAmrEncHandle;
int32_t EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
int32_t frameCount = INT32_MAX);
+ bool compareBinaryFiles(const string& refFilePath, const string& outFilePath);
};
int32_t AmrnbEncoderTest::EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
@@ -87,6 +89,42 @@
return 0;
}
+bool AmrnbEncoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ " but output file size = %td bytes.", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_F(AmrnbEncoderTest, CreateAmrnbEncoderTest) {
mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
@@ -111,7 +149,7 @@
int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
- string inputFile = gEnv->getRes() + GetParam().first;
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
FILE *fpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
@@ -121,7 +159,7 @@
// Write file header.
fwrite("#!AMR\n", 1, 6, fpOutput);
- int32_t mode = GetParam().second;
+ int32_t mode = std::get<1>(GetParam());
int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput);
ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
@@ -134,6 +172,11 @@
free(mAmrEncHandle);
mAmrEncHandle = nullptr;
ALOGV("Successfully deleted encoder");
+
+ string refFilePath = gEnv->getRes() + std::get<2>(GetParam());
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
+ << " does not match the reference file " << refFilePath << ".";
}
TEST_P(AmrnbEncoderTest, ResetEncoderTest) {
@@ -142,7 +185,7 @@
int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
- string inputFile = gEnv->getRes() + GetParam().first;
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
FILE *fpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
@@ -152,7 +195,7 @@
// Write file header.
fwrite("#!AMR\n", 1, 6, fpOutput);
- int32_t mode = GetParam().second;
+ int32_t mode = std::get<1>(GetParam());
// Encode kNumFrameReset first
int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput, kNumFrameReset);
ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
@@ -177,22 +220,23 @@
// TODO: Add more test vectors
INSTANTIATE_TEST_SUITE_P(AmrnbEncoderTestAll, AmrnbEncoderTest,
- ::testing::Values(make_pair("bbb_raw_1ch_8khz_s16le.raw", MR475),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR515),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR59),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR67),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR74),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR795),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR102),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR122),
- make_pair("sinesweepraw.raw", MR475),
- make_pair("sinesweepraw.raw", MR515),
- make_pair("sinesweepraw.raw", MR59),
- make_pair("sinesweepraw.raw", MR67),
- make_pair("sinesweepraw.raw", MR74),
- make_pair("sinesweepraw.raw", MR795),
- make_pair("sinesweepraw.raw", MR102),
- make_pair("sinesweepraw.raw", MR122)));
+ ::testing::Values(
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR475, "bbb_raw_1ch_8khz_s16le_MR475_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR515, "bbb_raw_1ch_8khz_s16le_MR515_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR59, "bbb_raw_1ch_8khz_s16le_MR59_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR67, "bbb_raw_1ch_8khz_s16le_MR67_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR74, "bbb_raw_1ch_8khz_s16le_MR74_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR795, "bbb_raw_1ch_8khz_s16le_MR795_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR102, "bbb_raw_1ch_8khz_s16le_MR102_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR122, "bbb_raw_1ch_8khz_s16le_MR122_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR475, "sinesweepraw_MR475_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR515, "sinesweepraw_MR515_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR59, "sinesweepraw_MR59_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR67, "sinesweepraw_MR67_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR74, "sinesweepraw_MR74_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR795, "sinesweepraw_MR795_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR102, "sinesweepraw_MR102_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR122, "sinesweepraw_MR122_ref.amrnb")));
int main(int argc, char **argv) {
gEnv = new AmrnbEncTestEnvironment();
diff --git a/media/module/codecs/amrnb/enc/test/AndroidTest.xml b/media/module/codecs/amrnb/enc/test/AndroidTest.xml
index 1509728..a325ee8 100644
--- a/media/module/codecs/amrnb/enc/test/AndroidTest.xml
+++ b/media/module/codecs/amrnb/enc/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrnbEncoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrnbEncoderTest-1.0" />
+ <option name="media-folder-name" value="AmrnbEncoderTest-2.0" />
<option name="dynamic-config-module" value="AmrnbEncoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrnbEncoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrnbEncoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrnbEncoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrnb/enc/test/DynamicConfig.xml b/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
index 713667a..fdc0daa 100644
--- a/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
+++ b/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrnb/enc/test/README.md b/media/module/codecs/amrnb/enc/test/README.md
index f896bd1..c7b9964 100644
--- a/media/module/codecs/amrnb/enc/test/README.md
+++ b/media/module/codecs/amrnb/enc/test/README.md
@@ -22,15 +22,15 @@
adb push ${OUT}/data/nativetest/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
-adb push AmrnbEncoderTest-1.0 /data/local/tmp/
+adb push AmrnbEncoderTest-2.0 /data/local/tmp/
```
usage: AmrnbEncoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTest-1.0/
+adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp b/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
index 2cc88ce..c0e032f 100644
--- a/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
+++ b/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
@@ -23,6 +23,7 @@
#include <audio_utils/sndfile.h>
#include <memory>
#include <stdio.h>
+#include <fstream>
#include "pvamrwbdecoder.h"
#include "pvamrwbdecoder_api.h"
@@ -44,7 +45,7 @@
static AmrwbDecTestEnvironment *gEnv = nullptr;
-class AmrwbDecoderTest : public ::testing::TestWithParam<string> {
+class AmrwbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
public:
AmrwbDecoderTest() : mFpInput(nullptr) {}
@@ -59,6 +60,7 @@
int32_t DecodeFrames(int16_t *decoderCookie, void *decoderBuf, SNDFILE *outFileHandle,
int32_t frameCount = INT32_MAX);
SNDFILE *openOutputFile(SF_INFO *sfInfo);
+ bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
};
SNDFILE *AmrwbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
@@ -120,6 +122,42 @@
return 0;
}
+bool AmrwbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ "but output file size = %td bytes", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_F(AmrwbDecoderTest, MultiCreateAmrwbDecoderTest) {
uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
std::unique_ptr<char[]> decoderBuf(new char[memRequirements]);
@@ -147,7 +185,7 @@
pvDecoder_AmrWb_Init(&amrHandle, decoderBuf.get(), &decoderCookie);
ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -160,6 +198,10 @@
ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
sf_close(outFileHandle);
+ string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file "
+ << OUTPUT_FILE << " does not match the reference file " << refFilePath << ".";
}
TEST_P(AmrwbDecoderTest, ResetDecoderTest) {
@@ -173,7 +215,7 @@
pvDecoder_AmrWb_Init(&amrHandle, decoderBuf.get(), &decoderCookie);
ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -198,8 +240,21 @@
}
INSTANTIATE_TEST_SUITE_P(AmrwbDecoderTestAll, AmrwbDecoderTest,
- ::testing::Values(("bbb_amrwb_1ch_14kbps_16000hz.amrwb"),
- ("bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb")));
+ ::testing::Values(std::make_tuple(
+ "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+ "bbb_amrwb_1ch_14kbps_16000hz_ref.pcm"),
+ std::make_tuple(
+ "bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb",
+ "bbb_16000hz_1ch_9kbps_amrwb_30sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_16kHz_1ch_16bps_1sec.amrwb",
+ "bbb_16kHz_1ch_16bps_1sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_16kHz_1ch_6.6bps_3sec.amrwb",
+ "bbb_16kHz_1ch_6.6bps_3sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_16kHz_1ch_23.85bps_3sec.amrwb",
+ "bbb_16kHz_1ch_23.85bps_3sec_ref.pcm")));
int main(int argc, char **argv) {
gEnv = new AmrwbDecTestEnvironment();
diff --git a/media/module/codecs/amrwb/dec/test/AndroidTest.xml b/media/module/codecs/amrwb/dec/test/AndroidTest.xml
index 392df03..dbd1407 100644
--- a/media/module/codecs/amrwb/dec/test/AndroidTest.xml
+++ b/media/module/codecs/amrwb/dec/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrwbDecoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrwbDecoderTest-1.0" />
+ <option name="media-folder-name" value="AmrwbDecoderTest-2.0" />
<option name="dynamic-config-module" value="AmrwbDecoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrwbDecoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrwbDecoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrwbDecoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrwb/dec/test/DynamicConfig.xml b/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
index 506cc3d..52453ee 100644
--- a/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
+++ b/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrwb/dec/test/README.md b/media/module/codecs/amrwb/dec/test/README.md
index 8e77456..ed76051 100644
--- a/media/module/codecs/amrwb/dec/test/README.md
+++ b/media/module/codecs/amrwb/dec/test/README.md
@@ -22,15 +22,15 @@
adb push ${OUT}/data/nativetest/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
-adb push AmrwbDecoderTest-1.0 /data/local/tmp/
+adb push AmrwbDecoderTest-2.0 /data/local/tmp/
```
usage: AmrwbDecoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTest-1.0/
+adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecs/amrwb/enc/Android.bp b/media/module/codecs/amrwb/enc/Android.bp
index 04f36b5..6ca3b6e 100644
--- a/media/module/codecs/amrwb/enc/Android.bp
+++ b/media/module/codecs/amrwb/enc/Android.bp
@@ -96,8 +96,6 @@
"-DARM",
"-DARMV7",
"-DASM_OPT",
- // don't actually generate neon instructions, see bug 26932980
- "-mfpu=vfpv3",
],
local_include_dirs: [
"src/asm/ARMV7",
diff --git a/media/module/codecs/amrwb/enc/src/az_isp.c b/media/module/codecs/amrwb/enc/src/az_isp.c
index d7074f0..22a5c25 100644
--- a/media/module/codecs/amrwb/enc/src/az_isp.c
+++ b/media/module/codecs/amrwb/enc/src/az_isp.c
@@ -248,10 +248,10 @@
b1_h = b0_h;
}
- t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
- t0 += (b2_h * (-32768))<<1; /* t0 = x*b1 - b2 */
- t0 -= (b2_l << 1);
- t0 += (f[n] << 12); /* t0 = x*b1 - b2 + f[i]/2 */
+ __builtin_add_overflow(((b1_h * x)<<1), (((b1_l * x)>>15)<<1), &t0);
+ __builtin_add_overflow(t0, (b2_h * (-32768))<<1, &t0); /* t0 = x*b1 - b2 */
+ __builtin_sub_overflow(t0, (b2_l << 1), &t0);
+ __builtin_add_overflow(t0, (f[n] << 12), &t0); /* t0 = x*b1 - b2 + f[i]/2 */
t0 = L_shl2(t0, 6); /* Q24 to Q30 with saturation */
diff --git a/media/module/codecs/amrwb/enc/src/syn_filt.c b/media/module/codecs/amrwb/enc/src/syn_filt.c
index 7eba12f..40398f5 100644
--- a/media/module/codecs/amrwb/enc/src/syn_filt.c
+++ b/media/module/codecs/amrwb/enc/src/syn_filt.c
@@ -109,38 +109,38 @@
p2 = &sig_lo[i - 1];
p3 = &sig_hi[i - 1];
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
L_tmp = L_tmp >> 11;
L_tmp += vo_L_mult(exc[i], a0);
diff --git a/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp b/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
index 1a6ee27..dc9c1b1 100644
--- a/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
+++ b/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <stdio.h>
+#include <fstream>
#include "cmnMemory.h"
#include "voAMRWB.h"
@@ -34,13 +35,15 @@
static AmrwbEncTestEnvironment *gEnv = nullptr;
-class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, VOAMRWBFRAMETYPE>> {
+class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t,
+ VOAMRWBFRAMETYPE, string>> {
public:
AmrwbEncoderTest() : mEncoderHandle(nullptr) {
- tuple<string, int32_t, VOAMRWBFRAMETYPE> params = GetParam();
+ tuple<string, int32_t, VOAMRWBFRAMETYPE, string> params = GetParam();
mInputFile = gEnv->getRes() + get<0>(params);
mMode = get<1>(params);
mFrameType = get<2>(params);
+ refFilePath = gEnv->getRes() + get<3>(params);
mMemOperator.Alloc = cmnMemAlloc;
mMemOperator.Copy = cmnMemCopy;
mMemOperator.Free = cmnMemFree;
@@ -66,8 +69,47 @@
VO_CODEC_INIT_USERDATA mUserData;
VO_HANDLE mEncoderHandle;
int32_t mMode;
+ string refFilePath;
+
+ bool compareBinaryFiles(const string& refFilePath, const string& outFilePath);
};
+bool AmrwbEncoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ "but output file size = %td bytes", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_P(AmrwbEncoderTest, CreateAmrwbEncoderTest) {
int32_t status = voGetAMRWBEncAPI(&mApiHandle);
ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
@@ -152,38 +194,69 @@
if (fpOutput) {
fclose(fpOutput);
}
+
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file "
+ << OUTPUT_FILE << " does not match the reference file " << refFilePath << ".";
}
INSTANTIATE_TEST_SUITE_P(
- AmrwbEncoderTestAll, AmrwbEncoderTest,
- ::testing::Values(
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267)));
+ AmrwbEncoderTestAll, AmrwbEncoderTest,
+ ::testing::Values(
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_RFC3267_ref.amrwb")));
int main(int argc, char **argv) {
gEnv = new AmrwbEncTestEnvironment();
diff --git a/media/module/codecs/amrwb/enc/test/AndroidTest.xml b/media/module/codecs/amrwb/enc/test/AndroidTest.xml
index 8822cb2..1f4121f 100644
--- a/media/module/codecs/amrwb/enc/test/AndroidTest.xml
+++ b/media/module/codecs/amrwb/enc/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrwbEncoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrwbEncoderTest-1.0" />
+ <option name="media-folder-name" value="AmrwbEncoderTest-2.0" />
<option name="dynamic-config-module" value="AmrwbEncoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrwbEncoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrwbEncoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrwbEncoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrwb/enc/test/DynamicConfig.xml b/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
index a0b6218..59701ea 100644
--- a/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
+++ b/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrwb/enc/test/README.md b/media/module/codecs/amrwb/enc/test/README.md
index 3b9cc39..ea2c31e 100644
--- a/media/module/codecs/amrwb/enc/test/README.md
+++ b/media/module/codecs/amrwb/enc/test/README.md
@@ -22,7 +22,7 @@
adb push ${OUT}/data/nativetest/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
adb push AmrwbEncoderTest-1.0 /data/local/tmp/
@@ -30,7 +30,7 @@
usage: AmrwbEncoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTest-1.0/
+adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 42fd94e..433b5e9 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -790,47 +790,6 @@
}
using namespace ::android::hardware::media::c2;
-
- if (!ionPropertiesDefined()) {
- using IComponentStore =
- ::android::hardware::media::c2::V1_0::IComponentStore;
- std::string const preferredStoreName = "default";
- if (aidlSelected) {
- std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
- if (__builtin_available(android __ANDROID_API_S__, *)) {
- std::string instanceName = ::android::base::StringPrintf(
- "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
- if (AServiceManager_isDeclared(instanceName.c_str())) {
- preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
- AServiceManager_waitForService(instanceName.c_str())));
- }
- }
- if (preferredStore) {
- ::android::SetPreferredCodec2ComponentStore(
- std::make_shared<H2C2ComponentStore>(preferredStore));
- LOG(INFO) <<
- "Preferred Codec2 AIDL store is set to \"" <<
- preferredStoreName << "\".";
- } else {
- LOG(INFO) <<
- "Preferred Codec2 AIDL store is defaulted to \"software\".";
- }
- } else {
- sp<IComponentStore> preferredStore =
- IComponentStore::getService(preferredStoreName.c_str());
- if (preferredStore) {
- ::android::SetPreferredCodec2ComponentStore(
- std::make_shared<H2C2ComponentStore>(preferredStore));
- LOG(INFO) <<
- "Preferred Codec2 HIDL store is set to \"" <<
- preferredStoreName << "\".";
- } else {
- LOG(INFO) <<
- "Preferred Codec2 HIDL store is defaulted to \"software\".";
- }
- }
- }
-
bool registered = false;
const std::string aidlServiceName =
std::string(c2_aidl::IComponentStore::descriptor) + "/software";
@@ -876,6 +835,48 @@
" so it is not being registered with hwservicemanager.";
}
+ // Preferred store must be set after the store is registered to ensure that
+ // the correct preferred store is set.
+ if (!ionPropertiesDefined()) {
+ using IComponentStore =
+ ::android::hardware::media::c2::V1_0::IComponentStore;
+ std::string const preferredStoreName = "default";
+ if (aidlSelected) {
+ std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
+ if (__builtin_available(android __ANDROID_API_S__, *)) {
+ std::string instanceName = ::android::base::StringPrintf(
+ "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
+ if (AServiceManager_isDeclared(instanceName.c_str())) {
+ preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
+ AServiceManager_waitForService(instanceName.c_str())));
+ }
+ }
+ if (preferredStore) {
+ ::android::SetPreferredCodec2ComponentStore(
+ std::make_shared<H2C2ComponentStore>(preferredStore));
+ LOG(INFO) <<
+ "Preferred Codec2 AIDL store is set to \"" <<
+ preferredStoreName << "\".";
+ } else {
+ LOG(INFO) <<
+ "Preferred Codec2 AIDL store is defaulted to \"software\".";
+ }
+ } else {
+ sp<IComponentStore> preferredStore =
+ IComponentStore::getService(preferredStoreName.c_str());
+ if (preferredStore) {
+ ::android::SetPreferredCodec2ComponentStore(
+ std::make_shared<H2C2ComponentStore>(preferredStore));
+ LOG(INFO) <<
+ "Preferred Codec2 HIDL store is set to \"" <<
+ preferredStoreName << "\".";
+ } else {
+ LOG(INFO) <<
+ "Preferred Codec2 HIDL store is defaulted to \"software\".";
+ }
+ }
+ }
+
if (registered) {
LOG(INFO) << "Software Codec2 service created and registered.";
}
diff --git a/media/module/extractors/Android.bp b/media/module/extractors/Android.bp
index f654ecd..e29d3e6 100644
--- a/media/module/extractors/Android.bp
+++ b/media/module/extractors/Android.bp
@@ -28,6 +28,10 @@
"liblog",
],
+ static_libs: [
+ "libstagefright_metadatautils",
+ ],
+
// extractors are expected to run on Q(29)
min_sdk_version: "29",
apex_available: [
@@ -56,6 +60,7 @@
"libutils",
"libmediandk_format",
"libmedia_ndkformatpriv",
+ "libstagefright_metadatautils",
],
},
},
@@ -68,3 +73,21 @@
],
},
}
+
+aconfig_declarations {
+ name: "android.media.extractor.flags-aconfig",
+ package: "com.android.media.extractor.flags",
+ container: "com.android.media",
+ srcs: ["extractor.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "android.media.extractor.flags-aconfig-cc",
+ aconfig_declarations: "android.media.extractor.flags-aconfig",
+ host_supported: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+}
diff --git a/media/module/extractors/extractor.aconfig b/media/module/extractors/extractor.aconfig
new file mode 100644
index 0000000..c9bf694
--- /dev/null
+++ b/media/module/extractors/extractor.aconfig
@@ -0,0 +1,14 @@
+# Media Extractor flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+package: "com.android.media.extractor.flags"
+container: "com.android.media"
+
+flag {
+ name: "extractor_sniff_midi_optimizations"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "media_extractor"
+ description: "Enable SniffMidi optimizations."
+ bug: "359920208"
+}
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 7a49d8e..3da1589 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -24,6 +24,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_av_license"],
+ default_team: "trendy_team_android_media_solutions_playback",
}
cc_defaults {
@@ -131,6 +132,7 @@
"libstagefright_id3",
"libstagefright_esds",
"libmp4extractor",
+ "libstagefright_metadatautils",
],
dictionary: "mp4_extractor_fuzzer.dict",
@@ -301,12 +303,18 @@
],
static_libs: [
+ "android.media.extractor.flags-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libsonivox",
"libmedia_midiiowrapper",
"libmidiextractor",
"libwatchdog",
],
+ shared_libs: [
+ "server_configurable_flags",
+ ],
+
dictionary: "midi_extractor_fuzzer.dict",
host_supported: true,
diff --git a/media/module/extractors/midi/Android.bp b/media/module/extractors/midi/Android.bp
index feabf9e..0eb34fc 100644
--- a/media/module/extractors/midi/Android.bp
+++ b/media/module/extractors/midi/Android.bp
@@ -32,6 +32,8 @@
],
static_libs: [
+ "android.media.extractor.flags-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libmedia_midiiowrapper",
"libsonivoxwithoutjet",
"libstagefright_foundation",
@@ -40,6 +42,7 @@
shared_libs: [
"libbase",
+ "server_configurable_flags",
],
host_supported: true,
diff --git a/media/module/extractors/midi/MidiExtractor.cpp b/media/module/extractors/midi/MidiExtractor.cpp
index 167cc40..98d7716 100644
--- a/media/module/extractors/midi/MidiExtractor.cpp
+++ b/media/module/extractors/midi/MidiExtractor.cpp
@@ -20,6 +20,7 @@
#include "MidiExtractor.h"
+#include <com_android_media_extractor_flags.h>
#include <media/MidiIoWrapper.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
@@ -323,10 +324,97 @@
return AMediaFormat_copy(meta, mFileMetadata);
}
-// Sniffer
+static bool startsWith(const uint8_t *buf, size_t size, const char *pattern, size_t patternSize) {
+ if (size < patternSize) {
+ return false;
+ }
+ return (memcmp(buf, pattern, patternSize) == 0);
+}
-bool SniffMidi(CDataSource *source, float *confidence)
-{
+static bool isValidMThd(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "MThd", 4);
+}
+
+static bool isValidXmf(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "XMF_", 4);
+}
+
+static bool isValidImelody(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "BEGIN:IMELODY", 13);
+}
+
+static bool isValidRtttl(const uint8_t *buf, size_t size) {
+ #define RTTTL_MAX_TITLE_LEN 32
+ // rtttl starts with the following:
+ // <title>:<type>=<value>
+ //
+ // Where:
+ // - <title>: Up to 32 characters
+ // - <type>: Single character indicating:
+ // 'd' for duration
+ // 'o' for octave
+ // 'b' for beats per minute
+ // - <value>: Corresponding value for the type
+ if (size < 4) {
+ return false;
+ }
+ for (size_t i = 0; i < RTTTL_MAX_TITLE_LEN && i < size; i++) {
+ if (buf[i] == ':') {
+ if (i < (size - 3) && buf[i + 2] == '=') {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+static bool isValidOta(const uint8_t *buf, size_t size) {
+ #define OTA_RINGTONE 0x25
+ #define OTA_SOUND 0x1d
+ #define OTA_UNICODE 0x22
+
+ // ota starts with the following:
+ // <cmdLen><cmd1><cmd2>..<cmdN>
+ //
+ // Where:
+ // - <cmdLen>: Single character command length
+ // - <cmd1>: Single character (OTA_RINGTONE << 1)
+ // - <cmd2>: Single character (OTA_SOUND << 1) or (OTA_UNICODE << 1)
+ // and so on with last cmd being (0x1d << 1)
+
+ if (size < 3) {
+ return false;
+ }
+
+ uint8_t cmdLen = buf[0];
+ if (cmdLen < 2) {
+ return false;
+ }
+
+ if ((buf[1] >> 1) != OTA_RINGTONE) {
+ return false;
+ }
+ cmdLen--;
+
+ size_t i = 2;
+ while(cmdLen && i < size) {
+ switch(buf[i] >> 1) {
+ case OTA_SOUND:
+ return true;
+ case OTA_UNICODE:
+ break;
+ default:
+ return false;
+ }
+ cmdLen--;
+ i++;
+ }
+
+ return false;
+}
+
+bool SniffMidiLegacy(CDataSource *source, float *confidence) {
MidiEngine p(source, NULL, NULL);
if (p.initCheck() == OK) {
*confidence = 0.8;
@@ -335,7 +423,47 @@
}
ALOGV("SniffMidi: no");
return false;
+}
+bool SniffMidiEfficiently(CDataSource *source, float *confidence) {
+ uint8_t header[128];
+ int filled = source->readAt(source->handle, 0, header, sizeof(header));
+
+ if (isValidMThd(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, MThd");
+ return true;
+ }
+ if (isValidXmf(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, XMF_");
+ return true;
+ }
+ if (isValidImelody(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, imelody");
+ return true;
+ }
+ if (isValidRtttl(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, rtttl");
+ return true;
+ }
+ if (isValidOta(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, ota");
+ return true;
+ }
+ ALOGV("SniffMidi: no");
+ return false;
+}
+
+// Sniffer
+bool SniffMidi(CDataSource *source, float *confidence) {
+ if(com::android::media::extractor::flags::extractor_sniff_midi_optimizations()) {
+ return SniffMidiEfficiently(source, confidence);
+ }
+ return SniffMidiLegacy(source, confidence);
}
static const char *extensions[] = {
diff --git a/media/module/extractors/mkv/MatroskaExtractor.cpp b/media/module/extractors/mkv/MatroskaExtractor.cpp
index f326db1..10ae07a 100644
--- a/media/module/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/module/extractors/mkv/MatroskaExtractor.cpp
@@ -1787,7 +1787,7 @@
return ERROR_MALFORMED;
}
- if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) {
+ if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) {
return ERROR_MALFORMED;
}
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index f247f8c..12c0aaf 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -51,6 +51,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
#include <byteswap.h>
@@ -2596,8 +2597,32 @@
*offset += chunk_size;
break;
}
-
case FOURCC("vpcC"):
+ {
+ if (mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+ if (buffer.get() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) {
+ ALOGE("Failed to create VP9 CodecPrivate from vpcC.");
+ return ERROR_MALFORMED;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC("av1C"):
{
auto buffer = heapbuffer<uint8_t>(chunk_data_size);
diff --git a/media/module/metadatautils/MetaDataUtils.cpp b/media/module/metadatautils/MetaDataUtils.cpp
index 0895bb5..177438a 100644
--- a/media/module/metadatautils/MetaDataUtils.cpp
+++ b/media/module/metadatautils/MetaDataUtils.cpp
@@ -134,10 +134,54 @@
}
return true;
}
+
+/**
+ * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec.
+ * For reference:
+ * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
+ *
+ * @param meta A pointer to AMediaFormat object.
+ * @param profile The profile value of the VP9 stream.
+ * @param level The VP9 codec level. If the level is unknown, pass -1 to this parameter.
+ * @param bitDepth The bit depth of the luma and color components of the VP9 stream.
+ * @param chromaSubsampling The chroma subsampling of the VP9 stream. If chromaSubsampling is
+ * unknown, pass -1 to this parameter.
+ * @return true if CodecPrivate is set as CSD of AMediaFormat object.
+ *
+ */
+static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level,
+ int32_t bitDepth, int32_t chromaSubsampling) {
+ if (meta == nullptr) {
+ return false;
+ }
+
+ std::vector<uint8_t> codecPrivate;
+ // Construct CodecPrivate in WebM format (ID | Length | Data).
+ // Helper lambda to add a field to the codec private data
+ auto addField = [&codecPrivate](uint8_t id, uint8_t value) {
+ codecPrivate.push_back(id);
+ codecPrivate.push_back(0x01); // Length is always 1
+ codecPrivate.push_back(value);
+ };
+
+ // Add fields
+ addField(0x01, static_cast<uint8_t>(profile));
+ if (level >= 0) {
+ addField(0x02, static_cast<uint8_t>(level));
+ }
+ addField(0x03, static_cast<uint8_t>(bitDepth));
+ if (chromaSubsampling >= 0) {
+ addField(0x04, static_cast<uint8_t>(chromaSubsampling));
+ }
+ // Set CSD in the meta format
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size());
+ return true;
+}
+
// The param data contains the first frame data, starting with the uncompressed frame
// header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
// used to parse profile, bitdepth and subsampling.
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) {
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) {
if (meta == nullptr || data == nullptr || size == 0) {
return false;
}
@@ -227,29 +271,29 @@
if (chromaSubsampling != -1) {
csdSize += 3;
}
+ // As level is not present in first frame build CodecPrivate without it.
+ return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling);
+}
- // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed
- // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
- sp<ABuffer> csd = sp<ABuffer>::make(csdSize);
- uint8_t* csdData = csd->data();
-
- *csdData++ = 0x01 /* FEATURE PROFILE */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = profile;
-
- *csdData++ = 0x03 /* FEATURE BITDEPTH */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = bitDepth;
-
- // csdSize more than 6 means chroma subsampling data was found.
- if (csdSize > 6) {
- *csdData++ = 0x04 /* FEATURE SUBSAMPLING */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = chromaSubsampling;
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) {
+ if (meta == nullptr || csdData == nullptr || size < 12) {
+ return false;
}
- AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size());
- return true;
+ // Check the first 4 bytes (VersionAndFlags) if they match the required value.
+ if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) {
+ return false;
+ }
+
+ // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed.
+ // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
+ const uint8_t* vpcCData = csdData + 4; // Skip the first 4 bytes (VersionAndFlags)
+
+ int32_t profile = vpcCData[0];
+ int32_t level = vpcCData[1];
+ int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F; // Bit Depth (4 bits).
+ int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07; // Chroma Subsampling (3 bits).
+ return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling);
}
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
diff --git a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
index 69cf21a..9988544 100644
--- a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
+++ b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
@@ -38,7 +38,10 @@
void parseVorbisComment(
AMediaFormat *fileMeta, const char *comment, size_t commentLength);
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecSpecificData(AMediaFormat* meta, int32_t csdSize, int32_t profile, int32_t level,
+ int32_t bitDepth, int32_t chromaSubsampling);
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* data, size_t size);
} // namespace android
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 658191e..6a5bbbe 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -184,6 +184,22 @@
}
/* static */
+std::string TimeCheck::signalAudioHals() {
+ std::vector<pid_t> pids = getAudioHalPids();
+ std::string halPids;
+ if (pids.size() != 0) {
+ for (const auto& pid : pids) {
+ ALOGI("requesting tombstone for pid: %d", pid);
+ halPids.append(std::to_string(pid)).append(" ");
+ signalAudioHAL(pid);
+ }
+ // Allow time to complete, usually the caller is forcing restart afterwards.
+ sleep(1);
+ }
+ return halPids;
+}
+
+/* static */
TimerThread& TimeCheck::getTimeCheckThread() {
static TimerThread sTimeCheckThread{};
return sTimeCheckThread;
@@ -302,21 +318,14 @@
// HAL processes which can affect thread behavior.
const auto snapshotAnalysis = getTimeCheckThread().getSnapshotAnalysis(4 /* retiredCount */);
- // Generate audio HAL processes tombstones and allow time to complete
- // before forcing restart
- std::vector<pid_t> pids = TimeCheck::getAudioHalPids();
- std::string halPids = "HAL pids [ ";
- if (pids.size() != 0) {
- for (const auto& pid : pids) {
- ALOGI("requesting tombstone for pid: %d", pid);
- halPids.append(std::to_string(pid)).append(" ");
- signalAudioHAL(pid);
- }
- sleep(1);
+ // Generate audio HAL processes tombstones.
+ std::string halPids = signalAudioHals();
+ if (!halPids.empty()) {
+ halPids = "HAL pids [ " + halPids + "]";
} else {
- ALOGI("No HAL process pid available, skipping tombstones");
+ halPids = "No HAL process pids available";
+ ALOGI("%s", (halPids + ", skipping tombstones").c_str());
}
- halPids.append("]");
LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str());
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index 3e8d35d..c112863 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -107,6 +107,7 @@
static std::string toString();
static void setAudioHalPids(const std::vector<pid_t>& pids);
static std::vector<pid_t> getAudioHalPids();
+ static std::string signalAudioHals();
private:
// Helper class for handling events.
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2c1976b..8215247 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2923,7 +2923,7 @@
audio_config_base_t *mixerConfig,
audio_devices_t deviceType,
const String8& address,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
const audio_attributes_t attributes)
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
@@ -2958,7 +2958,7 @@
mHardwareStatus = AUDIO_HW_IDLE;
if (status == NO_ERROR) {
- if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+ if (*flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
const sp<IAfMmapPlaybackThread> thread = IAfMmapPlaybackThread::create(
this, *output, outHwDev, outputStream, mSystemReady);
mMmapThreads.add(*output, thread);
@@ -2967,22 +2967,22 @@
return thread;
} else {
sp<IAfPlaybackThread> thread;
- if (flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ if (*flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
thread = IAfPlaybackThread::createBitPerfectThread(
this, outputStream, *output, mSystemReady);
ALOGV("%s() created bit-perfect output: ID %d thread %p",
__func__, *output, thread.get());
- } else if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
+ } else if (*flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
thread = IAfPlaybackThread::createSpatializerThread(this, outputStream, *output,
mSystemReady, mixerConfig);
ALOGV("openOutput_l() created spatializer output: ID %d thread %p",
*output, thread.get());
- } else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ } else if (*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = IAfPlaybackThread::createOffloadThread(this, outputStream, *output,
mSystemReady, halConfig->offload_info);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
- } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
+ } else if ((*flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !IAfThreadBase::isValidPcmSinkFormat(halConfig->format)
|| !IAfThreadBase::isValidPcmSinkChannelMask(halConfig->channel_mask)) {
thread = IAfPlaybackThread::createDirectOutputThread(this, outputStream, *output,
@@ -3046,7 +3046,7 @@
audio_utils::lock_guard _l(mutex());
const sp<IAfThreadBase> thread = openOutput_l(module, &output, &halConfig,
- &mixerConfig, deviceType, address, flags, attributes);
+ &mixerConfig, deviceType, address, &flags, attributes);
if (thread != 0) {
uint32_t latencyMs = 0;
if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
@@ -3948,8 +3948,12 @@
// TODO: We could check compatibility of the secondaryThread with the PatchTrack
// for fast usage: thread has fast mixer, sample rate matches, etc.;
// for now, we exclude fast tracks by removing the Fast flag.
+ constexpr audio_output_flags_t kIncompatiblePatchTrackFlags =
+ static_cast<audio_output_flags_t>(AUDIO_OUTPUT_FLAG_FAST
+ | AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+
const audio_output_flags_t outputFlags =
- (audio_output_flags_t)(track->getOutputFlags() & ~AUDIO_OUTPUT_FLAG_FAST);
+ (audio_output_flags_t)(track->getOutputFlags() & ~kIncompatiblePatchTrackFlags);
sp<IAfPatchTrack> patchTrack = IAfPatchTrack::create(secondaryThread,
track->streamType(),
track->sampleRate(),
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 21c171d..6777075 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -337,7 +337,7 @@
audio_config_base_t* mixerConfig,
audio_devices_t deviceType,
const String8& address,
- audio_output_flags_t flags,
+ audio_output_flags_t* flags,
audio_attributes_t attributes) final REQUIRES(mutex());
const DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>&
getAudioHwDevs_l() const final REQUIRES(mutex(), hardwareMutex()) {
diff --git a/services/audioflinger/IAfPatchPanel.h b/services/audioflinger/IAfPatchPanel.h
index 37dce3a..15b6ddf 100644
--- a/services/audioflinger/IAfPatchPanel.h
+++ b/services/audioflinger/IAfPatchPanel.h
@@ -82,7 +82,7 @@
audio_config_base_t* mixerConfig,
audio_devices_t deviceType,
const String8& address,
- audio_output_flags_t flags,
+ audio_output_flags_t* flags,
audio_attributes_t attributes) REQUIRES(mutex()) = 0;
virtual audio_utils::mutex& mutex() const
RETURN_CAPABILITY(audio_utils::AudioFlinger_Mutex) = 0;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 35f17c1..994dd47 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -268,7 +268,7 @@
&mixerConfig,
outputDevice,
outputDeviceAddress,
- flags,
+ &flags,
attributes);
ALOGV("mAfPatchPanelCallback->openOutput_l() returned %p", thread.get());
if (thread == 0) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ecbd0ae..147a5d6 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3220,9 +3220,9 @@
// Calculate size of normal sink buffer relative to the HAL output buffer size
double multiplier = 1.0;
- // Note: mType == SPATIALIZER does not support FastMixer.
- if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
- kUseFastMixer == FastMixer_Dynamic)) {
+ // Note: mType == SPATIALIZER does not support FastMixer and DEEP is by definition not "fast"
+ if ((mType == MIXER && !(mOutput->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) &&
+ (kUseFastMixer == FastMixer_Static || kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
@@ -4017,7 +4017,13 @@
// FIXME could this be made local to while loop?
writeFrames = 0;
- cacheParameters_l();
+ {
+ audio_utils::lock_guard l(mutex());
+
+ cacheParameters_l();
+ checkSilentMode_l();
+ }
+
mSleepTimeUs = mIdleSleepTimeUs;
if (mType == MIXER || mType == SPATIALIZER) {
@@ -4042,8 +4048,6 @@
// suspended mode (for now) to help schedule the wait time until next iteration.
nsecs_t timeLoopNextNs = 0;
- checkSilentMode_l();
-
audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
sendCheckOutputStageEffectsEvent();
@@ -5135,7 +5139,16 @@
break;
case FastMixer_Static:
case FastMixer_Dynamic:
- initFastMixer = mFrameCount < mNormalFrameCount;
+ if (mType == MIXER && (output->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ /* Do not init fast mixer on deep buffer, warn if buffers are confed too small */
+ initFastMixer = false;
+ ALOGW_IF(mFrameCount * 1000 / mSampleRate < kMinNormalSinkBufferSizeMs,
+ "HAL DEEP BUFFER Buffer (%zu ms) is smaller than set minimal buffer "
+ "(%u ms), seems like a configuration error",
+ mFrameCount * 1000 / mSampleRate, kMinNormalSinkBufferSizeMs);
+ } else {
+ initFastMixer = mFrameCount < mNormalFrameCount;
+ }
break;
}
ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
diff --git a/services/audioflinger/datapath/AudioHwDevice.cpp b/services/audioflinger/datapath/AudioHwDevice.cpp
index 5314e9e..c2e538c 100644
--- a/services/audioflinger/datapath/AudioHwDevice.cpp
+++ b/services/audioflinger/datapath/AudioHwDevice.cpp
@@ -41,19 +41,20 @@
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t deviceType,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
struct audio_config *config,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
{
struct audio_config originalConfig = *config;
- auto outputStream = new AudioStreamOut(this, flags);
+ auto outputStream = new AudioStreamOut(this);
// Try to open the HAL first using the current format.
ALOGV("openOutputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
config->format, config->channel_mask);
- status_t status = outputStream->open(handle, deviceType, config, address, sourceMetadata);
+ status_t status = outputStream->open(handle, deviceType, config, flags, address,
+ sourceMetadata);
if (status != NO_ERROR) {
delete outputStream;
@@ -67,19 +68,25 @@
// If the data is encoded then try again using wrapped PCM.
const bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
- && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
- && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
+ && ((*flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
+ && ((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
if (wrapperNeeded) {
if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
- outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
- status = outputStream->open(handle, deviceType, &originalConfig, address,
+ outputStream = new SpdifStreamOut(this, originalConfig.format);
+ status = outputStream->open(handle, deviceType, &originalConfig, flags, address,
sourceMetadata);
if (status != NO_ERROR) {
ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
status);
delete outputStream;
outputStream = nullptr;
+ } else {
+ // on success, we need to assign the actual HAL stream config so that clients
+ // know and can later patch correctly.
+ config->format = originalConfig.format;
+ config->channel_mask = originalConfig.channel_mask;
+ config->sample_rate = originalConfig.sample_rate;
}
} else {
ALOGE("ERROR - openOutputStream(), SPDIFEncoder does not support format 0x%08x",
@@ -153,6 +160,12 @@
status);
delete inputStream;
inputStream = nullptr;
+ } else {
+ // on success, we need to assign the actual HAL stream config so that clients
+ // know and can later patch correctly.
+ config->format = originalConfig.format;
+ config->channel_mask = originalConfig.channel_mask;
+ config->sample_rate = originalConfig.sample_rate;
}
} else {
ALOGE("ERROR - openInputStream(), SPDIFDecoder does not support format 0x%08x",
diff --git a/services/audioflinger/datapath/AudioHwDevice.h b/services/audioflinger/datapath/AudioHwDevice.h
index e1a9018..6a35b91 100644
--- a/services/audioflinger/datapath/AudioHwDevice.h
+++ b/services/audioflinger/datapath/AudioHwDevice.h
@@ -85,7 +85,7 @@
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t deviceType,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
struct audio_config *config,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata);
diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp
index c65373e..7aadda3 100644
--- a/services/audioflinger/datapath/AudioStreamOut.cpp
+++ b/services/audioflinger/datapath/AudioStreamOut.cpp
@@ -30,9 +30,8 @@
namespace android {
// ----------------------------------------------------------------------------
-AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
+AudioStreamOut::AudioStreamOut(AudioHwDevice *dev)
: audioHwDev(dev)
- , flags(flags)
{
}
@@ -93,14 +92,16 @@
audio_io_handle_t handle,
audio_devices_t deviceType,
struct audio_config *config,
+ audio_output_flags_t *flagsPtr,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
{
sp<StreamOutHalInterface> outStream;
- const audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
- ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
- : flags;
+ audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
+ ? (audio_output_flags_t)(*flagsPtr | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+ : *flagsPtr;
+ *flagsPtr = flags = customFlags;
int status = hwDev()->openOutputStream(
handle,
diff --git a/services/audioflinger/datapath/AudioStreamOut.h b/services/audioflinger/datapath/AudioStreamOut.h
index 2bf94a1..1857099 100644
--- a/services/audioflinger/datapath/AudioStreamOut.h
+++ b/services/audioflinger/datapath/AudioStreamOut.h
@@ -37,16 +37,17 @@
public:
AudioHwDevice * const audioHwDev;
sp<StreamOutHalInterface> stream;
- const audio_output_flags_t flags;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
[[nodiscard]] sp<DeviceHalInterface> hwDev() const;
- AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags);
+ explicit AudioStreamOut(AudioHwDevice *dev);
virtual status_t open(
audio_io_handle_t handle,
audio_devices_t deviceType,
struct audio_config *config,
+ audio_output_flags_t *flagsPtr,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata);
diff --git a/services/audioflinger/datapath/SpdifStreamIn.cpp b/services/audioflinger/datapath/SpdifStreamIn.cpp
index 98ce712..0090bc5 100644
--- a/services/audioflinger/datapath/SpdifStreamIn.cpp
+++ b/services/audioflinger/datapath/SpdifStreamIn.cpp
@@ -81,6 +81,11 @@
outputDevice,
outputDeviceAddress);
+ // reset config back to whatever is returned by HAL
+ config->sample_rate = customConfig.sample_rate;
+ config->format = customConfig.format;
+ config->channel_mask = customConfig.channel_mask;
+
ALOGI("SpdifStreamIn::open() status = %d", status);
#ifdef TEE_SINK
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index d3983b0..a565955 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -33,10 +33,8 @@
* PCM then we need to wrap the data in an SPDIF wrapper.
*/
SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev,
- audio_output_flags_t flags,
audio_format_t format)
- // Tell the HAL that the data will be compressed audio wrapped in a data burst.
- : AudioStreamOut(dev, (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO))
+ : AudioStreamOut(dev)
, mSpdifEncoder(this, format)
{
}
@@ -45,6 +43,7 @@
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
+ audio_output_flags_t *flags,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
{
@@ -63,6 +62,8 @@
customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
customConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ // Tell the HAL that the data will be compressed audio wrapped in a data burst.
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
// Always print this because otherwise it could be very confusing if the
// HAL and AudioFlinger are using different formats.
@@ -76,9 +77,15 @@
handle,
devices,
&customConfig,
+ flags,
address,
sourceMetadata);
+ // reset config back to whatever is returned by HAL
+ config->sample_rate = customConfig.sample_rate;
+ config->format = customConfig.format;
+ config->channel_mask = customConfig.channel_mask;
+
ALOGI("SpdifStreamOut::open() status = %d", status);
#ifdef TEE_SINK
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index 1cd8f65..3241d6f 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -36,13 +36,13 @@
class SpdifStreamOut : public AudioStreamOut {
public:
- SpdifStreamOut(AudioHwDevice *dev, audio_output_flags_t flags,
- audio_format_t format);
+ SpdifStreamOut(AudioHwDevice *dev, audio_format_t format);
status_t open(
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
+ audio_output_flags_t *flags,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata) override;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 1bac259..35973c1 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -477,7 +477,7 @@
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 audioAttributes) = 0;
// creates a special output that is duplicated to the two outputs passed as arguments.
// The duplication is performed by a special mixer thread in the AudioFlinger.
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 3b7cae3..d499222 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -29,19 +29,21 @@
/**
* Legacy audio policy product strategies IDs. These strategies are supported by the default
* policy engine.
+ * IMPORTANT NOTE: the order of this enum is important as it determines the priority
+ * between active strategies for routing decisions: lower enum value => higher prioriy
*/
enum legacy_strategy {
STRATEGY_NONE = -1,
- STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
- STRATEGY_SONIFICATION_RESPECTFUL,
- STRATEGY_DTMF,
STRATEGY_ENFORCED_AUDIBLE,
- STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
- STRATEGY_REROUTING,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_MEDIA,
+ STRATEGY_DTMF,
STRATEGY_CALL_ASSISTANT,
+ STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
+ STRATEGY_REROUTING,
STRATEGY_PATCH,
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index bfb28a5..a18cf1f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -412,7 +412,7 @@
const audio_config_base_t *mixerConfig,
const DeviceVector &devices,
audio_stream_type_t stream,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_io_handle_t *output,
audio_attributes_t attributes);
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/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index d206637..26bb94f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -137,6 +137,7 @@
class HwModuleCollection : public Vector<sp<HwModule> >
{
public:
+ sp<HwModule> getModuleFromHandle(audio_module_handle_t handle) const;
sp<HwModule> getModuleFromName(const char *name) const;
/**
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a8663fa..3c2f46a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -587,7 +587,7 @@
const audio_config_base_t *mixerConfig,
const DeviceVector &devices,
audio_stream_type_t stream,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_io_handle_t *output,
audio_attributes_t attributes)
{
@@ -617,7 +617,7 @@
// create a default one
if ((mProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
lHalConfig.offload_info.format == AUDIO_FORMAT_DEFAULT) {
- flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
lHalConfig.offload_info = AUDIO_INFO_INITIALIZER;
lHalConfig.offload_info.sample_rate = lHalConfig.sample_rate;
lHalConfig.offload_info.channel_mask = lHalConfig.channel_mask;
@@ -635,7 +635,7 @@
lMixerConfig = *mixerConfig;
}
- mFlags = (audio_output_flags_t)(mFlags | flags);
+ mFlags = (audio_output_flags_t)(mFlags | *flags);
// If no mixer config is specified for a spatializer output, default to 5.1 for proper
// configuration of the final downmixer or spatializer
@@ -653,8 +653,9 @@
&lMixerConfig,
device,
&mLatency,
- mFlags,
+ &mFlags,
attributes);
+ *flags = mFlags;
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index abeaaf8..723887d 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>
@@ -341,7 +342,13 @@
AUDIO_FORMAT_AAC_XHE}},
{AUDIO_FORMAT_DOLBY_TRUEHD, {}},
{AUDIO_FORMAT_E_AC3_JOC, {}},
- {AUDIO_FORMAT_AC4, {}}};
+ {AUDIO_FORMAT_AC4, {}}, // L0-3
+ {AUDIO_FORMAT_AC4_L4, {}}};
+}
+
+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/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 6696b45..2d8231a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -283,6 +283,16 @@
dumpAudioRouteVector(mRoutes, dst, spaces);
}
+sp<HwModule> HwModuleCollection::getModuleFromHandle(audio_module_handle_t handle) const
+{
+ for (const auto& module : *this) {
+ if (module->getHandle() == handle) {
+ return module;
+ }
+ }
+ return nullptr;
+}
+
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
{
for (const auto& module : *this) {
diff --git a/services/audiopolicy/config/surround_sound_configuration_5_0.xml b/services/audiopolicy/config/surround_sound_configuration_5_0.xml
index 590a181..6a268d8 100644
--- a/services/audiopolicy/config/surround_sound_configuration_5_0.xml
+++ b/services/audiopolicy/config/surround_sound_configuration_5_0.xml
@@ -27,5 +27,6 @@
<format name="AUDIO_FORMAT_DTS_HD" />
<format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
<format name="AUDIO_FORMAT_AC4" />
+ <format name="AUDIO_FORMAT_AC4_L4" />
</formats>
</surroundSound>
diff --git a/services/audiopolicy/config/surround_sound_configuration_aidl.xml b/services/audiopolicy/config/surround_sound_configuration_aidl.xml
index cf15711..51ccaa9 100644
--- a/services/audiopolicy/config/surround_sound_configuration_aidl.xml
+++ b/services/audiopolicy/config/surround_sound_configuration_aidl.xml
@@ -30,5 +30,6 @@
<format name="AUDIO_FORMAT_DTS_UHD_P2" />
<format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
<format name="AUDIO_FORMAT_AC4" />
+ <format name="AUDIO_FORMAT_AC4_L4" />
</formats>
</surroundSound>
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 8162720..9b1125d 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -92,6 +92,10 @@
bool isDefault() const;
+ bool isPatchStrategy() const {
+ return getVolumeGroupForStreamType(AUDIO_STREAM_PATCH) != VOLUME_GROUP_NONE;
+ }
+
void dump(String8 *dst, int spaces = 0) const;
private:
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 976791f..fb8379e 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -311,6 +311,9 @@
}
StrategyVector orderedStrategies;
for (const auto &iter : strategies) {
+ if (iter.second->isPatchStrategy()) {
+ continue;
+ }
orderedStrategies.push_back(iter.second->getId());
}
return orderedStrategies;
@@ -742,6 +745,9 @@
auto defaultDevices = DeviceVector(getApmObserver()->getDefaultOutputDevice());
for (const auto &iter : getProductStrategies()) {
const auto &strategy = iter.second;
+ if (strategy->isPatchStrategy()) {
+ continue;
+ }
mDevicesForStrategies[strategy->getId()] = defaultDevices;
setStrategyDevices(strategy, defaultDevices);
}
@@ -750,6 +756,9 @@
void EngineBase::updateDeviceSelectionCache() {
for (const auto &iter : getProductStrategies()) {
const auto& strategy = iter.second;
+ if (strategy->isPatchStrategy()) {
+ continue;
+ }
auto devices = getDevicesForProductStrategy(strategy->getId());
mDevicesForStrategies[strategy->getId()] = devices;
setStrategyDevices(strategy, devices);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f36d8d5..354c59c 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -122,17 +122,16 @@
}
}
-void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+status_t AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
media::DeviceConnectedState state)
{
audio_port_v7 devicePort;
device->toAudioPort(&devicePort);
- if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
- status != OK) {
- ALOGE("Error %d while setting connected state %d for device %s",
- status, static_cast<int>(state),
- device->getDeviceTypeAddr().toString(false).c_str());
- }
+ status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
+ ALOGE_IF(status != OK, "Error %d while setting connected state %d for device %s", status,
+ static_cast<int>(state), device->getDeviceTypeAddr().toString(false).c_str());
+
+ return status;
}
status_t AudioPolicyManager::setDeviceConnectionStateInt(
@@ -213,7 +212,14 @@
// Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the outputs...)
- broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+ if (broadcastDeviceConnectionState(
+ device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
+ mAvailableOutputDevices.remove(device);
+ mHwModules.cleanUpForDevice(device);
+ ALOGE("%s() device %s format %x connection failed", __func__,
+ device->toString().c_str(), device->getEncodedFormat());
+ return INVALID_OPERATION;
+ }
if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
mAvailableOutputDevices.remove(device);
@@ -398,7 +404,14 @@
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
- broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+ if (broadcastDeviceConnectionState(
+ device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
+ mAvailableInputDevices.remove(device);
+ mHwModules.cleanUpForDevice(device);
+ ALOGE("%s() device %s format %x connection failed", __func__,
+ device->toString().c_str(), device->getEncodedFormat());
+ return INVALID_OPERATION;
+ }
// Propagate device availability to Engine
setEngineDeviceConnectionState(device, state);
@@ -1153,8 +1166,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);
@@ -1251,7 +1263,8 @@
// FIXME: in case of RENDER policy, the output capabilities should be checked
if ((secondaryMixes != nullptr && !secondaryMixes->empty())
- && !audio_is_linear_pcm(config->format)) {
+ && (!audio_is_linear_pcm(config->format) ||
+ *flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
ALOGD("%s: rejecting request as secondary mixes only support pcm", __func__);
return BAD_VALUE;
}
@@ -1527,6 +1540,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.
@@ -1603,14 +1623,19 @@
releaseMsdOutputPatches(devices);
status_t status =
- outputDesc->open(config, nullptr /* mixerConfig */, devices, stream, flags, output,
+ outputDesc->open(config, nullptr /* mixerConfig */, devices, stream, &flags, output,
attributes);
- // only accept an output with the requested parameters
+ // only accept an output with the requested parameters, unless the format can be IEC61937
+ // encapsulated and opened by AudioFlinger as wrapped IEC61937.
+ const bool ignoreRequestedParametersCheck = audio_is_iec61937_compatible(config->format)
+ && (flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+ && audio_has_proportional_frames(outputDesc->getFormat());
if (status != NO_ERROR ||
- (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
- (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
- (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())) {
+ (!ignoreRequestedParametersCheck &&
+ ((config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+ (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+ (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())))) {
ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
"format %d %d, channel mask %04x %04x", __func__, *output, config->sample_rate,
outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
@@ -1630,11 +1655,11 @@
outputDesc->mDirectClientSession = session;
addOutput(*output, outputDesc);
- setOutputDevices(__func__, outputDesc,
- devices,
- true,
- 0,
- NULL);
+ // The version check is essentially to avoid making this call in the case of the HIDL HAL.
+ if (auto hwModule = mHwModules.getModuleFromHandle(mPrimaryModuleHandle); hwModule &&
+ hwModule->getHalVersionMajor() >= 3) {
+ setOutputDevices(__func__, outputDesc, devices, true, 0, NULL);
+ }
mPreviousOutputs = mOutputs;
ALOGV("%s returns new direct output %d", __func__, *output);
mpClientInterface->onAudioPortListUpdate();
@@ -1675,8 +1700,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;
}
@@ -3472,6 +3496,11 @@
}
ALOGV("%s: group %d matching with %s index %d",
__FUNCTION__, group, toString(attributes).c_str(), index);
+ if (mEngine->getStreamTypeForAttributes(attributes) == AUDIO_STREAM_PATCH) {
+ ALOGV("%s: cannot change volume for PATCH stream, attrs: %s",
+ __FUNCTION__, toString(attributes).c_str());
+ return NO_ERROR;
+ }
status_t status = NO_ERROR;
IVolumeCurves &curves = getVolumeCurves(attributes);
VolumeSource vs = toVolumeSource(group);
@@ -5979,7 +6008,8 @@
audio_devices_t deviceType = device->type();
// Enabling/disabling formats are applied to only HDMI devices. So, this function
// returns formats reported by HDMI devices.
- if (deviceType != AUDIO_DEVICE_OUT_HDMI) {
+ if (deviceType != AUDIO_DEVICE_OUT_HDMI &&
+ deviceType != AUDIO_DEVICE_OUT_HDMI_ARC && deviceType != AUDIO_DEVICE_OUT_HDMI_EARC) {
continue;
}
// Formats reported by sink devices
@@ -6048,13 +6078,13 @@
sp<SwAudioOutputDescriptor> outputDesc;
bool profileUpdated = false;
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_HDMI);
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypes(
+ {AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_HDMI_EARC});
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
String8 address = String8(hdmiOutputDevices[i]->address().c_str());
std::string name = hdmiOutputDevices[i]->getName();
- status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ status_t status = setDeviceConnectionStateInt(hdmiOutputDevices[i]->type(),
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
address.c_str(),
name.c_str(),
@@ -6062,7 +6092,7 @@
if (status != NO_ERROR) {
continue;
}
- status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ status = setDeviceConnectionStateInt(hdmiOutputDevices[i]->type(),
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
address.c_str(),
name.c_str(),
@@ -6602,11 +6632,12 @@
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
status_t status = outputDesc->open(nullptr /* halConfig */, nullptr /* mixerConfig */,
DeviceVector(supportedDevice),
AUDIO_STREAM_DEFAULT,
- AUDIO_OUTPUT_FLAG_NONE, &output, attributes);
+ &flags, &output, attributes);
if (status != NO_ERROR) {
ALOGW("Cannot open output stream for devices %s on hw module %s",
supportedDevice->toString().c_str(), hwModule->getName());
@@ -7415,7 +7446,8 @@
client->getSecondaryOutputs().begin(),
client->getSecondaryOutputs().end(),
secondaryDescs.begin(), secondaryDescs.end())) {
- if (!audio_is_linear_pcm(client->config().format)) {
+ if (client->flags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
+ || !audio_is_linear_pcm(client->config().format)) {
// If the format is not PCM, the tracks should be invalidated to get correct
// behavior when the secondary output is changed.
clientsToInvalidate.push_back(client->portId());
@@ -7975,9 +8007,21 @@
if (result.source == AUDIO_SOURCE_HOTWORD && !inputDesc->isSoundTrigger()) {
result.source = AUDIO_SOURCE_VOICE_RECOGNITION;
}
- return result; }).
+ return result; });
//only one input device for now
- addSource(device);
+ if (audio_is_remote_submix_device(device->type())) {
+ // remote submix HAL does not support audio conversion, need source device
+ // audio config to match the sink input descriptor audio config, otherwise AIDL
+ // HAL patching will fail
+ audio_port_config srcDevicePortConfig = {};
+ device->toAudioPortConfig(&srcDevicePortConfig, nullptr);
+ srcDevicePortConfig.sample_rate = inputDesc->getSamplingRate();
+ srcDevicePortConfig.channel_mask = inputDesc->getChannelMask();
+ srcDevicePortConfig.format = inputDesc->getFormat();
+ patchBuilder.addSource(srcDevicePortConfig);
+ } else {
+ patchBuilder.addSource(device);
+ }
status = installPatch(__func__, patchHandle, inputDesc.get(), patchBuilder.patch(), 0);
}
}
@@ -8686,6 +8730,8 @@
mReportedFormatsMap[devDesc] = formats;
if (devDesc->type() == AUDIO_DEVICE_OUT_HDMI ||
+ devDesc->type() == AUDIO_DEVICE_OUT_HDMI_ARC ||
+ devDesc->type() == AUDIO_DEVICE_OUT_HDMI_EARC ||
isDeviceOfModule(devDesc,AUDIO_HARDWARE_MODULE_ID_MSD)) {
modifySurroundFormats(devDesc, &formats);
size_t modifiedNumProfiles = 0;
@@ -8820,7 +8866,7 @@
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
status_t status = desc->open(halConfig, mixerConfig, devices,
- AUDIO_STREAM_DEFAULT, flags, &output, attributes);
+ AUDIO_STREAM_DEFAULT, &flags, &output, attributes);
if (status != NO_ERROR) {
ALOGE("%s failed to open output %d", __func__, status);
return nullptr;
@@ -8858,7 +8904,7 @@
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
- status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, flags, &output,
+ status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, &flags, &output,
attributes);
if (status != NO_ERROR) {
return nullptr;
@@ -8866,11 +8912,11 @@
}
addOutput(output, desc);
- setOutputDevices(__func__, desc,
- devices,
- true,
- 0,
- NULL);
+ // The version check is essentially to avoid making this call in the case of the HIDL HAL.
+ if (auto hwModule = mHwModules.getModuleFromHandle(mPrimaryModuleHandle); hwModule &&
+ hwModule->getHalVersionMajor() >= 3) {
+ setOutputDevices(__func__, desc, devices, true, 0, NULL);
+ }
sp<DeviceDescriptor> speaker = mAvailableOutputDevices.getDevice(
AUDIO_DEVICE_OUT_SPEAKER, String8(""), AUDIO_FORMAT_DEFAULT);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 953fd2a..9d2166a 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -1105,8 +1105,8 @@
// It can give a chance to HAL implementer to retrieve dynamic capabilities associated
// to this device for example.
// TODO avoid opening stream to retrieve capabilities of a profile.
- void broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
- media::DeviceConnectedState state);
+ status_t broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+ media::DeviceConnectedState state);
// updates device caching and output for streams that can influence the
// routing of notifications
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 22fc151..6d2c772 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -56,7 +56,7 @@
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)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
@@ -74,7 +74,7 @@
request.mixerConfig = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_config_base_t_AudioConfigBase(*mixerConfig, false /*isInput*/));
request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_DeviceDescriptorBase(device));
- request.flags = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
+ request.flags = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_output_flags_t_int32_t_mask(*flags));
request.attributes = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attributes));
@@ -89,7 +89,9 @@
.channel_mask = halConfig->channel_mask,
.format = halConfig->format,
};
- mAudioPolicyService->registerOutput(*output, config, flags);
+ *flags = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_int32_t_audio_output_flags_t_mask(response.flags));
+ mAudioPolicyService->registerOutput(*output, config, *flags);
}
return status;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 8d53bd5..d529130 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -1801,6 +1801,7 @@
++numTimesBecameEmpty;
}
mLastCommand = command;
+ status_t createAudioPatchStatus;
switch (command->mCommand) {
case SET_VOLUME: {
@@ -1858,10 +1859,11 @@
ALOGV("AudioCommandThread() processing create audio patch");
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
- command->mStatus = PERMISSION_DENIED;
+ createAudioPatchStatus = PERMISSION_DENIED;
} else {
ul.unlock();
- command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+ createAudioPatchStatus = af->createAudioPatch(&data->mPatch,
+ &data->mHandle);
ul.lock();
}
} break;
@@ -2030,8 +2032,28 @@
{
audio_utils::lock_guard _l(command->mMutex);
if (command->mWaitStatus) {
+ if (command->mCommand == CREATE_AUDIO_PATCH) {
+ command->mStatus = createAudioPatchStatus;
+ }
command->mWaitStatus = false;
command->mCond.notify_one();
+ } else if (command->mCommand == CREATE_AUDIO_PATCH &&
+ command->mStatus == TIMED_OUT &&
+ createAudioPatchStatus == NO_ERROR) {
+ // Because of special handling in insertCommand_l() the CREATE_AUDIO_PATCH
+ // command wait status can be only false in case timeout (see TIMED_OUT)
+ // happened.
+ CreateAudioPatchData *createData =
+ (CreateAudioPatchData *)command->mParam.get();
+ ALOGW("AudioCommandThread() no caller awaiting for handle(%d) after \
+ processing create audio patch, going to release it",
+ createData->mHandle);
+ sp<AudioCommand> releaseCommand = new AudioCommand();
+ releaseCommand->mCommand = RELEASE_AUDIO_PATCH;
+ ReleaseAudioPatchData *releaseData = new ReleaseAudioPatchData();
+ releaseData->mHandle = createData->mHandle;
+ releaseCommand->mParam = releaseData;
+ insertCommand_l(releaseCommand, 0);
}
}
waitTime = -1;
@@ -2549,7 +2571,8 @@
// Disable wait for status if delay is not 0.
// Except for create audio patch command because the returned patch handle
- // is needed by audio policy manager
+ // is needed by audio policy manager. Audio patch created after timeout
+ // (see TIMED_OUT) will be released from threadLoop().
if (delayMs != 0 && command->mCommand != CREATE_AUDIO_PATCH) {
command->mWaitStatus = false;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 5d9813f..eccefa7 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -790,7 +790,7 @@
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);
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
// a special mixer thread in the AudioFlinger.
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 5a25a77..483f827 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*/,
@@ -262,6 +280,13 @@
return it == mTracksInternalMute.end() ? false : it->second;
}
+ 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;
@@ -276,6 +301,7 @@
std::set<audio_channel_mask_t> mSupportedChannelMasks;
std::map<audio_port_handle_t, bool> mTracksInternalMute;
std::set<audio_io_handle_t> mOpenedInputs;
+ std::map<audio_io_handle_t, audio_output_flags_t> mOpenedOutputs;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 0299160..6116eab 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -37,7 +37,7 @@
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 { return NO_INIT; }
audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
audio_io_handle_t /*output2*/) override {
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 9445af1..5278b73 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>
@@ -175,6 +176,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;
@@ -191,7 +197,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);
@@ -222,8 +228,6 @@
std::unique_ptr<AudioPolicyManagerTestClient> mClient;
std::unique_ptr<AudioPolicyTestManager> mManager;
- constexpr static const uint32_t k48000SamplingRate = 48000;
-
static const std::string sTestEngineConfig;
};
@@ -494,6 +498,9 @@
void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
// TODO: Consider using Serializer to load part of the config from a string.
ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTest::SetUpManagerConfig());
+ mConfig->getHwModules().getModuleFromName(
+ AUDIO_HARDWARE_MODULE_ID_PRIMARY)->setHalVersion(3, 0);
+
mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
sp<AudioProfile> pcmOutputProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, k48000SamplingRate);
@@ -525,7 +532,7 @@
addOutputProfile(spdifOutputProfile);
}
- sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
+ sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 3 /*halVersionMajor*/);
HwModuleCollection modules = mConfig->getHwModules();
modules.add(msdModule);
mConfig->setHwModules(modules);
@@ -787,27 +794,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;
@@ -854,27 +861,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;
@@ -1130,12 +1137,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);
}
@@ -1176,9 +1183,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;
@@ -2513,7 +2520,7 @@
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 {
return mSimulateFailure ? BAD_VALUE :
AudioPolicyManagerTestClient::openOutput(
@@ -2535,8 +2542,29 @@
void setSimulateFailure(bool simulateFailure) { mSimulateFailure = simulateFailure; }
+ void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
+ if (status != NO_ERROR) {
+ // simulate device connect status
+ mSimulateBroadcastDeviceStatus[device] = status;
+ } else {
+ // remove device connection fixed status
+ mSimulateBroadcastDeviceStatus.erase(device);
+ }
+ }
+
+ status_t setDeviceConnectedState(const struct audio_port_v7* port,
+ media::DeviceConnectedState state) override {
+ if (mSimulateBroadcastDeviceStatus.find(port->ext.device.type) !=
+ mSimulateBroadcastDeviceStatus.end()) {
+ // If a simulated status exists, return a status value
+ return mSimulateBroadcastDeviceStatus[port->ext.device.type];
+ }
+ return AudioPolicyManagerTestClient::setDeviceConnectedState(port, state);
+ }
+
private:
bool mSimulateFailure = false;
+ std::map<audio_devices_t, status_t> mSimulateBroadcastDeviceStatus;
};
} // namespace
@@ -2557,6 +2585,9 @@
void setSimulateOpenFailure(bool simulateFailure) {
mFullClient->setSimulateFailure(simulateFailure); }
+ void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
+ mFullClient->setSimulateBroadcastDeviceStatus(device, status); }
+
static const std::string sBluetoothConfig;
private:
@@ -2600,6 +2631,30 @@
}
}
+TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, BroadcastDeviceFailure) {
+ const audio_devices_t type = std::get<0>(GetParam());
+ const std::string name = std::get<1>(GetParam());
+ const std::string address = std::get<2>(GetParam());
+ const audio_format_t format = std::get<3>(GetParam());
+
+ // simulate broadcastDeviceConnectionState return failure
+ setSimulateBroadcastDeviceStatus(type, INVALID_OPERATION);
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), format));
+
+ // if broadcast is fail, device should not be added to available devices list
+ if (audio_is_output_device(type)) {
+ auto availableDevices = mManager->getAvailableOutputDevices();
+ EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
+ } else if (audio_is_input_device(type)) {
+ auto availableDevices = mManager->getAvailableInputDevices();
+ EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
+ }
+
+ setSimulateBroadcastDeviceStatus(type, NO_ERROR);
+}
+
INSTANTIATE_TEST_CASE_P(
DeviceConnectionFailure,
AudioPolicyManagerTestDeviceConnectionFailed,
@@ -3184,6 +3239,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;
@@ -3336,7 +3644,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);
@@ -3357,7 +3665,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
@@ -3368,7 +3676,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(
@@ -3394,7 +3702,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);
@@ -3407,7 +3715,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
@@ -3418,7 +3726,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(
@@ -3492,7 +3800,7 @@
audio_port_handle_t routedPortId = devicePort.id;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &inputClientHandle, session, 1, &routedPortId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000, AUDIO_INPUT_FLAG_NONE, &portId));
+ k48000SamplingRate, AUDIO_INPUT_FLAG_NONE, &portId));
ASSERT_EQ(devicePort.id, routedPortId);
auto selectedDevice = availableDevices.getDeviceFromId(routedPortId);
ASSERT_NE(nullptr, selectedDevice);
@@ -3521,7 +3829,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));
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 15e51b0..8e7a697 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -20,6 +20,7 @@
"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/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/Android.bp b/services/camera/libcameraservice/Android.bp
index 38476a4..0c4bfcb 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -265,9 +265,21 @@
"liblog",
"libutils",
"libxml2",
- "camera_platform_flags_c_lib",
],
+ target: {
+ android: {
+ shared_libs: [
+ "camera_platform_flags_c_lib",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "camera_platform_flags_c_lib_for_test",
+ ],
+ },
+ },
+
include_dirs: [
"frameworks/av/camera/include",
"frameworks/av/camera/include/camera",
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index 55e2c9d..d49aad6 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -44,13 +44,25 @@
"libjpeg",
"liblog",
"libutils",
- "camera_platform_flags_c_lib",
],
static_libs: [
"libgmock",
],
+ target: {
+ android: {
+ shared_libs: [
+ "camera_platform_flags_c_lib",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "camera_platform_flags_c_lib_for_test",
+ ],
+ },
+ },
+
cflags: [
"-Wall",
"-Wextra",
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index 5a5966b..c6b58fb 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -216,8 +216,8 @@
std::mutex mLock;
std::deque<std::unique_ptr<ProcessCaptureRequestTask>> mQueue GUARDED_BY(mLock);
std::condition_variable mCondVar;
- volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
- volatile bool mPendingExit GUARDED_BY(mLock);
+ volatile bool GUARDED_BY(mLock) mTextureUpdateRequested = false;
+ volatile bool GUARDED_BY(mLock) mPendingExit = false;
// Acquisition timestamp of last frame.
std::atomic<uint64_t> mLastAcquisitionTimestampNanoseconds;
diff --git a/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
index c7468c7..572e969 100644
--- a/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
@@ -22,6 +22,7 @@
using ::android::MediaMetricsService;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ signal(SIGPIPE, SIG_IGN);
auto service = sp<MediaMetricsService>::make();
fuzzService(service, FuzzedDataProvider(data, size));
return 0;
diff --git a/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
index 6253df7..1cad482 100644
--- a/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
@@ -26,6 +26,7 @@
using ndk::SharedRefBase;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ signal(SIGPIPE, SIG_IGN);
std::shared_ptr<ResourceManagerService> service = ResourceManagerService::Create();
fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
return 0;