Merge "Camera: Bump up the offline switch capture request timeout" into main
diff --git a/Android.bp b/Android.bp
index 7a2bb9b..72b8721 100644
--- a/Android.bp
+++ b/Android.bp
@@ -105,7 +105,6 @@
aidl_interface {
name: "av-audio-types-aidl",
- unstable: true,
host_supported: true,
vendor_available: true,
double_loadable: true,
@@ -125,4 +124,12 @@
sdk_version: "module_current",
},
},
+ versions_with_info: [
+ {
+ version: "1",
+ imports: ["android.hardware.audio.core-V2"],
+ },
+ ],
+ frozen: true,
+
}
diff --git a/aidl/android/media/audio/IHalAdapterVendorExtension.aidl b/aidl/android/media/audio/IHalAdapterVendorExtension.aidl
index b7a7678..48fb291 100644
--- a/aidl/android/media/audio/IHalAdapterVendorExtension.aidl
+++ b/aidl/android/media/audio/IHalAdapterVendorExtension.aidl
@@ -23,6 +23,8 @@
* is optional. Vendors may provide an implementation on the system_ext
* partition. The default instance of this interface, if provided, must be
* registered prior to the moment when the audio server connects to HAL modules.
+ * Vendors need to set the system property `ro.audio.ihaladaptervendorextension_enabled`
+ * to `true` for the framework to bind to this service.
*
* {@hide}
*/
diff --git a/aidl_api/av-audio-types-aidl/1/.hash b/aidl_api/av-audio-types-aidl/1/.hash
new file mode 100644
index 0000000..0002682
--- /dev/null
+++ b/aidl_api/av-audio-types-aidl/1/.hash
@@ -0,0 +1 @@
+ef1bc5ed9db445fbfc116cdec6e6ad081458ee40
diff --git a/aidl_api/av-audio-types-aidl/1/android/media/audio/IHalAdapterVendorExtension.aidl b/aidl_api/av-audio-types-aidl/1/android/media/audio/IHalAdapterVendorExtension.aidl
new file mode 100644
index 0000000..a9aa2c1
--- /dev/null
+++ b/aidl_api/av-audio-types-aidl/1/android/media/audio/IHalAdapterVendorExtension.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio;
+/* @hide */
+interface IHalAdapterVendorExtension {
+ @utf8InCpp String[] parseVendorParameterIds(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeys);
+ void parseVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeysAndValues, out android.hardware.audio.core.VendorParameter[] syncParameters, out android.hardware.audio.core.VendorParameter[] asyncParameters);
+ android.hardware.audio.core.VendorParameter[] parseBluetoothA2dpReconfigureOffload(in @utf8InCpp String rawValue);
+ android.hardware.audio.core.VendorParameter[] parseBluetoothLeReconfigureOffload(in @utf8InCpp String rawValue);
+ @utf8InCpp String processVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in android.hardware.audio.core.VendorParameter[] parameters);
+ enum ParameterScope {
+ MODULE = 0,
+ STREAM = 1,
+ }
+}
diff --git a/aidl_api/av-audio-types-aidl/current/android/media/audio/IHalAdapterVendorExtension.aidl b/aidl_api/av-audio-types-aidl/current/android/media/audio/IHalAdapterVendorExtension.aidl
new file mode 100644
index 0000000..a9aa2c1
--- /dev/null
+++ b/aidl_api/av-audio-types-aidl/current/android/media/audio/IHalAdapterVendorExtension.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media.audio;
+/* @hide */
+interface IHalAdapterVendorExtension {
+ @utf8InCpp String[] parseVendorParameterIds(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeys);
+ void parseVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in @utf8InCpp String rawKeysAndValues, out android.hardware.audio.core.VendorParameter[] syncParameters, out android.hardware.audio.core.VendorParameter[] asyncParameters);
+ android.hardware.audio.core.VendorParameter[] parseBluetoothA2dpReconfigureOffload(in @utf8InCpp String rawValue);
+ android.hardware.audio.core.VendorParameter[] parseBluetoothLeReconfigureOffload(in @utf8InCpp String rawValue);
+ @utf8InCpp String processVendorParameters(android.media.audio.IHalAdapterVendorExtension.ParameterScope scope, in android.hardware.audio.core.VendorParameter[] parameters);
+ enum ParameterScope {
+ MODULE = 0,
+ STREAM = 1,
+ }
+}
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 5d3b65b..8c3424f 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -255,6 +255,7 @@
template<class T>
void CameraManagerGlobal::registerAvailCallback(const T *callback) {
Mutex::Autolock _l(mLock);
+ getCameraServiceLocked();
Callback cb(callback);
auto pair = mCallbacks.insert(cb);
// Send initial callbacks if callback is newly registered
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index 3aa7817..099786b 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -396,6 +396,7 @@
template <class T>
void CameraManagerGlobal::registerAvailCallback(const T *callback) {
+ getCameraService();
Mutex::Autolock _l(mLock);
Callback cb(callback);
auto res = mCallbacks.insert(cb);
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index 0ee8779..e26290f 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -204,7 +204,7 @@
mInterpolatorType = interpolatorType;
return NO_ERROR;
default:
- ALOGE("invalid interpolatorType: %d", interpolatorType);
+ ALOGE("invalid interpolatorType: %d", static_cast<int>(interpolatorType));
return BAD_VALUE;
}
}
diff --git a/media/Android.mk b/media/Android.mk
deleted file mode 100644
index 220a358..0000000
--- a/media/Android.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-$(eval $(call declare-1p-copy-files,frameworks/av/media/libeffects,audio_effects.conf))
-$(eval $(call declare-1p-copy-files,frameworks/av/media/libeffects,audio_effects.xml))
-$(eval $(call declare-1p-copy-files,frameworks/av/media/libstagefright,))
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
index f95d723..16beb28 100644
--- a/media/aconfig/Android.bp
+++ b/media/aconfig/Android.bp
@@ -1,15 +1,19 @@
+// deprecated
aconfig_declarations {
name: "aconfig_mediacodec_flags",
package: "com.android.media.codec.flags",
+ container: "system",
srcs: ["mediacodec_flags.aconfig"],
}
+// deprecated
java_aconfig_library {
name: "aconfig_mediacodec_flags_java_lib",
aconfig_declarations: "aconfig_mediacodec_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// deprecated
cc_aconfig_library {
name: "aconfig_mediacodec_flags_c_lib",
min_sdk_version: "30",
@@ -21,3 +25,28 @@
],
aconfig_declarations: "aconfig_mediacodec_flags",
}
+
+aconfig_declarations {
+ name: "aconfig_codec_fwk_flags",
+ package: "android.media.codec",
+ container: "system",
+ srcs: ["codec_fwk.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.media.codec-aconfig-java",
+ aconfig_declarations: "aconfig_codec_fwk_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+cc_aconfig_library {
+ name: "android.media.codec-aconfig-cc",
+ min_sdk_version: "30",
+ vendor_available: true,
+ double_loadable: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+ aconfig_declarations: "aconfig_codec_fwk_flags",
+}
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
new file mode 100644
index 0000000..3092091
--- /dev/null
+++ b/media/aconfig/codec_fwk.aconfig
@@ -0,0 +1,76 @@
+# Codec framework feature flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+
+package: "android.media.codec"
+container: "system"
+
+flag {
+ name: "aidl_hal_input_surface"
+ namespace: "codec_fwk"
+ description: "Feature flags for enabling AIDL HAL InputSurface handling"
+ bug: "201479783"
+}
+
+flag {
+ name: "dynamic_color_aspects"
+ namespace: "codec_fwk"
+ description: "Feature flag for dynamic color aspect support"
+ bug: "297914560"
+}
+
+flag {
+ name: "hlg_editing"
+ namespace: "codec_fwk"
+ description: "Feature flag for HLG editing support"
+ bug: "316397061"
+}
+
+flag {
+ name: "in_process_sw_audio_codec"
+ namespace: "codec_fwk"
+ description: "Feature flag for in-process software audio codec API"
+ bug: "297922713"
+}
+
+flag {
+ name: "in_process_sw_audio_codec_support"
+ namespace: "codec_fwk"
+ description: "Feature flag for in-process software audio codec support"
+ bug: "325520135"
+}
+
+flag {
+ name: "large_audio_frame_finish"
+ namespace: "codec_fwk"
+ description: "Implementation flag for large audio frame finishing tasks"
+ bug: "325512893"
+}
+
+flag {
+ name: "null_output_surface"
+ namespace: "codec_fwk"
+ description: "Feature flag for null output Surface API"
+ bug: "297920102"
+}
+
+flag {
+ name: "null_output_surface_support"
+ namespace: "codec_fwk"
+ description: "Feature flag for null output Surface support"
+ bug: "325550522"
+}
+
+flag {
+ name: "region_of_interest"
+ namespace: "codec_fwk"
+ description: "Feature flag for region of interest API"
+ bug: "299191092"
+}
+
+flag {
+ name: "region_of_interest_support"
+ namespace: "codec_fwk"
+ description: "Feature flag for region of interest support"
+ bug: "325549730"
+}
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index c82ad4d..4d1e5ca 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -1,4 +1,10 @@
package: "com.android.media.codec.flags"
+container: "system"
+
+# ******************************************************************
+# !!! DO NOT ADD FURTHER FLAGS TO THIS FILE !!!
+# !!! USE codec_fwk.aconfig INSTEAD !!!
+# ******************************************************************
flag {
name: "large_audio_frame"
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
new file mode 100644
index 0000000..82f3d85
--- /dev/null
+++ b/media/audio/aconfig/Android.bp
@@ -0,0 +1,37 @@
+// media_audio namespace flags
+
+cc_defaults {
+ name: "audio-aconfig-cc-defaults",
+ host_supported: true,
+}
+
+// Framework available flags to follow
+// Care must be taken to avoid namespace conflicts.
+// These flags are accessible outside of the platform! Limit usage to @FlaggedApi wherever possible
+
+aconfig_declarations {
+ name: "android.media.audio-aconfig",
+ package: "android.media.audio",
+ container: "system",
+ srcs: ["audio_framework.aconfig"],
+ visibility: ["//frameworks/base/api"],
+}
+
+java_aconfig_library {
+ name: "android.media.audio-aconfig-java",
+ aconfig_declarations: "android.media.audio-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+cc_aconfig_library {
+ name: "android.media.audio-aconfig-cc",
+ aconfig_declarations: "android.media.audio-aconfig",
+ defaults: ["audio-aconfig-cc-defaults"],
+}
+
+aconfig_declarations_group {
+ name: "audio-framework-aconfig",
+ java_aconfig_libraries: [
+ "android.media.audio-aconfig-java",
+ ],
+}
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
new file mode 100644
index 0000000..2cafe58
--- /dev/null
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -0,0 +1,15 @@
+# Top level framework (android.media) flags
+# Only add flags here which must be included in framework.jar
+#
+# Please add flags in alphabetical order.
+
+package: "android.media.audio"
+
+flag {
+ name: "sco_managed_by_audio"
+ namespace: "media_audio"
+ description: "\
+Enable new implementation of headset profile device connection and\
+SCO audio activation."
+ bug: "265057196"
+}
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index bcb31f3..9eaddce 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -904,7 +904,7 @@
case Tag::voiceMask:
return convert(aidl, mVoice, __func__, "voice");
}
- ALOGE("%s: unexpected tag value %d", __func__, aidl.getTag());
+ ALOGE("%s: unexpected tag value %d", __func__, static_cast<int>(aidl.getTag()));
return unexpected(BAD_VALUE);
}
diff --git a/media/codec2/Android.mk b/media/codec2/Android.mk
deleted file mode 100644
index 82d739f..0000000
--- a/media/codec2/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# =============================================================================
-# DOCUMENTATION GENERATION
-# =============================================================================
-C2_ROOT := $(call my-dir)
-
-C2_DOCS_ROOT := $(OUT_DIR)/target/common/docs/codec2
-
-C2_OUT_TEMP := $(PRODUCT_OUT)/gen/ETC/Codec2-docs_intermediates
-
-C2_DOXY := $(or $(shell command -v doxygen),\
- $(shell command -v /Applications/Doxygen.app/Contents/Resources/doxygen))
-
-.PHONY: check-doxygen
-check-doxygen:
-ifndef C2_DOXY
- $(error 'doxygen is not available')
-endif
-
-$(C2_OUT_TEMP)/doxy-api.config: $(C2_ROOT)/docs/doxygen.config
- # only document include directory, no internal sections
- sed 's/\(^INPUT *=.*\)/\1include\//; \
- s/\(^INTERNAL_DOCS *= *\).*/\1NO/; \
- s/\(^ENABLED_SECTIONS *=.*\)INTERNAL\(.*\).*/\1\2/; \
- s:\(^OUTPUT_DIRECTORY *= \)out:\1'$(OUT_DIR)':;' \
- $(C2_ROOT)/docs/doxygen.config > $@
-
-$(C2_OUT_TEMP)/doxy-internal.config: $(C2_ROOT)/docs/doxygen.config
- sed 's:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$(OUT_DIR)'\2internal:;' \
- $(C2_ROOT)/docs/doxygen.config > $@
-
-.PHONY: docs-api
-docs-api: $(C2_OUT_TEMP)/doxy-api.config check-doxygen
- echo API docs are building in $(C2_DOCS_ROOT)/api
- rm -rf $(C2_DOCS_ROOT)/api
- mkdir -p $(C2_DOCS_ROOT)/api
- $(C2_DOXY) $(C2_OUT_TEMP)/doxy-api.config
-
-.PHONY: docs-internal
-docs-internal: $(C2_OUT_TEMP)/doxy-internal.config check-doxygen
- echo Internal docs are building in $(C2_DOCS_ROOT)/internal
- rm -rf $(C2_DOCS_ROOT)/internal
- mkdir -p $(C2_DOCS_ROOT)/internal
- $(C2_DOXY) $(C2_OUT_TEMP)/doxy-internal.config
-
-.PHONY: docs-all
-docs-all: docs-api docs-internal
-
-include $(call all-makefiles-under,$(call my-dir))
diff --git a/media/codec2/components/OWNERS b/media/codec2/components/OWNERS
new file mode 100644
index 0000000..453999a
--- /dev/null
+++ b/media/codec2/components/OWNERS
@@ -0,0 +1 @@
+kyslov@google.com
\ No newline at end of file
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index d1b08bd..c770d0c 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -35,14 +35,14 @@
#define FILEREAD_MAX_LAYERS 2
-#define DRC_DEFAULT_MOBILE_REF_LEVEL -16.0 /* 64*-0.25dB = -16 dB below full scale for mobile conf */
-#define DRC_DEFAULT_MOBILE_DRC_CUT 1.0 /* maximum compression of dynamic range for mobile conf */
-#define DRC_DEFAULT_MOBILE_DRC_BOOST 1.0 /* maximum compression of dynamic range for mobile conf */
-#define DRC_DEFAULT_MOBILE_DRC_HEAVY C2Config::DRC_COMPRESSION_HEAVY /* switch for heavy compression for mobile conf */
+#define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */
+#define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */
+#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
+#define DRC_DEFAULT_MOBILE_DRC_HEAVY 1 /* switch for heavy compression for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_EFFECT 3 /* MPEG-D DRC effect type; 3 => Limited playback range */
#define DRC_DEFAULT_MOBILE_DRC_ALBUM 0 /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */
#define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS (0.25) /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
-#define DRC_DEFAULT_MOBILE_ENC_LEVEL (0.25) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
+#define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */
// names of properties that can be used to override the default DRC settings
#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level"
@@ -145,9 +145,13 @@
.withSetter(ProfileLevelSetter)
.build());
+ C2Config::drc_compression_mode_t defaultCompressionMode =
+ property_get_int32(PROP_DRC_OVERRIDE_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY) == 1
+ ? C2Config::DRC_COMPRESSION_HEAVY
+ : C2Config::DRC_COMPRESSION_LIGHT;
addParameter(
DefineParam(mDrcCompressMode, C2_PARAMKEY_DRC_COMPRESSION_MODE)
- .withDefault(new C2StreamDrcCompressionModeTuning::input(0u, C2Config::DRC_COMPRESSION_HEAVY))
+ .withDefault(new C2StreamDrcCompressionModeTuning::input(0u, defaultCompressionMode))
.withFields({
C2F(mDrcCompressMode, value).oneOf({
C2Config::DRC_COMPRESSION_ODM_DEFAULT,
@@ -158,37 +162,48 @@
.withSetter(Setter<decltype(*mDrcCompressMode)>::StrictValueWithNoDeps)
.build());
+
+ float defaultRefLevel = -0.25 * property_get_int32(PROP_DRC_OVERRIDE_REF_LEVEL,
+ DRC_DEFAULT_MOBILE_REF_LEVEL);
addParameter(
DefineParam(mDrcTargetRefLevel, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL)
- .withDefault(new C2StreamDrcTargetReferenceLevelTuning::input(0u, DRC_DEFAULT_MOBILE_REF_LEVEL))
+ .withDefault(new C2StreamDrcTargetReferenceLevelTuning::input(0u, defaultRefLevel))
.withFields({C2F(mDrcTargetRefLevel, value).inRange(-31.75, 0.25)})
.withSetter(Setter<decltype(*mDrcTargetRefLevel)>::StrictValueWithNoDeps)
.build());
+ float defaultEncLevel = -0.25 * property_get_int32(PROP_DRC_OVERRIDE_ENC_LEVEL,
+ DRC_DEFAULT_MOBILE_ENC_LEVEL);
addParameter(
DefineParam(mDrcEncTargetLevel, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL)
- .withDefault(new C2StreamDrcEncodedTargetLevelTuning::input(0u, DRC_DEFAULT_MOBILE_ENC_LEVEL))
+ .withDefault(new C2StreamDrcEncodedTargetLevelTuning::input(0u, defaultEncLevel))
.withFields({C2F(mDrcEncTargetLevel, value).inRange(-31.75, 0.25)})
.withSetter(Setter<decltype(*mDrcEncTargetLevel)>::StrictValueWithNoDeps)
.build());
+ float defaultDrcBoost =
+ property_get_int32(PROP_DRC_OVERRIDE_BOOST, DRC_DEFAULT_MOBILE_DRC_BOOST) / 127.;
addParameter(
DefineParam(mDrcBoostFactor, C2_PARAMKEY_DRC_BOOST_FACTOR)
- .withDefault(new C2StreamDrcBoostFactorTuning::input(0u, DRC_DEFAULT_MOBILE_DRC_BOOST))
+ .withDefault(new C2StreamDrcBoostFactorTuning::input(0u, defaultDrcBoost))
.withFields({C2F(mDrcBoostFactor, value).inRange(0, 1.)})
.withSetter(Setter<decltype(*mDrcBoostFactor)>::StrictValueWithNoDeps)
.build());
+ float defaultDrcCut =
+ property_get_int32(PROP_DRC_OVERRIDE_CUT, DRC_DEFAULT_MOBILE_DRC_CUT) / 127.;
addParameter(
DefineParam(mDrcAttenuationFactor, C2_PARAMKEY_DRC_ATTENUATION_FACTOR)
- .withDefault(new C2StreamDrcAttenuationFactorTuning::input(0u, DRC_DEFAULT_MOBILE_DRC_CUT))
+ .withDefault(new C2StreamDrcAttenuationFactorTuning::input(0u, defaultDrcCut))
.withFields({C2F(mDrcAttenuationFactor, value).inRange(0, 1.)})
.withSetter(Setter<decltype(*mDrcAttenuationFactor)>::StrictValueWithNoDeps)
.build());
+ C2Config::drc_effect_type_t defaultDrcEffectType = (C2Config::drc_effect_type_t)
+ property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT);
addParameter(
DefineParam(mDrcEffectType, C2_PARAMKEY_DRC_EFFECT_TYPE)
- .withDefault(new C2StreamDrcEffectTypeTuning::input(0u, C2Config::DRC_EFFECT_LIMITED_PLAYBACK_RANGE))
+ .withDefault(new C2StreamDrcEffectTypeTuning::input(0u, defaultDrcEffectType))
.withFields({
C2F(mDrcEffectType, value).oneOf({
C2Config::DRC_EFFECT_ODM_DEFAULT,
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 71909e5..7c9d3e8 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -338,6 +338,19 @@
}
c2_status_t C2SoftAomEnc::onStop() {
+ IntfImpl::Lock lock = mIntf->lock();
+ std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
+ lock.unlock();
+ if (requestSync != mRequestSync) {
+ // we can handle IDR immediately
+ if (requestSync->value) {
+ // unset request
+ C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
+ }
+ mRequestSync = requestSync;
+ }
onRelease();
return C2_OK;
}
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 96a4c4a..3385b95 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -416,6 +416,7 @@
ivdext_create_op_t s_create_op = {};
s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+ s_create_ip.u4_keep_threads_active = 1;
s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index e424860..80a5e67 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -152,6 +152,17 @@
.build());
addParameter(
+ DefineParam(mBitrateMode, C2_PARAMKEY_BITRATE_MODE)
+ .withDefault(new C2StreamBitrateModeTuning::output(0u, C2Config::BITRATE_VARIABLE))
+ .withFields({C2F(mBitrateMode, value).oneOf({
+ C2Config::BITRATE_CONST,
+ C2Config::BITRATE_VARIABLE,
+ C2Config::BITRATE_IGNORE})
+ })
+ .withSetter(Setter<decltype(*mBitrateMode)>::StrictValueWithNoDeps)
+ .build());
+
+ addParameter(
DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
.withDefault(new C2StreamBitrateInfo::output(0u, 64000))
.withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
@@ -536,6 +547,9 @@
std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
std::shared_ptr<C2StreamIntraRefreshTuning::output> getIntraRefresh_l() const { return mIntraRefresh; }
std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
+ std::shared_ptr<C2StreamBitrateModeTuning::output> getBitrateMode_l() const {
+ return mBitrateMode;
+ }
std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> getRequestSync_l() const { return mRequestSync; }
std::shared_ptr<C2StreamGopTuning::output> getGop_l() const { return mGop; }
@@ -552,6 +566,7 @@
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefresh;
std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+ std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
std::shared_ptr<C2StreamGopTuning::output> mGop;
@@ -1154,6 +1169,7 @@
{
IntfImpl::Lock lock = mIntf->lock();
mSize = mIntf->getSize_l();
+ mBitrateMode = mIntf->getBitrateMode_l();
mBitrate = mIntf->getBitrate_l();
mFrameRate = mIntf->getFrameRate_l();
mIntraRefresh = mIntf->getIntraRefresh_l();
@@ -1326,8 +1342,23 @@
} else {
ps_init_ip->u4_enable_recon = 0;
}
+
+ switch (mBitrateMode->value) {
+ case C2Config::BITRATE_IGNORE:
+ ps_init_ip->e_rc_mode = IVE_RC_NONE;
+ break;
+ case C2Config::BITRATE_CONST:
+ ps_init_ip->e_rc_mode = IVE_RC_CBR_NON_LOW_DELAY;
+ break;
+ case C2Config::BITRATE_VARIABLE:
+ ps_init_ip->e_rc_mode = IVE_RC_STORAGE;
+ break;
+ default:
+ ps_init_ip->e_rc_mode = DEFAULT_RC_MODE;
+ break;
+ break;
+ }
ps_init_ip->e_recon_color_fmt = DEFAULT_RECON_COLOR_FORMAT;
- ps_init_ip->e_rc_mode = DEFAULT_RC_MODE;
ps_init_ip->u4_max_framerate = DEFAULT_MAX_FRAMERATE;
ps_init_ip->u4_max_bitrate = DEFAULT_MAX_BITRATE;
ps_init_ip->u4_num_bframes = mBframes;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.h b/media/codec2/components/avc/C2SoftAvcEnc.h
index cde6604..33d166f 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.h
+++ b/media/codec2/components/avc/C2SoftAvcEnc.h
@@ -191,6 +191,7 @@
std::shared_ptr<C2StreamIntraRefreshTuning::output> mIntraRefresh;
std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+ std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 15d6dcd..81db2a1 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -407,6 +407,7 @@
ivdext_create_op_t s_create_op = {};
s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+ s_create_ip.u4_keep_threads_active = 1;
s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorformat;
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index 439323c..491098d 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -433,6 +433,7 @@
s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
s_fill_mem_ip.u4_share_disp_buf = 0;
+ s_fill_mem_ip.u4_keep_threads_active = 1;
s_fill_mem_ip.e_output_format = mIvColorformat;
s_fill_mem_ip.u4_deinterlace = 1;
s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
@@ -474,6 +475,7 @@
s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
s_init_ip.u4_share_disp_buf = 0;
s_init_ip.u4_deinterlace = 1;
+ s_init_ip.u4_keep_threads_active = 1;
s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index e903069..2a33048 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -29,6 +29,12 @@
#define INT32_MAX 2147483647
#endif
+/* Quantization param values defined by the spec */
+#define VPX_QP_MIN 0
+#define VPX_QP_MAX 63
+#define VPX_QP_DEFAULT_MIN VPX_QP_MIN
+#define VPX_QP_DEFAULT_MAX VPX_QP_MAX
+
namespace android {
C2SoftVpxEnc::IntfImpl::IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
@@ -197,6 +203,20 @@
})
.withSetter(CodedColorAspectsSetter, mColorAspects)
.build());
+
+ addParameter(
+ DefineParam(mPictureQuantization, C2_PARAMKEY_PICTURE_QUANTIZATION)
+ .withDefault(C2StreamPictureQuantizationTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mPictureQuantization, m.values[0].type_).oneOf(
+ {C2Config::I_FRAME, C2Config::P_FRAME}),
+ C2F(mPictureQuantization, m.values[0].min).inRange(
+ VPX_QP_DEFAULT_MIN, VPX_QP_DEFAULT_MAX),
+ C2F(mPictureQuantization, m.values[0].max).inRange(
+ VPX_QP_DEFAULT_MIN, VPX_QP_DEFAULT_MAX)})
+ .withSetter(PictureQuantizationSetter)
+ .build());
+
}
C2R C2SoftVpxEnc::IntfImpl::BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
@@ -330,6 +350,58 @@
double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
}
+
+C2R C2SoftVpxEnc::IntfImpl::PictureQuantizationSetter(bool mayBlock,
+ C2P<C2StreamPictureQuantizationTuning::output>
+ &me) {
+ (void)mayBlock;
+ // these are the ones we're going to set, so want them to default
+ // to the DEFAULT values for the codec
+ int32_t iMin = VPX_QP_DEFAULT_MIN, pMin = VPX_QP_DEFAULT_MIN;
+ int32_t iMax = VPX_QP_DEFAULT_MAX, pMax = VPX_QP_DEFAULT_MAX;
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+ // layerMin is clamped to [VPX_QP_MIN, layerMax] to avoid error
+ // cases where layer.min > layer.max
+ int32_t layerMax = std::clamp(layer.max, VPX_QP_MIN, VPX_QP_MAX);
+ int32_t layerMin = std::clamp(layer.min, VPX_QP_MIN, layerMax);
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ iMax = layerMax;
+ iMin = layerMin;
+ ALOGV("iMin %d iMax %d", iMin, iMax);
+ } else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ pMax = layerMax;
+ pMin = layerMin;
+ ALOGV("pMin %d pMax %d", pMin, pMax);
+ }
+ }
+ ALOGV("PictureQuantizationSetter(entry): i %d-%d p %d-%d",
+ iMin, iMax, pMin, pMax);
+
+ // vpx library takes same range for I/P picture type
+ int32_t maxFrameQP = std::min({iMax, pMax});
+ int32_t minFrameQP = std::max({iMin, pMin});
+ if (minFrameQP > maxFrameQP) {
+ minFrameQP = maxFrameQP;
+ }
+ // put them back into the structure
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = me.v.m.values[i];
+
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ else if (layer.type_ == C2Config::picture_type_t(P_FRAME)) {
+ me.set().m.values[i].max = maxFrameQP;
+ me.set().m.values[i].min = minFrameQP;
+ }
+ }
+ ALOGV("PictureQuantizationSetter(exit): minFrameQP = %d maxFrameQP = %d",
+ minFrameQP, maxFrameQP);
+ return C2R::Ok();
+}
+
C2R C2SoftVpxEnc::IntfImpl::ColorAspectsSetter(bool mayBlock,
C2P<C2StreamColorAspectsInfo::input>& me) {
(void)mayBlock;
@@ -453,6 +525,7 @@
mRequestSync = mIntf->getRequestSync_l();
mLayering = mIntf->getTemporalLayers_l();
mTemporalLayers = mLayering->m.layerCount;
+ mQpBounds = mIntf->getPictureQuantization_l();
}
switch (mBitrateMode->value) {
@@ -466,6 +539,18 @@
break;
}
+ if (mQpBounds->flexCount() > 0) {
+ // read min max qp for sequence
+ for (size_t i = 0; i < mQpBounds->flexCount(); ++i) {
+ const C2PictureQuantizationStruct &layer = mQpBounds->m.values[i];
+ if (layer.type_ == C2Config::picture_type_t(I_FRAME)) {
+ mMaxQuantizer = layer.max;
+ mMinQuantizer = layer.min;
+ break;
+ }
+ }
+ }
+
setCodecSpecificInterface();
if (!mCodecInterface) goto CleanUp;
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index bfb4444..980de04 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -219,6 +219,7 @@
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
std::shared_ptr<C2StreamTemporalLayeringTuning::output> mLayering;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mQpBounds;
C2_DO_NOT_COPY(C2SoftVpxEnc);
};
@@ -250,6 +251,9 @@
static C2R LayeringSetter(bool mayBlock, C2P<C2StreamTemporalLayeringTuning::output>& me);
+ static C2R PictureQuantizationSetter(bool mayBlock,
+ C2P<C2StreamPictureQuantizationTuning::output> &me);
+
// unsafe getters
std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
std::shared_ptr<C2StreamIntraRefreshTuning::output> getIntraRefresh_l() const {
@@ -269,6 +273,9 @@
std::shared_ptr<C2StreamColorAspectsInfo::output> getCodedColorAspects_l() const {
return mCodedColorAspects;
}
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const {
+ return mPictureQuantization;
+ }
uint32_t getSyncFramePeriod() const;
static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me);
static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
@@ -287,6 +294,7 @@
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
+ std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
};
} // namespace android
diff --git a/media/codec2/core/include/C2Param.h b/media/codec2/core/include/C2Param.h
index e938f96..387d2b8 100644
--- a/media/codec2/core/include/C2Param.h
+++ b/media/codec2/core/include/C2Param.h
@@ -427,7 +427,9 @@
inline bool operator==(const C2Param &o) const {
return equals(o) && memcmp(this, &o, _mSize) == 0;
}
+#if __cplusplus < 202002
inline bool operator!=(const C2Param &o) const { return !operator==(o); }
+#endif
/// safe(r) type cast from pointer and size
inline static C2Param* From(void *addr, size_t len) {
diff --git a/media/codec2/core/include/C2ParamDef.h b/media/codec2/core/include/C2ParamDef.h
index 86dfe65..1805464 100644
--- a/media/codec2/core/include/C2ParamDef.h
+++ b/media/codec2/core/include/C2ParamDef.h
@@ -212,6 +212,26 @@
}
};
+/// Define equality (and inequality) operators for params.
+#if __cplusplus < 202002
+
+#define DEFINE_EQUALITY_OPERATORS(_Type, T) \
+ inline bool operator==(const _Type &o) const { \
+ return this->T::operator==(o); \
+ } \
+ inline bool operator!=(const _Type &o) const { \
+ return !operator==(o); \
+ }
+
+#else
+
+#define DEFINE_EQUALITY_OPERATORS(_Type, T) \
+ inline bool operator==(const _Type &o) const { \
+ return this->T::operator==(o); \
+ }
+
+#endif
+
/// Define From() cast operators for params.
#define DEFINE_CAST_OPERATORS(_Type) \
inline static _Type* From(C2Param *other) { \
@@ -404,12 +424,12 @@
/// Specialization for an input port parameter.
struct input : public T, public S,
public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
- using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Wrapper around base structure's constructor.
template<typename ...Args>
inline input(const Args(&... args)) : T(sizeof(_Type), input::PARAM_TYPE), S(args...) { }
+ DEFINE_EQUALITY_OPERATORS(input, T)
DEFINE_CAST_OPERATORS(input)
};
@@ -417,12 +437,12 @@
/// Specialization for an output port parameter.
struct output : public T, public S,
public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
- using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Wrapper around base structure's constructor.
template<typename ...Args>
inline output(const Args(&... args)) : T(sizeof(_Type), output::PARAM_TYPE), S(args...) { }
+ DEFINE_EQUALITY_OPERATORS(output, T)
DEFINE_CAST_OPERATORS(output)
};
};
@@ -472,7 +492,6 @@
/// Specialization for an input port parameter.
struct input : public T,
public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
- using T::operator!=;
private:
/// Wrapper around base structure's constructor while also specifying port/direction.
template<typename ...Args>
@@ -482,6 +501,7 @@
public:
S m; ///< wrapped flexible structure
+ DEFINE_EQUALITY_OPERATORS(input, T)
DEFINE_FLEXIBLE_METHODS(input, S)
DEFINE_CAST_OPERATORS(input)
};
@@ -489,7 +509,6 @@
/// Specialization for an output port parameter.
struct output : public T,
public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
- using T::operator!=;
private:
/// Wrapper around base structure's constructor while also specifying port/direction.
template<typename ...Args>
@@ -499,6 +518,7 @@
public:
S m; ///< wrapped flexible structure
+ DEFINE_EQUALITY_OPERATORS(output, T)
DEFINE_FLEXIBLE_METHODS(output, S)
DEFINE_CAST_OPERATORS(output)
};
@@ -553,7 +573,6 @@
struct input : public T, public S,
public _C2StructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
- using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Default constructor. Stream-ID is undefined.
@@ -565,6 +584,7 @@
/// Set stream-id. \retval true if the stream-id was successfully set.
inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+ DEFINE_EQUALITY_OPERATORS(input, T)
DEFINE_CAST_OPERATORS(input)
};
@@ -572,7 +592,6 @@
struct output : public T, public S,
public _C2StructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
- using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Default constructor. Stream-ID is undefined.
@@ -584,6 +603,7 @@
/// Set stream-id. \retval true if the stream-id was successfully set.
inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+ DEFINE_EQUALITY_OPERATORS(output, T)
DEFINE_CAST_OPERATORS(output)
};
};
@@ -640,7 +660,6 @@
struct input : public T,
public _C2FlexStructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
- using T::operator!=;
private:
/// Default constructor. Stream-ID is undefined.
inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
@@ -655,6 +674,7 @@
/// Set stream-id. \retval true if the stream-id was successfully set.
inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+ DEFINE_EQUALITY_OPERATORS(input, T)
DEFINE_FLEXIBLE_METHODS(input, S)
DEFINE_CAST_OPERATORS(input)
};
@@ -663,7 +683,6 @@
struct output : public T,
public _C2FlexStructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
- using T::operator!=;
private:
/// Default constructor. Stream-ID is undefined.
inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
@@ -678,6 +697,7 @@
/// Set stream-id. \retval true if the stream-id was successfully set.
inline bool setStream(unsigned stream) { return C2Param::setStream(stream); }
+ DEFINE_EQUALITY_OPERATORS(output, T)
DEFINE_FLEXIBLE_METHODS(output, S)
DEFINE_CAST_OPERATORS(output)
};
diff --git a/media/codec2/docs/doxygen.config b/media/codec2/docs/doxygen.config
index 5c3bea3..ab8b53b 100644
--- a/media/codec2/docs/doxygen.config
+++ b/media/codec2/docs/doxygen.config
@@ -162,7 +162,7 @@
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-STRIP_FROM_PATH = frameworks/av/media/libstagefright/codec2
+STRIP_FROM_PATH = frameworks/av/media/codec2
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
@@ -781,7 +781,7 @@
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = frameworks/av/media/libstagefright/codec2/
+INPUT = frameworks/av/media/codec2/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -897,7 +897,7 @@
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
-INPUT_FILTER = frameworks/av/media/libstagefright/codec2/docs/doxyfilter.sh
+INPUT_FILTER = frameworks/av/media/codec2/docs/doxyfilter.sh
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
diff --git a/media/codec2/doxygen.sh b/media/codec2/doxygen.sh
new file mode 100755
index 0000000..ca5aeed
--- /dev/null
+++ b/media/codec2/doxygen.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+# 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.
+
+# =============================================================================
+# DOCUMENTATION GENERATION
+# =============================================================================
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "error: Android build is not set up. Run this command after lunch." >&2
+ exit 2
+fi
+
+OUT_DIR=$ANDROID_BUILD_TOP/out
+
+# Codec 2.0 source and target paths
+C2_ROOT=$(dirname "$0")
+C2_DOCS_ROOT=$OUT_DIR/target/common/docs/codec2
+C2_OUT_TEMP=$ANDROID_PRODUCT_OUT/gen/ETC/Codec2-docs_intermediates
+
+# Doxygen path
+DOXY=$(which doxygen)
+DOXY_MAC="/Applications/Doxygen.app/Contents/Resources/doxygen"
+if [ -z "$DOXY" -a -x "$DOXY_MAC" ]; then
+ DOXY=$DOXY_MAC
+fi
+
+if [ -z "$DOXY" ]; then
+ echo "error: doxygen is not available" >&2
+ exit 2
+fi
+
+# Create doxygen config
+# ---------------------
+gen_doxy() {
+ local variant=$1
+ local variant_lc=$(echo $variant | tr A-Z a-z)
+ mkdir -p $C2_OUT_TEMP
+ if [ "$variant_lc" == "api" ]; then
+ # only document include directory, no internal sections
+ sed 's/\(^INPUT *=.*\)/\1core\/include\//;
+ s/\(^INTERNAL_DOCS *= *\).*/\1NO/;
+ s/\(^ENABLED_SECTIONS *=.*\)INTERNAL\(.*\).*/\1\2/;
+ s:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$OUT_DIR'\2'$variant_lc':;' \
+ $C2_ROOT/docs/doxygen.config > $C2_OUT_TEMP/doxy-$variant_lc.config
+
+ ls -la $C2_OUT_TEMP/doxy-$variant_lc.config
+ else
+ sed 's:\(^OUTPUT_DIRECTORY *= \)out\(.*\)api:\1'$OUT_DIR'\2'$variant_lc':;' \
+ $C2_ROOT/docs/doxygen.config > $C2_OUT_TEMP/doxy-$variant_lc.config
+ fi
+
+ echo $variant docs are building in $C2_DOCS_ROOT/$variant_lc
+ rm -rf $C2_DOCS_ROOT/$variant_lc
+ mkdir -p $C2_DOCS_ROOT/$variant_lc
+ pushd $ANDROID_BUILD_TOP
+ $DOXY $C2_OUT_TEMP/doxy-$variant_lc.config
+ popd
+}
+
+usage() {
+ echo "usage: $(basename "$0") [target]"
+ echo " where target can be one of:"
+ echo " all: build both API and internal docs (default)"
+ echo " api: build API docs only"
+ echo " internal: build internal docs which include implementation details"
+}
+
+TARGET=${1:-all}
+case "$TARGET" in
+ api) gen_doxy API;;
+ internal) gen_doxy Internal;;
+ all) gen_doxy API; gen_doxy Internal;;
+ -h) usage; exit 0;;
+ *) echo "unknown target '$TARGET'" >&2; usage; exit 2;;
+esac
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index 4c2d5d3..eb64a4a 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -46,13 +46,17 @@
using ::aidl::android::hardware::common::NativeHandle;
using ::aidl::android::hardware::media::bufferpool2::IClientManager;
using ::ndk::ScopedAStatus;
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
// ComponentListener wrapper
struct Component::Listener : public C2Component::Listener {
Listener(const std::shared_ptr<Component>& component) :
- mComponent(component),
- mListener(component->mListener) {
+ mComponent(component),
+ mListener(component->mListener) {
+ CHECK(component);
+ CHECK(component->mListener);
}
virtual void onError_nb(
@@ -137,6 +141,52 @@
std::weak_ptr<IComponentListener> mListener;
};
+// Component listener for handle multiple access-units
+struct MultiAccessUnitListener : public Component::Listener {
+ MultiAccessUnitListener(const std::shared_ptr<Component>& component,
+ const std::shared_ptr<MultiAccessUnitHelper> &helper):
+ Listener(component), mHelper(helper) {
+ }
+
+ virtual void onError_nb(
+ std::weak_ptr<C2Component> c2component,
+ uint32_t errorCode) override {
+ if (mHelper) {
+ std::list<std::unique_ptr<C2Work>> worklist;
+ mHelper->error(&worklist);
+ if (!worklist.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(worklist));
+ }
+ }
+ Listener::onError_nb(c2component, errorCode);
+ }
+
+ virtual void onTripped_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+ ) override {
+ Listener::onTripped_nb(c2component,
+ c2settingResult);
+ }
+
+ virtual void onWorkDone_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::list<std::unique_ptr<C2Work>> c2workItems) override {
+ if (mHelper) {
+ std::list<std::unique_ptr<C2Work>> processedWork;
+ mHelper->gather(c2workItems, &processedWork);
+ if (!processedWork.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(processedWork));
+ }
+ } else {
+ Listener::onWorkDone_nb(c2component, std::move(c2workItems));
+ }
+ }
+
+ protected:
+ std::shared_ptr<MultiAccessUnitHelper> mHelper;
+};
+
// Component::DeathContext
struct Component::DeathContext {
std::weak_ptr<Component> mWeakComp;
@@ -149,14 +199,15 @@
const std::shared_ptr<ComponentStore>& store,
const std::shared_ptr<IClientManager>& clientPoolManager)
: mComponent{component},
- mInterface{SharedRefBase::make<ComponentInterface>(
- component->intf(), store->getParameterCache())},
mListener{listener},
mStore{store},
mBufferPoolSender{clientPoolManager},
mDeathContext(nullptr) {
// Retrieve supported parameters from store
// TODO: We could cache this per component/interface type
+ mMultiAccessUnitIntf = store->tryCreateMultiAccessUnitInterface(component->intf());
+ mInterface = SharedRefBase::make<ComponentInterface>(
+ component->intf(), mMultiAccessUnitIntf, store->getParameterCache());
mInit = mInterface->status();
}
@@ -179,8 +230,21 @@
registerFrameData(mListener, work->input);
}
}
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitHelper) {
+ std::list<std::list<std::unique_ptr<C2Work>>> c2worklists;
+ mMultiAccessUnitHelper->scatter(c2works, &c2worklists);
+ for (auto &c2worklist : c2worklists) {
+ err = mComponent->queue_nb(&c2worklist);
+ if (err != C2_OK) {
+ LOG(ERROR) << "Error Queuing to component.";
+ return ScopedAStatus::fromServiceSpecificError(err);
+ }
+ }
+ return ScopedAStatus::ok();
+ }
- c2_status_t err = mComponent->queue_nb(&c2works);
+ err = mComponent->queue_nb(&c2works);
if (err == C2_OK) {
return ScopedAStatus::ok();
}
@@ -192,7 +256,9 @@
c2_status_t c2res = mComponent->flush_sm(
C2Component::FLUSH_COMPONENT,
&c2flushedWorks);
-
+ if (mMultiAccessUnitHelper) {
+ c2res = mMultiAccessUnitHelper->flush(&c2flushedWorks);
+ }
// Unregister input buffers.
for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
if (work) {
@@ -289,30 +355,22 @@
const IComponent::BlockPoolAllocator &allocator,
IComponent::BlockPool *blockPool) {
std::shared_ptr<C2BlockPool> c2BlockPool;
- static constexpr IComponent::BlockPoolAllocator::Tag ALLOCATOR_ID =
- IComponent::BlockPoolAllocator::allocatorId;
- static constexpr IComponent::BlockPoolAllocator::Tag IGBA =
- IComponent::BlockPoolAllocator::allocator;
c2_status_t status = C2_OK;
::android::C2PlatformAllocatorDesc allocatorParam;
- switch (allocator.getTag()) {
- case ALLOCATOR_ID: {
- allocatorParam.allocatorId =
- allocator.get<IComponent::BlockPoolAllocator::allocatorId>();
- }
- break;
- case IGBA: {
- allocatorParam.allocatorId = ::android::C2PlatformAllocatorStore::IGBA;
- allocatorParam.igba =
- allocator.get<IComponent::BlockPoolAllocator::allocator>().igba;
+ allocatorParam.allocatorId = allocator.allocatorId;
+ switch (allocator.allocatorId) {
+ case ::android::C2PlatformAllocatorStore::IGBA: {
+ allocatorParam.igba = allocator.gbAllocator->igba;
allocatorParam.waitableFd.reset(
- allocator.get<IComponent::BlockPoolAllocator::allocator>()
- .waitableFd.dup().release());
+ allocator.gbAllocator->waitableFd.dup().release());
}
break;
- default:
- return ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED);
+ default: {
+ // no-op
+ }
+ break;
}
+
#ifdef __ANDROID_APEX__
status = ::android::CreateCodec2BlockPool(
allocatorParam,
@@ -370,6 +428,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
if (status == C2_OK) {
return ScopedAStatus::ok();
@@ -383,6 +444,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
if (status == C2_OK) {
return ScopedAStatus::ok();
@@ -421,13 +485,20 @@
void Component::initListener(const std::shared_ptr<Component>& self) {
if (__builtin_available(android __ANDROID_API_T__, *)) {
- std::shared_ptr<C2Component::Listener> c2listener =
+ std::shared_ptr<C2Component::Listener> c2listener;
+ if (mMultiAccessUnitIntf) {
+ mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+ }
+ c2listener = mMultiAccessUnitHelper ?
+ std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
std::make_shared<Listener>(self);
c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
if (res != C2_OK) {
mInit = res;
}
+ // b/321902635, mListener should not be null.
+ CHECK(mListener);
mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
AIBinder_DeathRecipient_new(OnBinderDied));
mDeathContext = new DeathContext{ref<Component>()};
diff --git a/media/codec2/hal/aidl/ComponentInterface.cpp b/media/codec2/hal/aidl/ComponentInterface.cpp
index 2d812c9..8ae9fa8 100644
--- a/media/codec2/hal/aidl/ComponentInterface.cpp
+++ b/media/codec2/hal/aidl/ComponentInterface.cpp
@@ -24,6 +24,8 @@
#include <utils/Timers.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Debug.h>
#include <C2PlatformSupport.h>
@@ -43,9 +45,10 @@
// Implementation of ConfigurableC2Intf based on C2ComponentInterface
struct CompIntf : public ConfigurableC2Intf {
- CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+ CompIntf(const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<MultiAccessUnitInterface>& multiAccessUnitIntf):
ConfigurableC2Intf{intf->getName(), intf->getId()},
- mIntf{intf} {
+ mIntf{intf}, mMultiAccessUnitIntf{multiAccessUnitIntf} {
}
virtual c2_status_t config(
@@ -53,7 +56,34 @@
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2SettingResult>>* const failures
) override {
- return mIntf->config_vb(params, mayBlock, failures);
+ std::vector<C2Param*> paramsToIntf;
+ std::vector<C2Param*> paramsToLargeFrameIntf;
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitIntf == nullptr) {
+ err = mIntf->config_vb(params, mayBlock, failures);
+ return err;
+ }
+ for (auto &p : params) {
+ if (mMultiAccessUnitIntf->isParamSupported(p->index())) {
+ paramsToLargeFrameIntf.push_back(p);
+ } else {
+ paramsToIntf.push_back(p);
+ }
+ }
+ c2_status_t err1 = C2_OK;
+ if (paramsToIntf.size() > 0) {
+ err1 = mIntf->config_vb(paramsToIntf, mayBlock, failures);
+ }
+ if (err1 != C2_OK) {
+ LOG(ERROR) << "We have a failed config";
+ }
+ c2_status_t err2 = C2_OK;
+ if (paramsToLargeFrameIntf.size() > 0) {
+ err2 = mMultiAccessUnitIntf->config(
+ paramsToLargeFrameIntf, mayBlock, failures);
+ }
+ // TODO: correct failure vector
+ return err1 != C2_OK ? err1 : err2;
}
virtual c2_status_t query(
@@ -61,23 +91,82 @@
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2Param>>* const params
) const override {
- return mIntf->query_vb({}, indices, mayBlock, params);
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitIntf == nullptr) {
+ err = mIntf->query_vb({}, indices, mayBlock, params);
+ return err;
+ }
+ std::vector<C2Param::Index> paramsToIntf;
+ std::vector<C2Param::Index> paramsToLargeFrameIntf;
+ for (auto &i : indices) {
+ if (mMultiAccessUnitIntf->isParamSupported(i)) {
+ paramsToLargeFrameIntf.push_back(i);
+ } else {
+ paramsToIntf.push_back(i);
+ }
+ }
+ c2_status_t err1 = C2_OK;
+ if (paramsToIntf.size() > 0) {
+ err1 = mIntf->query_vb({}, paramsToIntf, mayBlock, params);
+ }
+ c2_status_t err2 = C2_OK;
+ if (paramsToLargeFrameIntf.size() > 0) {
+ err2 = mMultiAccessUnitIntf->query(
+ {}, paramsToLargeFrameIntf, mayBlock, params);
+ }
+ // TODO: correct failure vector
+ return err1 != C2_OK ? err1 : err2;
}
virtual c2_status_t querySupportedParams(
std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
) const override {
- return mIntf->querySupportedParams_nb(params);
+ c2_status_t err = mIntf->querySupportedParams_nb(params);
+ if (mMultiAccessUnitIntf != nullptr) {
+ err = mMultiAccessUnitIntf->querySupportedParams(params);
+ }
+ return err;
}
virtual c2_status_t querySupportedValues(
std::vector<C2FieldSupportedValuesQuery>& fields,
c2_blocking_t mayBlock) const override {
- return mIntf->querySupportedValues_vb(fields, mayBlock);
+ if (mMultiAccessUnitIntf == nullptr) {
+ return mIntf->querySupportedValues_vb(fields, mayBlock);
+ }
+ std::vector<C2FieldSupportedValuesQuery> dup = fields;
+ std::vector<C2FieldSupportedValuesQuery> queryArray[2];
+ std::map<C2ParamField, std::pair<uint32_t, size_t>> queryMap;
+ c2_status_t err = C2_OK;
+ for (int i = 0 ; i < fields.size(); i++) {
+ const C2ParamField &field = fields[i].field();
+ uint32_t queryArrayIdx = 1;
+ if (mMultiAccessUnitIntf->isValidField(fields[i].field())) {
+ queryArrayIdx = 0;
+ }
+ queryMap[field] = std::make_pair(
+ queryArrayIdx, queryArray[queryArrayIdx].size());
+ queryArray[queryArrayIdx].push_back(fields[i]);
+ }
+ if (queryArray[0].size() > 0) {
+ err = mMultiAccessUnitIntf->querySupportedValues(queryArray[0], mayBlock);
+ }
+ if (queryArray[1].size() > 0) {
+ err = mIntf->querySupportedValues_vb(queryArray[1], mayBlock);
+ }
+ for (int i = 0 ; i < dup.size(); i++) {
+ auto it = queryMap.find(dup[i].field());
+ if (it != queryMap.end()) {
+ std::pair<uint32_t, size_t> queryid = it->second;
+ fields[i] = queryArray[queryid.first][queryid.second];
+ }
+ }
+ return err;
}
protected:
std::shared_ptr<C2ComponentInterface> mIntf;
+ std::shared_ptr<MultiAccessUnitInterface> mMultiAccessUnitIntf;
};
} // unnamed namespace
@@ -85,10 +174,16 @@
// ComponentInterface
ComponentInterface::ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<ParameterCache>& cache):ComponentInterface(intf, nullptr, cache) {
+}
+
+ComponentInterface::ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<MultiAccessUnitInterface>& multiAccessUnitIntf,
const std::shared_ptr<ParameterCache>& cache)
: mInterface{intf},
mConfigurable{SharedRefBase::make<CachedConfigurable>(
- std::make_unique<CompIntf>(intf))} {
+ std::make_unique<CompIntf>(intf, multiAccessUnitIntf))} {
mInit = mConfigurable->init(cache);
}
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index f0a1490..b95c09e 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -199,6 +199,36 @@
}
#endif
+std::shared_ptr<MultiAccessUnitInterface> ComponentStore::tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface) {
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf = nullptr;
+ if (c2interface == nullptr) {
+ return nullptr;
+ }
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ c2_status_t err = C2_OK;
+ C2ComponentDomainSetting domain;
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ std::vector<std::shared_ptr<C2ParamDescriptor>> params;
+ bool isComponentSupportsLargeAudioFrame = false;
+ c2interface->querySupportedParams_nb(¶ms);
+ for (const auto ¶mDesc : params) {
+ if (paramDesc->name().compare(C2_PARAMKEY_OUTPUT_LARGE_FRAME) == 0) {
+ isComponentSupportsLargeAudioFrame = true;
+ break;
+ }
+ }
+ if (!isComponentSupportsLargeAudioFrame) {
+ multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
+ c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ }
+ }
+ }
+ return multiAccessUnitIntf;
+}
+
// Methods from ::aidl::android::hardware::media::c2::IComponentStore
ScopedAStatus ComponentStore::createComponent(
const std::string& name,
@@ -206,6 +236,15 @@
const std::shared_ptr<IClientManager>& pool,
std::shared_ptr<IComponent> *component) {
+ if (!listener) {
+ ALOGE("createComponent(): listener is null");
+ return ScopedAStatus::fromServiceSpecificError(Status::BAD_VALUE);
+ }
+ if (!pool) {
+ ALOGE("createComponent(): pool is null");
+ return ScopedAStatus::fromServiceSpecificError(Status::BAD_VALUE);
+ }
+
std::shared_ptr<C2Component> c2component;
c2_status_t status =
mStore->createComponent(name, &c2component);
@@ -218,7 +257,8 @@
std::shared_ptr<Component> comp =
SharedRefBase::make<Component>(c2component, listener, ref<ComponentStore>(), pool);
*component = comp;
- if (!component) {
+ if (!component || !comp) {
+ ALOGE("createComponent(): component cannot be returned");
status = C2_CORRUPTED;
} else {
reportComponentBirth(comp.get());
@@ -248,7 +288,10 @@
c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
#endif
onInterfaceLoaded(c2interface);
- *intf = SharedRefBase::make<ComponentInterface>(c2interface, mParameterCache);
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf =
+ tryCreateMultiAccessUnitInterface(c2interface);
+ *intf = SharedRefBase::make<ComponentInterface>(
+ c2interface, multiAccessUnitIntf, mParameterCache);
return ScopedAStatus::ok();
}
return ScopedAStatus::fromServiceSpecificError(res);
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Component.h b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
index 94b760f..9725bcf 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/Component.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
@@ -31,6 +31,8 @@
#include <aidl/android/hardware/media/c2/IInputSurface.h>
#include <aidl/android/hardware/media/c2/IInputSurfaceConnection.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Component.h>
#include <C2Buffer.h>
#include <C2.h>
@@ -46,6 +48,8 @@
namespace c2 {
namespace utils {
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
struct ComponentStore;
@@ -85,6 +89,8 @@
std::shared_ptr<C2Component> mComponent;
std::shared_ptr<ComponentInterface> mInterface;
std::shared_ptr<IComponentListener> mListener;
+ std::shared_ptr<MultiAccessUnitInterface> mMultiAccessUnitIntf;
+ std::shared_ptr<MultiAccessUnitHelper> mMultiAccessUnitHelper;
std::shared_ptr<ComponentStore> mStore;
DefaultBufferPoolSender mBufferPoolSender;
@@ -102,6 +108,8 @@
struct Listener;
+ friend struct MultiAccessUnitListener;
+
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
static void OnBinderDied(void *cookie);
static void OnBinderUnlinked(void *cookie);
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
index 7723bee..bd19cd6 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
@@ -22,11 +22,14 @@
#include <aidl/android/hardware/media/c2/BnComponentInterface.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Component.h>
#include <C2Buffer.h>
#include <C2.h>
#include <memory>
+#include <set>
namespace aidl {
namespace android {
@@ -35,12 +38,16 @@
namespace c2 {
namespace utils {
-struct ComponentStore;
+using ::android::MultiAccessUnitInterface;
struct ComponentInterface : public BnComponentInterface {
ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& interface,
const std::shared_ptr<ParameterCache>& cache);
+ ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& interface,
+ const std::shared_ptr<MultiAccessUnitInterface>& largeBufferIntf,
+ const std::shared_ptr<ParameterCache>& cache);
c2_status_t status() const;
::ndk::ScopedAStatus getConfigurable(
std::shared_ptr<IConfigurable> *intf) override;
@@ -51,7 +58,6 @@
c2_status_t mInit;
};
-
} // namespace utils
} // namespace c2
} // namespace media
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index 0698b0f..746e1bf 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -75,6 +75,9 @@
static std::shared_ptr<::android::FilterWrapper> GetFilterWrapper();
+ std::shared_ptr<MultiAccessUnitInterface> tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface);
+
// Methods from ::aidl::android::hardware::media::c2::IComponentStore.
virtual ::ndk::ScopedAStatus createComponent(
const std::string& name,
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 85b5ec8..b3ae514 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -649,7 +649,7 @@
return C2_CORRUPTED;
}
size_t i = 0;
- size_t numUpdatedStackParams = 0;
+ size_t numQueried = 0;
for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
C2Param* paramPointer = *it;
if (numStackIndices > 0) {
@@ -678,7 +678,7 @@
continue;
}
if (stackParams[i++]->updateFrom(*paramPointer)) {
- ++numUpdatedStackParams;
+ ++numQueried;
} else {
LOG(WARNING) << "query -- param update failed: "
"index = "
@@ -695,14 +695,11 @@
"unexpected extra stack param.";
} else {
heapParams->emplace_back(C2Param::Copy(*paramPointer));
+ ++numQueried;
}
}
++it;
}
- size_t numQueried = numUpdatedStackParams;
- if (heapParams) {
- numQueried += heapParams->size();
- }
if (status == C2_OK && indices.size() != numQueried) {
status = C2_BAD_INDEX;
}
@@ -2072,6 +2069,8 @@
id = id == C2PlatformAllocatorStore::BUFFERQUEUE ?
C2PlatformAllocatorStore::IGBA : id;
+ c2_aidl::IComponent::BlockPoolAllocator allocator;
+ allocator.allocatorId = id;
if (id == C2PlatformAllocatorStore::IGBA) {
std::shared_ptr<AidlGraphicBufferAllocator> gba =
mGraphicBufferAllocators->create();
@@ -2081,12 +2080,11 @@
if (status != C2_OK) {
return status;
}
- c2_aidl::IComponent::BlockPoolAllocator allocator;
- allocator.set<c2_aidl::IComponent::BlockPoolAllocator::allocator>();
- allocator.get<c2_aidl::IComponent::BlockPoolAllocator::allocator>().igba =
+ c2_aidl::IComponent::GbAllocator gbAllocator;
+ gbAllocator.waitableFd = std::move(waitableFd);
+ gbAllocator.igba =
c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
- allocator.get<c2_aidl::IComponent::BlockPoolAllocator::allocator>().waitableFd =
- std::move(waitableFd);
+ allocator.gbAllocator = std::move(gbAllocator);
::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
allocator, &aidlBlockPool);
status = GetC2Status(transStatus, "createBlockPool");
@@ -2096,7 +2094,7 @@
mGraphicBufferAllocators->setCurrentId(aidlBlockPool.blockPoolId);
} else {
::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
- static_cast<int32_t>(id), &aidlBlockPool);
+ allocator, &aidlBlockPool);
status = GetC2Status(transStatus, "createBlockPool");
if (status != C2_OK) {
return status;
diff --git a/media/codec2/hal/common/Android.bp b/media/codec2/hal/common/Android.bp
index 2aedd8b..7d7b285 100644
--- a/media/codec2/hal/common/Android.bp
+++ b/media/codec2/hal/common/Android.bp
@@ -11,6 +11,7 @@
srcs: [
"BufferTypes.cpp",
+ "MultiAccessUnitHelper.cpp",
],
export_include_dirs: ["include/"],
@@ -26,7 +27,10 @@
"libcodec2_vndk",
"liblog",
"libstagefright_foundation",
+ "server_configurable_flags",
],
+
+ static_libs: ["aconfig_mediacodec_flags_c_lib"],
}
cc_library_static {
diff --git a/media/codec2/hal/common/HalSelection.cpp b/media/codec2/hal/common/HalSelection.cpp
index 761a409..d3ea181 100644
--- a/media/codec2/hal/common/HalSelection.cpp
+++ b/media/codec2/hal/common/HalSelection.cpp
@@ -28,7 +28,12 @@
namespace android {
bool IsCodec2AidlHalSelected() {
- if (!com::android::media::codec::flags::provider_->aidl_hal()) {
+ // For new devices with vendor software targeting 202404, we always want to
+ // use AIDL if it exists
+ constexpr int kAndroidApi202404 = 202404;
+ int vendorVersion = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+ if (!com::android::media::codec::flags::provider_->aidl_hal() &&
+ vendorVersion < kAndroidApi202404) {
// Cannot select AIDL if not enabled
return false;
}
diff --git a/media/codec2/hal/common/MultiAccessUnitHelper.cpp b/media/codec2/hal/common/MultiAccessUnitHelper.cpp
new file mode 100644
index 0000000..03a76e9
--- /dev/null
+++ b/media/codec2/hal/common/MultiAccessUnitHelper.cpp
@@ -0,0 +1,740 @@
+/*
+ * Copyright 2023 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 "Codec2-MultiAccessUnitHelper"
+#include <android-base/logging.h>
+
+#include <com_android_media_codec_flags.h>
+
+#include <codec2/common/MultiAccessUnitHelper.h>
+#include <android-base/properties.h>
+
+#include <C2BufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+namespace android {
+
+static C2R MultiAccessUnitParamsSetter(
+ bool mayBlock, C2InterfaceHelper::C2P<C2LargeFrame::output> &me) {
+ (void)mayBlock;
+ C2R res = C2R::Ok();
+ if (!me.F(me.v.maxSize).supportsAtAll(me.v.maxSize)) {
+ res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.maxSize)));
+ } else if (!me.F(me.v.thresholdSize).supportsAtAll(me.v.thresholdSize)) {
+ res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.thresholdSize)));
+ } else if (me.v.maxSize < me.v.thresholdSize) {
+ me.set().maxSize = me.v.thresholdSize;
+ } else if (me.v.thresholdSize == 0 && me.v.maxSize > 0) {
+ me.set().thresholdSize = me.v.maxSize;
+ }
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ res.retrieveFailures(&failures);
+ if (!failures.empty()) {
+ me.set().maxSize = 0;
+ me.set().thresholdSize = 0;
+ }
+ return res;
+}
+
+MultiAccessUnitInterface::MultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface>& interface,
+ std::shared_ptr<C2ReflectorHelper> helper)
+ : C2InterfaceHelper(helper), mC2ComponentIntf(interface) {
+ setDerivedInstance(this);
+ addParameter(
+ DefineParam(mLargeFrameParams, C2_PARAMKEY_OUTPUT_LARGE_FRAME)
+ .withDefault(new C2LargeFrame::output(0u, 0, 0))
+ .withFields({
+ C2F(mLargeFrameParams, maxSize).inRange(
+ 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u)),
+ C2F(mLargeFrameParams, thresholdSize).inRange(
+ 0, c2_min(UINT_MAX, 10 * 512000 * 8 * 2u))
+ })
+ .withSetter(MultiAccessUnitParamsSetter)
+ .build());
+ std::vector<std::shared_ptr<C2ParamDescriptor>> supportedParams;
+ querySupportedParams(&supportedParams);
+ // Adding to set to do intf seperation in query/config
+ for (std::shared_ptr<C2ParamDescriptor> &desc : supportedParams) {
+ mSupportedParamIndexSet.insert(desc->index());
+ }
+ mParamFields.emplace_back(mLargeFrameParams.get(), &(mLargeFrameParams.get()->maxSize));
+ mParamFields.emplace_back(mLargeFrameParams.get(), &(mLargeFrameParams.get()->thresholdSize));
+
+ if (mC2ComponentIntf) {
+ c2_status_t err = mC2ComponentIntf->query_vb({&mKind}, {}, C2_MAY_BLOCK, nullptr);
+ }
+}
+
+bool MultiAccessUnitInterface::isValidField(const C2ParamField &field) const {
+ return (std::find(mParamFields.begin(), mParamFields.end(), field) != mParamFields.end());
+}
+bool MultiAccessUnitInterface::isParamSupported(C2Param::Index index) {
+ return (mSupportedParamIndexSet.count(index) != 0);
+}
+
+C2LargeFrame::output MultiAccessUnitInterface::getLargeFrameParam() const {
+ return *mLargeFrameParams;
+}
+
+C2Component::kind_t MultiAccessUnitInterface::kind() const {
+ return (C2Component::kind_t)(mKind.value);
+}
+
+bool MultiAccessUnitInterface::getDecoderSampleRateAndChannelCount(
+ uint32_t * const sampleRate_, uint32_t * const channelCount_) const {
+ if (sampleRate_ == nullptr || sampleRate_ == nullptr) {
+ return false;
+ }
+ if (mC2ComponentIntf) {
+ C2StreamSampleRateInfo::output sampleRate;
+ C2StreamChannelCountInfo::output channelCount;
+ c2_status_t res = mC2ComponentIntf->query_vb(
+ {&sampleRate, &channelCount}, {}, C2_MAY_BLOCK, nullptr);
+ if (res == C2_OK && sampleRate.value > 0 && channelCount.value > 0) {
+ *sampleRate_ = sampleRate.value;
+ *channelCount_ = channelCount.value;
+ return true;
+ }
+ }
+ return false;
+}
+
+//C2MultiAccessUnitBuffer
+class C2MultiAccessUnitBuffer : public C2Buffer {
+ public:
+ explicit C2MultiAccessUnitBuffer(
+ const std::vector<C2ConstLinearBlock> &blocks):
+ C2Buffer(blocks) {
+ }
+};
+
+//MultiAccessUnitHelper
+MultiAccessUnitHelper::MultiAccessUnitHelper(
+ const std::shared_ptr<MultiAccessUnitInterface>& intf):
+ mInit(false),
+ mInterface(intf) {
+ std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore();
+ if(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator) == C2_OK) {
+ mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, ++mBlockPoolId);
+ mInit = true;
+ }
+}
+
+MultiAccessUnitHelper::~MultiAccessUnitHelper() {
+ std::unique_lock<std::mutex> l(mLock);
+ mFrameHolder.clear();
+}
+
+bool MultiAccessUnitHelper::isEnabledOnPlatform() {
+ bool result = com::android::media::codec::flags::provider_->large_audio_frame();
+ if (!result) {
+ return false;
+ }
+ //TODO: remove this before launch
+ result = ::android::base::GetBoolProperty("debug.media.c2.large.audio.frame", true);
+ LOG(DEBUG) << "MultiAccessUnitHelper " << (result ? "enabled" : "disabled");
+ return result;
+}
+
+std::shared_ptr<MultiAccessUnitInterface> MultiAccessUnitHelper::getInterface() {
+ return mInterface;
+}
+
+bool MultiAccessUnitHelper::getStatus() {
+ return mInit;
+}
+
+void MultiAccessUnitHelper::reset() {
+ std::lock_guard<std::mutex> l(mLock);
+ mFrameHolder.clear();
+}
+
+c2_status_t MultiAccessUnitHelper::error(
+ std::list<std::unique_ptr<C2Work>> * const worklist) {
+ if (worklist == nullptr) {
+ LOG(ERROR) << "Provided null worklist for error()";
+ return C2_OK;
+ }
+ std::unique_lock<std::mutex> l(mLock);
+ for (auto frame = mFrameHolder.begin(); frame != mFrameHolder.end(); frame++) {
+ if (frame->mLargeWork) {
+ finalizeWork(*frame, 0, true);
+ worklist->push_back(std::move(frame->mLargeWork));
+ frame->reset();
+ }
+ }
+ mFrameHolder.clear();
+ return C2_OK;
+}
+
+c2_status_t MultiAccessUnitHelper::flush(
+ std::list<std::unique_ptr<C2Work>>* const c2flushedWorks) {
+ c2_status_t c2res = C2_OK;
+ std::lock_guard<std::mutex> l(mLock);
+ for (auto iterWork = c2flushedWorks->begin() ; iterWork != c2flushedWorks->end(); ) {
+ bool foundFlushedFrame = false;
+ std::list<MultiAccessUnitInfo>::iterator frame =
+ mFrameHolder.begin();
+ while (frame != mFrameHolder.end() && !foundFlushedFrame) {
+ auto it = frame->mComponentFrameIds.find(
+ (*iterWork)->input.ordinal.frameIndex.peekull());
+ if (it != frame->mComponentFrameIds.end()) {
+ LOG(DEBUG) << "Multi access-unit flush "
+ << (*iterWork)->input.ordinal.frameIndex.peekull()
+ << " with " << frame->inOrdinal.frameIndex.peekull();
+ (*iterWork)->input.ordinal.frameIndex = frame->inOrdinal.frameIndex;
+ frame = mFrameHolder.erase(frame);
+ foundFlushedFrame = true;
+ } else {
+ ++frame;
+ }
+ }
+ if (!foundFlushedFrame) {
+ iterWork = c2flushedWorks->erase(iterWork);
+ } else {
+ ++iterWork;
+ }
+ }
+ return c2res;
+}
+
+c2_status_t MultiAccessUnitHelper::scatter(
+ std::list<std::unique_ptr<C2Work>> &largeWork,
+ std::list<std::list<std::unique_ptr<C2Work>>>* const processedWork) {
+ LOG(DEBUG) << "Multiple access-unit: scatter";
+ if (processedWork == nullptr) {
+ LOG(ERROR) << "MultiAccessUnitHelper provided with no work list";
+ return C2_CORRUPTED;
+ }
+ for (std::unique_ptr<C2Work>& w : largeWork) {
+ std::list<std::unique_ptr<C2Work>> sliceWork;
+ C2WorkOrdinalStruct inputOrdinal = w->input.ordinal;
+ // To hold correspondence and processing bits b/w input and output
+ MultiAccessUnitInfo frameInfo(inputOrdinal);
+ std::set<uint64_t>& frameSet = frameInfo.mComponentFrameIds;
+ uint64_t newFrameIdx = mFrameIndex++;
+ // TODO: Do not split buffers if component inherantly supports MultipleFrames.
+ // if thats case, only replace frameindex.
+ auto cloneInputWork = [&newFrameIdx](std::unique_ptr<C2Work>& inWork, uint32_t flags) {
+ std::unique_ptr<C2Work> newWork(new C2Work);
+ newWork->input.flags = (C2FrameData::flags_t)flags;
+ newWork->input.ordinal = inWork->input.ordinal;
+ newWork->input.ordinal.frameIndex = newFrameIdx;
+ if (!inWork->input.configUpdate.empty()) {
+ for (std::unique_ptr<C2Param>& param : inWork->input.configUpdate) {
+ newWork->input.configUpdate.push_back(
+ std::move(C2Param::Copy(*(param.get()))));
+ }
+ }
+ newWork->input.infoBuffers = (inWork->input.infoBuffers);
+ if (!inWork->worklets.empty() && inWork->worklets.front() != nullptr) {
+ newWork->worklets.emplace_back(new C2Worklet);
+ newWork->worklets.front()->component = inWork->worklets.front()->component;
+ std::vector<std::unique_ptr<C2Tuning>> tunings;
+ for (std::unique_ptr<C2Tuning>& tuning : inWork->worklets.front()->tunings) {
+ tunings.push_back(std::move(
+ std::unique_ptr<C2Tuning>(
+ static_cast<C2Tuning*>(
+ C2Param::Copy(*(tuning.get())).release()))));
+ }
+ newWork->worklets.front()->tunings = std::move(tunings);
+ }
+ return newWork;
+ };
+ if (w->input.buffers.empty()
+ || (w->input.buffers.front() == nullptr)
+ || (!w->input.buffers.front()->hasInfo(
+ C2AccessUnitInfos::input::PARAM_TYPE))) {
+ LOG(DEBUG) << "Empty or MultiAU info buffer scatter frames with frameIndex "
+ << inputOrdinal.frameIndex.peekull()
+ << ") -> newFrameIndex " << newFrameIdx
+ <<" : input ts " << inputOrdinal.timestamp.peekull();
+ sliceWork.push_back(std::move(cloneInputWork(w, w->input.flags)));
+ if (!w->input.buffers.empty() && w->input.buffers.front() != nullptr) {
+ sliceWork.back()->input.buffers = std::move(w->input.buffers);
+ }
+ frameSet.insert(newFrameIdx);
+ processedWork->push_back(std::move(sliceWork));
+ } else {
+ const std::vector<std::shared_ptr<C2Buffer>>& inBuffers = w->input.buffers;
+ if (inBuffers.front()->data().linearBlocks().size() == 0) {
+ LOG(ERROR) << "ERROR: Work has Large frame info but has no linear blocks.";
+ return C2_CORRUPTED;
+ }
+ const std::vector<C2ConstLinearBlock>& multiAU =
+ inBuffers.front()->data().linearBlocks();
+ std::shared_ptr<const C2AccessUnitInfos::input> auInfo =
+ std::static_pointer_cast<const C2AccessUnitInfos::input>(
+ w->input.buffers.front()->getInfo(C2AccessUnitInfos::input::PARAM_TYPE));
+ uint32_t offset = 0; uint32_t multiAUSize = multiAU.front().size();
+ bool sendEos = false;
+ for (int idx = 0; idx < auInfo->flexCount(); ++idx) {
+ std::vector<C2ConstLinearBlock> au;
+ const C2AccessUnitInfosStruct &info = auInfo->m.values[idx];
+ sendEos |= (info.flags & C2FrameData::FLAG_END_OF_STREAM);
+ std::unique_ptr<C2Work> newWork = cloneInputWork(w, info.flags);
+ frameSet.insert(newFrameIdx);
+ newFrameIdx = mFrameIndex++;
+ newWork->input.ordinal.timestamp = info.timestamp;
+ au.push_back(multiAU.front().subBlock(offset, info.size));
+ if ((offset + info.size) > multiAUSize) {
+ LOG(ERROR) << "ERROR: access-unit offset > buffer size"
+ << " current offset " << (offset + info.size)
+ << " buffer size " << multiAUSize;
+ return C2_CORRUPTED;
+ }
+ newWork->input.buffers.push_back(
+ std::shared_ptr<C2Buffer>(new C2MultiAccessUnitBuffer(au)));
+ LOG(DEBUG) << "Frame scatter queuing frames WITH info in ordinal "
+ << inputOrdinal.frameIndex.peekull()
+ << " info.size " << info.size
+ << " : TS " << newWork->input.ordinal.timestamp.peekull()
+ << " with index " << newFrameIdx - 1;
+ // add to worklist
+ sliceWork.push_back(std::move(newWork));
+ processedWork->push_back(std::move(sliceWork));
+ offset += info.size;
+ }
+ mFrameIndex--;
+ if (!sendEos && (w->input.flags & C2FrameData::FLAG_END_OF_STREAM)) {
+ if (!processedWork->empty()) {
+ std::list<std::unique_ptr<C2Work>> &sliceWork = processedWork->back();
+ if (!sliceWork.empty()) {
+ std::unique_ptr<C2Work> &work = sliceWork.back();
+ if (work) {
+ work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+ }
+ }
+ }
+ }
+ }
+ if (!processedWork->empty()) {
+ C2LargeFrame::output multiAccessParams = mInterface->getLargeFrameParam();
+ frameInfo.mLargeFrameTuning = multiAccessParams;
+ std::lock_guard<std::mutex> l(mLock);
+ mFrameHolder.push_back(std::move(frameInfo));
+ }
+ }
+ return C2_OK;
+}
+
+c2_status_t MultiAccessUnitHelper::gather(
+ std::list<std::unique_ptr<C2Work>> &c2workItems,
+ std::list<std::unique_ptr<C2Work>>* const processedWork) {
+ LOG(DEBUG) << "Multi access-unit gather process";
+ if (processedWork == nullptr) {
+ LOG(ERROR) << "Nothing provided for processed work";
+ return C2_CORRUPTED;
+ }
+ auto addOutWork = [&processedWork](std::unique_ptr<C2Work>& work) {
+ processedWork->push_back(std::move(work));
+ };
+ {
+ std::lock_guard<std::mutex> l(mLock);
+ for (auto& work : c2workItems) {
+ LOG(DEBUG) << "FrameHolder Size: " << mFrameHolder.size();
+ uint64_t thisFrameIndex = work->input.ordinal.frameIndex.peekull();
+ bool removeEntry = work->worklets.empty()
+ || !work->worklets.front()
+ || (work->worklets.front()->output.flags
+ & C2FrameData::FLAG_INCOMPLETE) == 0;
+ bool foundFrame = false;
+ std::list<MultiAccessUnitInfo>::iterator frame =
+ mFrameHolder.begin();
+ while (!foundFrame && frame != mFrameHolder.end()) {
+ auto it = frame->mComponentFrameIds.find(thisFrameIndex);
+ if (it != frame->mComponentFrameIds.end()) {
+ foundFrame = true;
+ LOG(DEBUG) << "onWorkDone (frameIndex " << thisFrameIndex
+ << " worklstsSze " << work->worklets.size()
+ << ") -> frameIndex " << frame->inOrdinal.frameIndex.peekull();
+ if (work->result != C2_OK
+ || work->worklets.empty()
+ || !work->worklets.front()
+ || (frame->mLargeFrameTuning.thresholdSize == 0
+ || frame->mLargeFrameTuning.maxSize == 0)) {
+ if (removeEntry) {
+ frame->mComponentFrameIds.erase(it);
+ removeEntry = false;
+ }
+ if (frame->mLargeWork) {
+ finalizeWork(*frame);
+ addOutWork(frame->mLargeWork);
+ frame->reset();
+ }
+ c2_status_t workResult = work->result;
+ frame->mLargeWork = std::move(work);
+ frame->mLargeWork->input.ordinal.frameIndex =
+ frame->inOrdinal.frameIndex;
+ finalizeWork(*frame);
+ addOutWork(frame->mLargeWork);
+ frame->reset();
+ if (workResult != C2_OK) {
+ frame->mAccessUnitInfos.clear();
+ }
+ } else if (C2_OK != processWorklets(*frame, work, addOutWork)) {
+ LOG(DEBUG) << "Error while processing work";
+ }
+ if (removeEntry) {
+ LOG(DEBUG) << "Removing entry: " << thisFrameIndex
+ << " -> " << frame->inOrdinal.frameIndex.peekull();
+ frame->mComponentFrameIds.erase(it);
+ }
+ // This is to take care of the last bytes and to decide to send with
+ // FLAG_INCOMPLETE or not.
+ if ((frame->mWview
+ && (frame->mWview->offset() > frame->mLargeFrameTuning.thresholdSize))
+ || frame->mComponentFrameIds.empty()) {
+ if (frame->mLargeWork) {
+ finalizeWork(*frame);
+ addOutWork(frame->mLargeWork);
+ frame->reset();
+ }
+ }
+ if (frame->mComponentFrameIds.empty()) {
+ LOG(DEBUG) << "This frame is finished ID " << thisFrameIndex;
+ frame = mFrameHolder.erase(frame);
+ continue;
+ }
+ } else {
+ LOG(DEBUG) << "Received an out-of-order output " << thisFrameIndex
+ << " expected: " <<mFrameHolder.front().inOrdinal.frameIndex.peekull();
+ }
+ frame++;
+ }
+ if (!foundFrame) {
+ LOG(ERROR) <<" Error: Frame Holder reports no frame " << thisFrameIndex;
+ }
+ }
+ }
+ return C2_OK;
+}
+
+c2_status_t MultiAccessUnitHelper::createLinearBlock(MultiAccessUnitInfo &frame) {
+ if (!mInit) {
+ LOG(ERROR) << "Large buffer allocator failed";
+ return C2_NO_MEMORY;
+ }
+ C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ uint32_t maxOutSize = frame.mLargeFrameTuning.maxSize;
+ c2_status_t err = mLinearPool->fetchLinearBlock(maxOutSize, usage, &frame.mBlock);
+ LOG(DEBUG) << "Allocated block with offset : " << frame.mBlock->offset()
+ << " size " << frame.mBlock->size() << " Capacity " << frame.mBlock->capacity();
+ if (err != C2_OK) {
+ LOG(ERROR) << "Error allocating Multi access-unit Buffer";
+ return err;
+ }
+ frame.mWview = std::make_shared<C2WriteView>(frame.mBlock->map().get());
+ LOG(DEBUG) << "Allocated buffer : requested size : " <<
+ frame.mLargeFrameTuning.maxSize
+ << " alloc size " << frame.mWview->size();
+ return C2_OK;
+}
+
+/*
+ * For every work from the component, we try to do aggregation of work here.
+*/
+c2_status_t MultiAccessUnitHelper::processWorklets(MultiAccessUnitInfo &frame,
+ std::unique_ptr<C2Work>& work,
+ const std::function <void(std::unique_ptr<C2Work>&)>& addWork) {
+ // This will allocate work, worklet, c2Block
+ auto allocateWork = [&](MultiAccessUnitInfo &frame,
+ bool allocateWorket = false,
+ bool allocateBuffer = false) {
+ c2_status_t ret = C2_OK;
+ if (frame.mLargeWork == nullptr) {
+ frame.mLargeWork.reset(new C2Work);
+ frame.mLargeWork->input.ordinal = frame.inOrdinal;
+ frame.mLargeWork->input.ordinal.frameIndex = frame.inOrdinal.frameIndex;
+ }
+ if (allocateWorket) {
+ if (frame.mLargeWork->worklets.size() == 0) {
+ frame.mLargeWork->worklets.emplace_back(new C2Worklet);
+ }
+ }
+ if (allocateBuffer) {
+ if (frame.mWview == nullptr) {
+ ret = createLinearBlock(frame);
+ }
+ }
+ return ret;
+ };
+ // we will only have one worklet.
+ bool foundEndOfStream = false;
+ for (auto worklet = work->worklets.begin();
+ worklet != work->worklets.end() && (*worklet) != nullptr; ++worklet) {
+ uint32_t flagsForNoCopy = C2FrameData::FLAG_DROP_FRAME
+ | C2FrameData::FLAG_DISCARD_FRAME
+ | C2FrameData::FLAG_CORRUPT;
+ if ((*worklet)->output.flags & flagsForNoCopy) {
+ if (frame.mLargeWork) {
+ finalizeWork(frame);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ }
+ frame.mLargeWork = std::move(work);
+ frame.mLargeWork->input.ordinal.frameIndex = frame.inOrdinal.frameIndex;
+ finalizeWork(frame, (*worklet)->output.flags, true);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ return C2_OK;
+ }
+ int64_t sampleTimeUs = 0;
+ uint32_t frameSize = 0;
+ uint32_t sampleRate = 0;
+ uint32_t channelCount = 0;
+ if (mInterface->getDecoderSampleRateAndChannelCount(&sampleRate, &channelCount)) {
+ sampleTimeUs = (1000000u) / (sampleRate * channelCount * 2);
+ frameSize = channelCount * 2;
+ if (mInterface->kind() == C2Component::KIND_DECODER) {
+ frame.mLargeFrameTuning.maxSize =
+ (frame.mLargeFrameTuning.maxSize / frameSize) * frameSize;
+ frame.mLargeFrameTuning.thresholdSize =
+ (frame.mLargeFrameTuning.thresholdSize / frameSize) * frameSize;
+ }
+ }
+ c2_status_t c2ret = allocateWork(frame, true);
+ if (c2ret != C2_OK) {
+ return c2ret;
+ }
+ C2FrameData& outputFramedata = frame.mLargeWork->worklets.front()->output;
+ if (!(*worklet)->output.configUpdate.empty()) {
+ for (auto& configUpdate : (*worklet)->output.configUpdate) {
+ outputFramedata.configUpdate.push_back(std::move(configUpdate));
+ }
+ (*worklet)->output.configUpdate.clear();
+ }
+ outputFramedata.infoBuffers.insert(outputFramedata.infoBuffers.begin(),
+ (*worklet)->output.infoBuffers.begin(),
+ (*worklet)->output.infoBuffers.end());
+
+ LOG(DEBUG) << "maxOutSize " << frame.mLargeFrameTuning.maxSize
+ << " threshold " << frame.mLargeFrameTuning.thresholdSize;
+ if ((*worklet)->output.buffers.size() > 0) {
+ allocateWork(frame, true, true);
+ }
+ LOG(DEBUG) << "This worklet has " << (*worklet)->output.buffers.size() << " buffers"
+ << " ts: " << (*worklet)->output.ordinal.timestamp.peekull();
+ int64_t workletTimestamp = (*worklet)->output.ordinal.timestamp.peekull();
+ int64_t timestamp = workletTimestamp;
+ uint32_t flagsForCopy = ((*worklet)->output.flags) & C2FrameData::FLAG_CODEC_CONFIG;
+ for (int bufIdx = 0; bufIdx < (*worklet)->output.buffers.size(); ++bufIdx) {
+ std::shared_ptr<C2Buffer>& buffer = (*worklet)->output.buffers[bufIdx];
+ if (!buffer || buffer->data().linearBlocks().empty()) {
+ continue;
+ }
+ const std::vector<C2ConstLinearBlock>& blocks = buffer->data().linearBlocks();
+ if (blocks.size() > 0) {
+ uint32_t inputOffset = 0;
+ uint32_t inputSize = blocks.front().size();
+ frame.mInfos.insert(frame.mInfos.end(),
+ buffer->info().begin(), buffer->info().end());
+ if (frameSize != 0 && (mInterface->kind() == C2Component::KIND_DECODER)) {
+ // For decoders we only split multiples of 16bChannelCount*2
+ inputSize -= (inputSize % frameSize);
+ }
+ while (inputOffset < inputSize) {
+ if (frame.mWview->offset() >= frame.mLargeFrameTuning.thresholdSize) {
+ frame.mLargeWork->result = C2_OK;
+ finalizeWork(frame, flagsForCopy);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ allocateWork(frame, true, true);
+ }
+ if (mInterface->kind() == C2Component::KIND_ENCODER) {
+ if (inputSize > frame.mLargeFrameTuning.maxSize) {
+ LOG(ERROR) << "Enc: Output buffer too small for AU, configured with "
+ << frame.mLargeFrameTuning.maxSize
+ << " block size: " << blocks.front().size()
+ << "alloc size " << frame.mWview->size();
+ if (frame.mLargeWork
+ && frame.mWview && frame.mWview->offset() > 0) {
+ finalizeWork(frame, flagsForCopy);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ allocateWork(frame, true, false);
+ }
+ frame.mLargeWork->result = C2_NO_MEMORY;
+ finalizeWork(frame, 0, true);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ return C2_NO_MEMORY;
+ } else if (inputSize > frame.mWview->size()) {
+ LOG(DEBUG) << "Enc: Large frame hitting bufer limit, current size "
+ << frame.mWview->offset();
+ if (frame.mLargeWork
+ && frame.mWview && frame.mWview->offset() > 0) {
+ finalizeWork(frame, flagsForCopy);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ allocateWork(frame, true, true);
+ }
+ }
+ }
+ C2ReadView rView = blocks.front().map().get();
+ if (rView.error()) {
+ LOG(ERROR) << "Buffer read view error";
+ frame.mLargeWork->result = rView.error();
+ frame.mLargeWork->worklets.clear();
+ finalizeWork(frame, 0, true);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ return C2_NO_MEMORY;
+ }
+ uint32_t toCopy = 0;
+ if (mInterface->kind() == C2Component::KIND_ENCODER) {
+ toCopy = inputSize;
+ } else {
+ toCopy = c2_min(frame.mWview->size(), (inputSize - inputOffset));
+ timestamp = workletTimestamp + inputOffset * sampleTimeUs;
+ LOG(DEBUG) << "ts " << timestamp
+ << " copiedOutput " << inputOffset
+ << " sampleTimeUs " << sampleTimeUs;
+ }
+ LOG(DEBUG) << " Copy size " << toCopy
+ << " ts " << timestamp;
+ memcpy(frame.mWview->data(), rView.data() + inputOffset, toCopy);
+ frame.mWview->setOffset(frame.mWview->offset() + toCopy);
+ inputOffset += toCopy;
+ mergeAccessUnitInfo(frame, flagsForCopy, toCopy, timestamp);
+ }
+ } else {
+ frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(buffer));
+ LOG(DEBUG) << "Copying worklets without linear buffer";
+ }
+ }
+ uint32_t flagsForCsdOrEnd = (*worklet)->output.flags
+ & (C2FrameData::FLAG_END_OF_STREAM | C2FrameData::FLAG_CODEC_CONFIG);
+ if (flagsForCsdOrEnd) {
+ LOG(DEBUG) << "Output worklet has CSD/EOS data";
+ frame.mLargeWork->result = C2_OK;
+ // we can assign timestamp as this will be evaluated in finalizeWork
+ frame.mLargeWork->worklets.front()->output.ordinal.timestamp = timestamp;
+ finalizeWork(frame, flagsForCsdOrEnd, true);
+ addWork(frame.mLargeWork);
+ frame.reset();
+ }
+ }
+ return C2_OK;
+}
+
+c2_status_t MultiAccessUnitHelper::finalizeWork(
+ MultiAccessUnitInfo& frame, uint32_t inFlags, bool forceComplete) {
+ if (frame.mLargeWork == nullptr) {
+ return C2_OK;
+ }
+ //prepare input ordinal
+ frame.mLargeWork->input.ordinal = frame.inOrdinal;
+ // remove this
+ int64_t timeStampUs = frame.inOrdinal.timestamp.peekull();
+ if (!frame.mAccessUnitInfos.empty()) {
+ timeStampUs = frame.mAccessUnitInfos.front().timestamp;
+ } else if (!frame.mLargeWork->worklets.empty()) {
+ std::unique_ptr<C2Worklet> &worklet = frame.mLargeWork->worklets.front();
+ if (worklet) {
+ timeStampUs = worklet->output.ordinal.timestamp.peekull();
+ }
+ }
+ LOG(DEBUG) << "Finalizing work with input Idx "
+ << frame.mLargeWork->input.ordinal.frameIndex.peekull()
+ << " timestamp " << timeStampUs;
+ uint32_t finalFlags = 0;
+ if ((!forceComplete)
+ && (frame.mLargeWork->result == C2_OK)
+ && (!frame.mComponentFrameIds.empty())) {
+ finalFlags |= C2FrameData::FLAG_INCOMPLETE;
+ }
+ if (frame.mLargeWork->result == C2_OK) {
+ finalFlags |= inFlags;
+ }
+ // update worklet if present
+ if (!frame.mLargeWork->worklets.empty() &&
+ frame.mLargeWork->worklets.front() != nullptr) {
+ frame.mLargeWork->workletsProcessed = 1;
+ C2FrameData& outFrameData = frame.mLargeWork->worklets.front()->output;
+ outFrameData.ordinal.frameIndex = frame.inOrdinal.frameIndex.peekull();
+ outFrameData.ordinal.timestamp = timeStampUs;
+ finalFlags |= frame.mLargeWork->worklets.front()->output.flags;
+ outFrameData.flags = (C2FrameData::flags_t)finalFlags;
+ // update buffers
+ if (frame.mBlock && (frame.mWview->offset() > 0)) {
+ size_t size = frame.mWview->offset();
+ LOG(DEBUG) << "Finalize : Block: Large frame size set as " << size
+ << " timestamp as " << timeStampUs
+ << "frameIndex " << outFrameData.ordinal.frameIndex.peekull();
+ frame.mWview->setOffset(0);
+ std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateLinearBuffer(
+ frame.mBlock->share(0, size, ::C2Fence()));
+ if (frame.mAccessUnitInfos.size() > 0) {
+ if (finalFlags & C2FrameData::FLAG_END_OF_STREAM) {
+ frame.mAccessUnitInfos.back().flags |=
+ C2FrameData::FLAG_END_OF_STREAM;
+ }
+ std::shared_ptr<C2AccessUnitInfos::output> largeFrame =
+ C2AccessUnitInfos::output::AllocShared(
+ frame.mAccessUnitInfos.size(), 0u, frame.mAccessUnitInfos);
+ frame.mInfos.push_back(largeFrame);
+ frame.mAccessUnitInfos.clear();
+ }
+ for (auto &info : frame.mInfos) {
+ c2Buffer->setInfo(std::const_pointer_cast<C2Info>(info));
+ }
+ frame.mLargeWork->worklets.front()->output.buffers.push_back(std::move(c2Buffer));
+ frame.mInfos.clear();
+ frame.mBlock.reset();
+ frame.mWview.reset();
+ }
+ }
+ LOG(DEBUG) << "Multi access-unitflag setting as " << finalFlags;
+ return C2_OK;
+}
+
+void MultiAccessUnitHelper::mergeAccessUnitInfo(
+ MultiAccessUnitInfo &frame,
+ uint32_t flags_,
+ uint32_t size,
+ int64_t timestamp) {
+ // Remove flags that are not part of Access unit info
+ uint32_t flags = flags_ & ~(C2FrameData::FLAG_INCOMPLETE
+ | C2FrameData::FLAG_DISCARD_FRAME
+ | C2FrameData::FLAG_CORRUPT
+ | C2FrameData::FLAG_CORRECTED);
+ if (frame.mAccessUnitInfos.empty()) {
+ frame.mAccessUnitInfos.emplace_back(flags, size, timestamp);
+ return;
+ }
+ if ((mInterface->kind() == C2Component::KIND_DECODER) &&
+ (frame.mAccessUnitInfos.back().flags == flags)) {
+ // merge access units here
+ C2AccessUnitInfosStruct &s = frame.mAccessUnitInfos.back();
+ s.size += size; // don't have to update timestamp
+ } else {
+ frame.mAccessUnitInfos.emplace_back(flags, size, timestamp);
+ }
+}
+
+void MultiAccessUnitHelper::MultiAccessUnitInfo::reset() {
+ mBlock.reset();
+ mWview.reset();
+ mInfos.clear();
+ mAccessUnitInfos.clear();
+ mLargeWork.reset();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
new file mode 100644
index 0000000..a6d938e
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/MultiAccessUnitHelper.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_COMMON_MULTI_ACCESSUNIT_HELPER_H
+#define CODEC2_COMMON_MULTI_ACCESSUNIT_HELPER_H
+
+#include <hidl/Status.h>
+#include <hwbinder/IBinder.h>
+
+#include <C2Config.h>
+#include <util/C2InterfaceHelper.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <set>
+#include <memory>
+#include <mutex>
+
+namespace android {
+
+struct MultiAccessUnitHelper;
+
+struct MultiAccessUnitInterface : public C2InterfaceHelper {
+ explicit MultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface>& interface,
+ std::shared_ptr<C2ReflectorHelper> helper);
+
+ bool isParamSupported(C2Param::Index index);
+ C2LargeFrame::output getLargeFrameParam() const;
+ C2Component::kind_t kind() const;
+ bool isValidField(const C2ParamField &field) const;
+
+protected:
+ bool getDecoderSampleRateAndChannelCount(
+ uint32_t * const sampleRate_, uint32_t * const channelCount_) const;
+ const std::shared_ptr<C2ComponentInterface> mC2ComponentIntf;
+ std::shared_ptr<C2LargeFrame::output> mLargeFrameParams;
+ C2ComponentKindSetting mKind;
+ std::set<C2Param::Index> mSupportedParamIndexSet;
+ std::vector<C2ParamField> mParamFields;
+
+ friend struct MultiAccessUnitHelper;
+};
+
+struct MultiAccessUnitHelper {
+public:
+ MultiAccessUnitHelper(
+ const std::shared_ptr<MultiAccessUnitInterface>& intf);
+
+ virtual ~MultiAccessUnitHelper();
+
+ static bool isEnabledOnPlatform();
+
+ /*
+ * Scatters the incoming linear buffer into access-unit sized buffers
+ * based on the access-unit info.
+ */
+ c2_status_t scatter(
+ std::list<std::unique_ptr<C2Work>> &c2workItems,
+ std::list<std::list<std::unique_ptr<C2Work>>> * const processedWork);
+
+ /*
+ * Gathers different access-units into a single buffer based on the scatter list
+ * and the configured max and threshold sizes. This also generates the associated
+ * access-unit information and attach it with the final result.
+ */
+ c2_status_t gather(
+ std::list<std::unique_ptr<C2Work>> &c2workItems,
+ std::list<std::unique_ptr<C2Work>> * const processedWork);
+
+ /*
+ * Flushes the codec and generated the list of flushed buffers.
+ */
+ c2_status_t flush(
+ std::list<std::unique_ptr<C2Work>> * const c2flushedWorks);
+
+ /*
+ * Gets all the pending buffers under generation in c2workItems.
+ */
+ c2_status_t error(std::list<std::unique_ptr<C2Work>> * const c2workItems);
+
+ /*
+ * Get the interface object of this handler.
+ */
+ std::shared_ptr<MultiAccessUnitInterface> getInterface();
+
+ /*
+ * Gets the status of the object. This really is to make sure that
+ * all the allocators are configured properly within the handler.
+ */
+ bool getStatus();
+
+ /*
+ * Resets the structures inside the handler.
+ */
+ void reset();
+
+protected:
+
+ struct MultiAccessUnitInfo {
+ /*
+ * From the input
+ * Ordinal of the input frame
+ */
+ C2WorkOrdinalStruct inOrdinal;
+
+ /*
+ * Frame indexes of the scattered buffers
+ */
+ std::set<uint64_t> mComponentFrameIds;
+
+ /*
+ * For the output
+ * Current output block.
+ */
+ std::shared_ptr<C2LinearBlock> mBlock;
+
+ /*
+ * Write view of current block
+ */
+ std::shared_ptr<C2WriteView> mWview;
+
+ /*
+ * C2Info related to the current mBlock
+ */
+ std::vector<std::shared_ptr<const C2Info>> mInfos;
+
+ /*
+ * C2AccessUnitInfos for the current buffer
+ */
+ std::vector<C2AccessUnitInfosStruct> mAccessUnitInfos;
+
+ /*
+ * Current tuning used to process this input work
+ */
+ C2LargeFrame::output mLargeFrameTuning;
+
+ /*
+ * Current output C2Work being processed
+ */
+ std::unique_ptr<C2Work> mLargeWork;
+
+ MultiAccessUnitInfo(C2WorkOrdinalStruct ordinal):inOrdinal(ordinal) {
+
+ }
+
+ /*
+ * Resets this frame
+ */
+ void reset();
+ };
+
+ /*
+ * Creates a linear block to be used with work
+ */
+ c2_status_t createLinearBlock(MultiAccessUnitInfo &frame);
+
+ /*
+ * Processes worklets from the component
+ */
+ c2_status_t processWorklets(MultiAccessUnitInfo &frame,
+ std::unique_ptr<C2Work> &work,
+ const std::function <void(std::unique_ptr<C2Work>&)> &addWork);
+
+ /*
+ * Finalizes the work to be send out.
+ */
+ c2_status_t finalizeWork(MultiAccessUnitInfo &frame,
+ uint32_t flags = 0, bool forceComplete = false);
+
+ /*
+ * Merges different access unit infos if possible
+ */
+ void mergeAccessUnitInfo(MultiAccessUnitInfo &frame,
+ uint32_t flags,
+ uint32_t size,
+ int64_t timestamp);
+
+ bool mInit;
+
+ // Interface of this module
+ std::shared_ptr<MultiAccessUnitInterface> mInterface;
+ // Local pool id used for output buffer allocation
+ C2BlockPool::local_id_t mBlockPoolId;
+ // C2Blockpool for output buffer allocation
+ std::shared_ptr<C2BlockPool> mLinearPool;
+ // Allocator for output buffer allocation
+ std::shared_ptr<C2Allocator> mLinearAllocator;
+ // FrameIndex for the current outgoing work
+ std::atomic_uint64_t mFrameIndex;
+ // Mutex to protect mFrameHolder
+ std::mutex mLock;
+ // List of Infos that contains the input and
+ // output work and buffer objects
+ std::list<MultiAccessUnitInfo> mFrameHolder;
+};
+
+} // namespace android
+
+#endif // CODEC2_COMMON_MULTI_ACCESSUNIT_HELPER_H
diff --git a/media/codec2/hal/hidl/1.0/utils/Android.bp b/media/codec2/hal/hidl/1.0/utils/Android.bp
index 2f2ecd1..9646a0b 100644
--- a/media/codec2/hal/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hal/hidl/1.0/utils/Android.bp
@@ -52,7 +52,6 @@
],
}
-
// DO NOT DEPEND ON THIS DIRECTLY
// use libcodec2-hidl-defaults instead
cc_library {
diff --git a/media/codec2/hal/hidl/1.0/utils/Component.cpp b/media/codec2/hal/hidl/1.0/utils/Component.cpp
index 0aeed08..e32e6ae 100644
--- a/media/codec2/hal/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/Component.cpp
@@ -135,6 +135,52 @@
wp<IComponentListener> mListener;
};
+// Component listener for handle multiple access-units
+struct MultiAccessUnitListener : public Component::Listener {
+ MultiAccessUnitListener(const sp<Component> &component,
+ const std::shared_ptr<MultiAccessUnitHelper> &handler):
+ Listener(component), mHandler(handler) {
+ }
+
+ virtual void onError_nb(
+ std::weak_ptr<C2Component> c2component,
+ uint32_t errorCode) override {
+ if (mHandler) {
+ std::list<std::unique_ptr<C2Work>> worklist;
+ mHandler->error(&worklist);
+ if (!worklist.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(worklist));
+ }
+ }
+ Listener::onError_nb(c2component, errorCode);
+ }
+
+ virtual void onTripped_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+ ) override {
+ Listener::onTripped_nb(c2component,
+ c2settingResult);
+ }
+
+ virtual void onWorkDone_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::list<std::unique_ptr<C2Work>> c2workItems) override {
+ if (mHandler) {
+ std::list<std::unique_ptr<C2Work>> processedWork;
+ mHandler->gather(c2workItems, &processedWork);
+ if (!processedWork.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(processedWork));
+ }
+ } else {
+ Listener::onWorkDone_nb(c2component, std::move(c2workItems));
+ }
+ }
+
+ protected:
+ std::shared_ptr<MultiAccessUnitHelper> mHandler;
+};
+
// Component::Sink
struct Component::Sink : public IInputSink {
std::shared_ptr<Component> mComponent;
@@ -208,13 +254,14 @@
const sp<::android::hardware::media::bufferpool::V2_0::
IClientManager>& clientPoolManager)
: mComponent{component},
- mInterface{new ComponentInterface(component->intf(),
- store->getParameterCache())},
mListener{listener},
mStore{store},
mBufferPoolSender{clientPoolManager} {
// Retrieve supported parameters from store
// TODO: We could cache this per component/interface type
+ mMultiAccessUnitIntf = store->tryCreateMultiAccessUnitInterface(component->intf());
+ mInterface = new ComponentInterface(
+ component->intf(), mMultiAccessUnitIntf, store->getParameterCache());
mInit = mInterface->status();
}
@@ -240,7 +287,6 @@
// Methods from ::android::hardware::media::c2::V1_0::IComponent
Return<Status> Component::queue(const WorkBundle& workBundle) {
std::list<std::unique_ptr<C2Work>> c2works;
-
if (!objcpy(&c2works, workBundle)) {
return Status::CORRUPTED;
}
@@ -252,7 +298,19 @@
registerFrameData(mListener, work->input);
}
}
-
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitHelper) {
+ std::list<std::list<std::unique_ptr<C2Work>>> c2worklists;
+ mMultiAccessUnitHelper->scatter(c2works, &c2worklists);
+ for (auto &c2worklist : c2worklists) {
+ err = mComponent->queue_nb(&c2worklist);
+ if (err != C2_OK) {
+ LOG(ERROR) << "Error Queuing to component.";
+ break;
+ }
+ }
+ return static_cast<Status>(err);
+ }
return static_cast<Status>(mComponent->queue_nb(&c2works));
}
@@ -261,6 +319,9 @@
c2_status_t c2res = mComponent->flush_sm(
C2Component::FLUSH_COMPONENT,
&c2flushedWorks);
+ if (mMultiAccessUnitHelper) {
+ c2res = mMultiAccessUnitHelper->flush(&c2flushedWorks);
+ }
// Unregister input buffers.
for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
@@ -469,6 +530,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
return status;
}
@@ -479,6 +543,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
return status;
}
@@ -501,8 +568,14 @@
}
void Component::initListener(const sp<Component>& self) {
- std::shared_ptr<C2Component::Listener> c2listener =
+ std::shared_ptr<C2Component::Listener> c2listener;
+ if (mMultiAccessUnitIntf) {
+ mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+ }
+ c2listener = mMultiAccessUnitHelper ?
+ std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
std::make_shared<Listener>(self);
+
c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
if (res != C2_OK) {
mInit = res;
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp
index 12078e0..41a8904 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentInterface.cpp
@@ -25,7 +25,6 @@
#include <hidl/HidlBinderSupport.h>
#include <utils/Timers.h>
-#include <C2BqBufferPriv.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
@@ -45,9 +44,10 @@
// Implementation of ConfigurableC2Intf based on C2ComponentInterface
struct CompIntf : public ConfigurableC2Intf {
- CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+ CompIntf(const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<MultiAccessUnitInterface>& multiAccessUnitIntf):
ConfigurableC2Intf{intf->getName(), intf->getId()},
- mIntf{intf} {
+ mIntf{intf}, mMultiAccessUnitIntf{multiAccessUnitIntf} {
}
virtual c2_status_t config(
@@ -55,7 +55,34 @@
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2SettingResult>>* const failures
) override {
- return mIntf->config_vb(params, mayBlock, failures);
+ std::vector<C2Param*> paramsToIntf;
+ std::vector<C2Param*> paramsToLargeFrameIntf;
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitIntf == nullptr) {
+ err = mIntf->config_vb(params, mayBlock, failures);
+ return err;
+ }
+ for (auto &p : params) {
+ if (mMultiAccessUnitIntf->isParamSupported(p->index())) {
+ paramsToLargeFrameIntf.push_back(p);
+ } else {
+ paramsToIntf.push_back(p);
+ }
+ }
+ c2_status_t err1 = C2_OK;
+ if (paramsToIntf.size() > 0) {
+ err1 = mIntf->config_vb(paramsToIntf, mayBlock, failures);
+ }
+ if (err1 != C2_OK) {
+ LOG(ERROR) << "We have a failed config";
+ }
+ c2_status_t err2 = C2_OK;
+ if (paramsToLargeFrameIntf.size() > 0) {
+ err2 = mMultiAccessUnitIntf->config(
+ paramsToLargeFrameIntf, mayBlock, failures);
+ }
+ // TODO: correct failure vector
+ return err1 != C2_OK ? err1 : err2;
}
virtual c2_status_t query(
@@ -63,33 +90,100 @@
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2Param>>* const params
) const override {
- return mIntf->query_vb({}, indices, mayBlock, params);
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitIntf == nullptr) {
+ err = mIntf->query_vb({}, indices, mayBlock, params);
+ return err;
+ }
+ std::vector<C2Param::Index> paramsToIntf;
+ std::vector<C2Param::Index> paramsToLargeFrameIntf;
+ for (auto &i : indices) {
+ if (mMultiAccessUnitIntf->isParamSupported(i)) {
+ paramsToLargeFrameIntf.push_back(i);
+ } else {
+ paramsToIntf.push_back(i);
+ }
+ }
+ c2_status_t err1 = C2_OK;
+ if (paramsToIntf.size() > 0) {
+ err1 = mIntf->query_vb({}, paramsToIntf, mayBlock, params);
+ }
+ c2_status_t err2 = C2_OK;
+ if (paramsToLargeFrameIntf.size() > 0) {
+ err2 = mMultiAccessUnitIntf->query(
+ {}, paramsToLargeFrameIntf, mayBlock, params);
+ }
+ // TODO: correct failure vector
+ return err1 != C2_OK ? err1 : err2;
}
virtual c2_status_t querySupportedParams(
std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
) const override {
- return mIntf->querySupportedParams_nb(params);
+ c2_status_t err = mIntf->querySupportedParams_nb(params);
+ if (mMultiAccessUnitIntf != nullptr) {
+ err = mMultiAccessUnitIntf->querySupportedParams(params);
+ }
+ return err;
}
virtual c2_status_t querySupportedValues(
std::vector<C2FieldSupportedValuesQuery>& fields,
c2_blocking_t mayBlock) const override {
- return mIntf->querySupportedValues_vb(fields, mayBlock);
+ if (mMultiAccessUnitIntf == nullptr) {
+ return mIntf->querySupportedValues_vb(fields, mayBlock);
+ }
+ std::vector<C2FieldSupportedValuesQuery> dup = fields;
+ std::vector<C2FieldSupportedValuesQuery> queryArray[2];
+ std::map<C2ParamField, std::pair<uint32_t, size_t>> queryMap;
+ c2_status_t err = C2_OK;
+ for (int i = 0 ; i < fields.size(); i++) {
+ const C2ParamField &field = fields[i].field();
+ uint32_t queryArrayIdx = 1;
+ if (mMultiAccessUnitIntf->isValidField(field)) {
+ queryArrayIdx = 0;
+ }
+ queryMap[field] = std::make_pair(
+ queryArrayIdx, queryArray[queryArrayIdx].size());
+ queryArray[queryArrayIdx].push_back(fields[i]);
+ }
+ if (queryArray[0].size() > 0) {
+ err = mMultiAccessUnitIntf->querySupportedValues(queryArray[0], mayBlock);
+ }
+ if (queryArray[1].size() > 0) {
+ err = mIntf->querySupportedValues_vb(queryArray[1], mayBlock);
+ }
+ for (int i = 0 ; i < dup.size(); i++) {
+ auto it = queryMap.find(dup[i].field());
+ if (it != queryMap.end()) {
+ std::pair<uint32_t, size_t> queryid = it->second;
+ fields[i] = queryArray[queryid.first][queryid.second];
+ }
+ }
+ return err;
}
protected:
std::shared_ptr<C2ComponentInterface> mIntf;
+ std::shared_ptr<MultiAccessUnitInterface> mMultiAccessUnitIntf;
};
} // unnamed namespace
+
// ComponentInterface
ComponentInterface::ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<ParameterCache>& cache):ComponentInterface(intf, nullptr, cache) {
+}
+
+ComponentInterface::ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<MultiAccessUnitInterface>& multiAccessUnitIntf,
const std::shared_ptr<ParameterCache>& cache)
: mInterface{intf},
- mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<CompIntf>(intf, multiAccessUnitIntf))} {
mInit = mConfigurable->init(cache);
}
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 1c0d5b0..988ab6f 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -194,6 +194,36 @@
}
#endif
+std::shared_ptr<MultiAccessUnitInterface> ComponentStore::tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface) {
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf = nullptr;
+ if (c2interface == nullptr) {
+ return nullptr;
+ }
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ c2_status_t err = C2_OK;
+ C2ComponentDomainSetting domain;
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ std::vector<std::shared_ptr<C2ParamDescriptor>> params;
+ bool isComponentSupportsLargeAudioFrame = false;
+ c2interface->querySupportedParams_nb(¶ms);
+ for (const auto ¶mDesc : params) {
+ if (paramDesc->name().compare(C2_PARAMKEY_OUTPUT_LARGE_FRAME) == 0) {
+ isComponentSupportsLargeAudioFrame = true;
+ break;
+ }
+ }
+ if (!isComponentSupportsLargeAudioFrame) {
+ multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
+ c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ }
+ }
+ }
+ return multiAccessUnitIntf;
+}
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
Return<void> ComponentStore::createComponent(
const hidl_string& name,
@@ -242,7 +272,9 @@
c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
#endif
onInterfaceLoaded(c2interface);
- interface = new ComponentInterface(c2interface, mParameterCache);
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf =
+ tryCreateMultiAccessUnitInterface(c2interface);
+ interface = new ComponentInterface(c2interface, multiAccessUnitIntf, mParameterCache);
}
_hidl_cb(static_cast<Status>(res), interface);
return Void();
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
index 3f55618..aed94ec 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
@@ -30,6 +30,8 @@
#include <hidl/Status.h>
#include <hwbinder/IBinder.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Component.h>
#include <C2Buffer.h>
#include <C2.h>
@@ -54,6 +56,8 @@
using ::android::hardware::IBinder;
using ::android::sp;
using ::android::wp;
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
struct ComponentStore;
@@ -113,6 +117,8 @@
std::shared_ptr<C2Component> mComponent;
sp<ComponentInterface> mInterface;
sp<IComponentListener> mListener;
+ std::shared_ptr<MultiAccessUnitInterface> mMultiAccessUnitIntf;
+ std::shared_ptr<MultiAccessUnitHelper> mMultiAccessUnitHelper;
sp<ComponentStore> mStore;
::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
mBufferPoolSender;
@@ -135,6 +141,8 @@
struct Listener;
+ friend struct MultiAccessUnitListener;
+
using HwDeathRecipient = ::android::hardware::hidl_death_recipient;
sp<HwDeathRecipient> mDeathRecipient;
bool mClientDied{false};
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
index 9102f92..2995faf 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
@@ -23,10 +23,15 @@
#include <android/hardware/media/c2/1.0/IComponentInterface.h>
#include <hidl/Status.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Component.h>
#include <C2Buffer.h>
+#include <C2Config.h>
+#include <util/C2InterfaceHelper.h>
#include <C2.h>
+#include <set>
#include <memory>
namespace android {
@@ -39,6 +44,7 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
+using ::android::MultiAccessUnitInterface;
struct ComponentStore;
@@ -46,6 +52,11 @@
ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& interface,
const std::shared_ptr<ParameterCache>& cache);
+
+ ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& interface,
+ const std::shared_ptr<MultiAccessUnitInterface>& largeBufferIntf,
+ const std::shared_ptr<ParameterCache>& cache);
c2_status_t status() const;
virtual Return<sp<IConfigurable>> getConfigurable() override;
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 27e2a05..b5d85da 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
@@ -78,6 +78,9 @@
static std::shared_ptr<FilterWrapper> GetFilterWrapper();
+ std::shared_ptr<MultiAccessUnitInterface> tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface);
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
virtual Return<void> createComponent(
const hidl_string& name,
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index 92b0bf5..2da6501 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -17,7 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "media_c2_hidl_test_common"
#include <stdio.h>
-
+#include <numeric>
#include "media_c2_hidl_test_common.h"
#include <android/hardware/media/c2/1.0/IComponentStore.h>
@@ -221,6 +221,32 @@
return parameters;
}
+constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList{
+ {(1 << VTS_BIT_FLAG_SYNC_FRAME), 0},
+ {(1 << VTS_BIT_FLAG_CSD_FRAME), C2FrameData::FLAG_CODEC_CONFIG},
+};
+
+/*
+ * This is a conversion function that can be used to convert
+ * VTS flags to C2 flags and vice-versa based on the initializer list.
+ * @param flags can be a C2 flag or a VTS flag
+ * @param toC2 if true, converts flags to a C2 flag
+ * if false, converts flags to a VTS flag
+ */
+static uint32_t convertFlags(uint32_t flags, bool toC2) {
+ return std::transform_reduce(
+ flagList.begin(), flagList.end(),
+ 0u,
+ std::bit_or{},
+ [flags, toC2](const std::pair<uint32_t, uint32_t> &entry) {
+ if (toC2) {
+ return (flags & entry.first) ? entry.second : 0;
+ } else {
+ return (flags & entry.second) ? entry.first : 0;
+ }
+ });
+}
+
// Populate Info vector and return number of CSDs
int32_t populateInfoVector(std::string info, android::Vector<FrameInfo>* frameInfo,
bool timestampDevTest, std::list<uint64_t>* timestampUslist) {
@@ -258,9 +284,9 @@
eleInfo >> bytesCount;
eleInfo >> flags;
eleInfo >> timestamp;
- vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ uint32_t c2Flags = convertFlags(flags, true);
frameInfo->editItemAt(frameInfo->size() - 1).largeFrameInfo.push_back(
- {vtsFlags, static_cast<uint32_t>(bytesCount), timestamp});
+ {c2Flags, static_cast<uint32_t>(bytesCount), timestamp});
}
}
}
@@ -298,5 +324,8 @@
else if (infoFlags == 0x10) return (1 << VTS_BIT_FLAG_NO_SHOW_FRAME);
else if (infoFlags == 0x20) return (1 << VTS_BIT_FLAG_CSD_FRAME);
else if (infoFlags == 0x40) return (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME);
+ else if (infoFlags == 0x80) {
+ return (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME) | (1 << VTS_BIT_FLAG_SYNC_FRAME);
+ }
return 0xFF;
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
index 275a721..ab47b7c 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "codec2_hidl_hal_component_test"
#include <android-base/logging.h>
+#include <android/binder_process.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
@@ -382,5 +383,6 @@
}
::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
index 47ceed5..a34cef1 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "codec2_hidl_hal_master_test"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -82,6 +83,20 @@
}
}
+TEST_P(Codec2MasterHalTest, MustUseAidlBeyond202404) {
+ static int sBoardFirstApiLevel = android::base::GetIntProperty("ro.board.first_api_level", 0);
+ static int sBoardApiLevel = android::base::GetIntProperty("ro.board.api_level", 0);
+ if (sBoardFirstApiLevel < 202404 && sBoardApiLevel < 202404) {
+ GTEST_SKIP() << "board first level less than 202404:"
+ << " ro.board.first_api_level = " << sBoardFirstApiLevel
+ << " ro.board.api_level = " << sBoardApiLevel;
+ }
+ ALOGV("HidlCodecAllowed Test");
+
+ EXPECT_NE(mClient->getAidlBase(), nullptr) << "android.hardware.media.c2 MUST use AIDL "
+ << "for chipsets launching at 202404 or above";
+}
+
} // anonymous namespace
INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2MasterHalTest,
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
index 291e323..ee59a8e 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
+++ b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
@@ -1,5 +1,5 @@
-16384 64 0 1 16384 1 0
-49152 64 1024000 3 16384 1 1024000 16384 1 2048000 16384 1 3072000
-32768 64 4096000 2 16384 1 4096000 16384 1 5120000
-49152 64 6144000 3 16384 1 6144000 16384 1 7168000 16384 1 8192000
-10924 64 9216000 1 10924 1 9216000
+16384 128 0 1 16384 1 0
+49152 128 1024000 3 16384 1 1024000 16384 1 2048000 16384 1 3072000
+32768 128 4096000 2 16384 1 4096000 16384 1 5120000
+49152 128 6144000 3 16384 1 6144000 16384 1 7168000 16384 1 8192000
+10924 128 9216000 1 10924 1 9216000
diff --git a/media/codec2/hal/hidl/1.1/utils/Android.bp b/media/codec2/hal/hidl/1.1/utils/Android.bp
index 4f86511..d8b5db5 100644
--- a/media/codec2/hal/hidl/1.1/utils/Android.bp
+++ b/media/codec2/hal/hidl/1.1/utils/Android.bp
@@ -54,7 +54,6 @@
],
}
-
// DO NOT DEPEND ON THIS DIRECTLY
// use libcodec2-hidl-defaults instead
cc_library {
@@ -66,7 +65,6 @@
"com.android.media.swcodec",
],
-
defaults: ["hidl_defaults"],
srcs: [
@@ -97,6 +95,7 @@
"android.hardware.media.omx@1.0",
"libbase",
"libcodec2",
+ "libcodec2_hal_common",
"libcodec2_hidl@1.0",
"libcodec2_hidl_plugin_stub",
"libcodec2_vndk",
@@ -173,4 +172,3 @@
"libhidlbase",
],
}
-
diff --git a/media/codec2/hal/hidl/1.1/utils/Component.cpp b/media/codec2/hal/hidl/1.1/utils/Component.cpp
index d0f4f19..09e5709 100644
--- a/media/codec2/hal/hidl/1.1/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/Component.cpp
@@ -29,6 +29,8 @@
#include <hidl/HidlBinderSupport.h>
#include <utils/Timers.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2BqBufferPriv.h>
#include <C2Debug.h>
#include <C2PlatformSupport.h>
@@ -44,6 +46,8 @@
namespace utils {
using namespace ::android;
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
// ComponentListener wrapper
struct Component::Listener : public C2Component::Listener {
@@ -135,6 +139,52 @@
wp<IComponentListener> mListener;
};
+// Component listener for handle multiple access-units
+struct MultiAccessUnitListener : public Component::Listener {
+ MultiAccessUnitListener(const sp<Component> &component,
+ const std::shared_ptr<MultiAccessUnitHelper> &helper):
+ Listener(component), mHelper(helper) {
+ }
+
+ virtual void onError_nb(
+ std::weak_ptr<C2Component> c2component,
+ uint32_t errorCode) override {
+ if (mHelper) {
+ std::list<std::unique_ptr<C2Work>> worklist;
+ mHelper->error(&worklist);
+ if (!worklist.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(worklist));
+ }
+ }
+ Listener::onError_nb(c2component, errorCode);
+ }
+
+ virtual void onTripped_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+ ) override {
+ Listener::onTripped_nb(c2component,
+ c2settingResult);
+ }
+
+ virtual void onWorkDone_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::list<std::unique_ptr<C2Work>> c2workItems) override {
+ if (mHelper) {
+ std::list<std::unique_ptr<C2Work>> processedWork;
+ mHelper->gather(c2workItems, &processedWork);
+ if (!processedWork.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(processedWork));
+ }
+ } else {
+ Listener::onWorkDone_nb(c2component, std::move(c2workItems));
+ }
+ }
+
+ protected:
+ std::shared_ptr<MultiAccessUnitHelper> mHelper;
+};
+
// Component::Sink
struct Component::Sink : public IInputSink {
std::shared_ptr<Component> mComponent;
@@ -208,13 +258,14 @@
const sp<::android::hardware::media::bufferpool::V2_0::
IClientManager>& clientPoolManager)
: mComponent{component},
- mInterface{new ComponentInterface(component->intf(),
- store->getParameterCache())},
mListener{listener},
mStore{store},
mBufferPoolSender{clientPoolManager} {
// Retrieve supported parameters from store
// TODO: We could cache this per component/interface type
+ mMultiAccessUnitIntf = store->tryCreateMultiAccessUnitInterface(component->intf());
+ mInterface = new ComponentInterface(
+ component->intf(), mMultiAccessUnitIntf, store->getParameterCache());
mInit = mInterface->status();
}
@@ -252,6 +303,19 @@
registerFrameData(mListener, work->input);
}
}
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitHelper) {
+ std::list<std::list<std::unique_ptr<C2Work>>> c2worklists;
+ mMultiAccessUnitHelper->scatter(c2works, &c2worklists);
+ for (auto &c2worklist : c2worklists) {
+ err = mComponent->queue_nb(&c2worklist);
+ if (err != C2_OK) {
+ LOG(ERROR) << "Error Queuing to component.";
+ break;
+ }
+ }
+ return static_cast<Status>(err);
+ }
return static_cast<Status>(mComponent->queue_nb(&c2works));
}
@@ -261,6 +325,9 @@
c2_status_t c2res = mComponent->flush_sm(
C2Component::FLUSH_COMPONENT,
&c2flushedWorks);
+ if (mMultiAccessUnitHelper) {
+ c2res = mMultiAccessUnitHelper->flush(&c2flushedWorks);
+ }
// Unregister input buffers.
for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
@@ -469,6 +536,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
return status;
}
@@ -479,6 +549,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
return status;
}
@@ -508,7 +581,12 @@
}
void Component::initListener(const sp<Component>& self) {
- std::shared_ptr<C2Component::Listener> c2listener =
+ std::shared_ptr<C2Component::Listener> c2listener;
+ if (mMultiAccessUnitIntf) {
+ mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+ }
+ c2listener = mMultiAccessUnitHelper ?
+ std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
std::make_shared<Listener>(self);
c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
if (res != C2_OK) {
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index d47abdd..46af809 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -194,6 +194,37 @@
}
#endif
+std::shared_ptr<MultiAccessUnitInterface> ComponentStore::tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface) {
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf = nullptr;
+ if (c2interface == nullptr) {
+ return nullptr;
+ }
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ c2_status_t err = C2_OK;
+ C2ComponentDomainSetting domain;
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ std::vector<std::shared_ptr<C2ParamDescriptor>> params;
+ bool isComponentSupportsLargeAudioFrame = false;
+ c2interface->querySupportedParams_nb(¶ms);
+ for (const auto ¶mDesc : params) {
+ if (paramDesc->name().compare(C2_PARAMKEY_OUTPUT_LARGE_FRAME) == 0) {
+ isComponentSupportsLargeAudioFrame = true;
+ break;
+ }
+ }
+
+ if (!isComponentSupportsLargeAudioFrame) {
+ multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
+ c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ }
+ }
+ }
+ return multiAccessUnitIntf;
+}
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
Return<void> ComponentStore::createComponent(
const hidl_string& name,
@@ -241,7 +272,10 @@
c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
#endif
onInterfaceLoaded(c2interface);
- interface = new ComponentInterface(c2interface, mParameterCache);
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf =
+ tryCreateMultiAccessUnitInterface(c2interface);
+ interface = new ComponentInterface(
+ c2interface, multiAccessUnitIntf, mParameterCache);
}
_hidl_cb(static_cast<Status>(res), interface);
return Void();
diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
index f16de24..8f0478f 100644
--- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
+++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
@@ -29,6 +29,8 @@
#include <hidl/Status.h>
#include <hwbinder/IBinder.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Component.h>
#include <C2Buffer.h>
#include <C2.h>
@@ -57,6 +59,8 @@
using ::android::hardware::IBinder;
using ::android::sp;
using ::android::wp;
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
struct ComponentStore;
@@ -118,6 +122,8 @@
std::shared_ptr<C2Component> mComponent;
sp<ComponentInterface> mInterface;
sp<IComponentListener> mListener;
+ std::shared_ptr<MultiAccessUnitInterface> mMultiAccessUnitIntf;
+ std::shared_ptr<MultiAccessUnitHelper> mMultiAccessUnitHelper;
sp<ComponentStore> mStore;
::android::hardware::media::c2::V1_1::utils::DefaultBufferPoolSender
mBufferPoolSender;
@@ -140,6 +146,8 @@
struct Listener;
+ friend struct MultiAccessUnitListener;
+
using HwDeathRecipient = ::android::hardware::hidl_death_recipient;
sp<HwDeathRecipient> mDeathRecipient;
bool mClientDied{false};
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 f6daee7..85862a9 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
@@ -79,6 +79,9 @@
static std::shared_ptr<FilterWrapper> GetFilterWrapper();
+ std::shared_ptr<MultiAccessUnitInterface> tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface);
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
virtual Return<void> createComponent(
const hidl_string& name,
diff --git a/media/codec2/hal/hidl/1.2/utils/Android.bp b/media/codec2/hal/hidl/1.2/utils/Android.bp
index b92dc07..a339946 100644
--- a/media/codec2/hal/hidl/1.2/utils/Android.bp
+++ b/media/codec2/hal/hidl/1.2/utils/Android.bp
@@ -58,7 +58,6 @@
],
}
-
// DO NOT DEPEND ON THIS DIRECTLY
// use libcodec2-hidl-defaults instead
cc_library {
@@ -102,6 +101,7 @@
"android.hardware.media.omx@1.0",
"libbase",
"libcodec2",
+ "libcodec2_hal_common",
"libcodec2_hidl@1.0",
"libcodec2_hidl@1.1",
"libcodec2_hidl_plugin_stub",
@@ -197,4 +197,3 @@
name: "libcodec2-hidl-client-defaults",
defaults: ["libcodec2-hidl-client-defaults@1.2"],
}
-
diff --git a/media/codec2/hal/hidl/1.2/utils/Component.cpp b/media/codec2/hal/hidl/1.2/utils/Component.cpp
index 036c900..0fe16e3 100644
--- a/media/codec2/hal/hidl/1.2/utils/Component.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/Component.cpp
@@ -44,6 +44,8 @@
namespace utils {
using namespace ::android;
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
// ComponentListener wrapper
struct Component::Listener : public C2Component::Listener {
@@ -135,6 +137,52 @@
wp<IComponentListener> mListener;
};
+// Component listener for handle multiple access-units
+struct MultiAccessUnitListener : public Component::Listener {
+ MultiAccessUnitListener(const sp<Component> &component,
+ const std::shared_ptr<MultiAccessUnitHelper> &helper):
+ Listener(component), mHelper(helper) {
+ }
+
+ virtual void onError_nb(
+ std::weak_ptr<C2Component> c2component,
+ uint32_t errorCode) override {
+ if (mHelper) {
+ std::list<std::unique_ptr<C2Work>> worklist;
+ mHelper->error(&worklist);
+ if (!worklist.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(worklist));
+ }
+ }
+ Listener::onError_nb(c2component, errorCode);
+ }
+
+ virtual void onTripped_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+ ) override {
+ Listener::onTripped_nb(c2component,
+ c2settingResult);
+ }
+
+ virtual void onWorkDone_nb(
+ std::weak_ptr<C2Component> c2component,
+ std::list<std::unique_ptr<C2Work>> c2workItems) override {
+ if (mHelper) {
+ std::list<std::unique_ptr<C2Work>> processedWork;
+ mHelper->gather(c2workItems, &processedWork);
+ if (!processedWork.empty()) {
+ Listener::onWorkDone_nb(c2component, std::move(processedWork));
+ }
+ } else {
+ Listener::onWorkDone_nb(c2component, std::move(c2workItems));
+ }
+ }
+
+ protected:
+ std::shared_ptr<MultiAccessUnitHelper> mHelper;
+};
+
// Component::Sink
struct Component::Sink : public IInputSink {
std::shared_ptr<Component> mComponent;
@@ -208,13 +256,14 @@
const sp<::android::hardware::media::bufferpool::V2_0::
IClientManager>& clientPoolManager)
: mComponent{component},
- mInterface{new ComponentInterface(component->intf(),
- store->getParameterCache())},
mListener{listener},
mStore{store},
mBufferPoolSender{clientPoolManager} {
// Retrieve supported parameters from store
// TODO: We could cache this per component/interface type
+ mMultiAccessUnitIntf = store->tryCreateMultiAccessUnitInterface(component->intf());
+ mInterface = new ComponentInterface(
+ component->intf(), mMultiAccessUnitIntf, store->getParameterCache());
mInit = mInterface->status();
}
@@ -252,7 +301,19 @@
registerFrameData(mListener, work->input);
}
}
-
+ c2_status_t err = C2_OK;
+ if (mMultiAccessUnitHelper) {
+ std::list<std::list<std::unique_ptr<C2Work>>> c2worklists;
+ mMultiAccessUnitHelper->scatter(c2works, &c2worklists);
+ for (auto &c2worklist : c2worklists) {
+ err = mComponent->queue_nb(&c2worklist);
+ if (err != C2_OK) {
+ LOG(ERROR) << "Error Queuing to component.";
+ break;
+ }
+ }
+ return static_cast<Status>(err);
+ }
return static_cast<Status>(mComponent->queue_nb(&c2works));
}
@@ -261,7 +322,9 @@
c2_status_t c2res = mComponent->flush_sm(
C2Component::FLUSH_COMPONENT,
&c2flushedWorks);
-
+ if (mMultiAccessUnitHelper) {
+ c2res = mMultiAccessUnitHelper->flush(&c2flushedWorks);
+ }
// Unregister input buffers.
for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
if (work) {
@@ -469,6 +532,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
return status;
}
@@ -479,6 +545,9 @@
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
mBlockPools.clear();
}
+ if (mMultiAccessUnitHelper) {
+ mMultiAccessUnitHelper->reset();
+ }
InputBufferManager::unregisterFrameData(mListener);
return status;
}
@@ -539,7 +608,12 @@
}
void Component::initListener(const sp<Component>& self) {
- std::shared_ptr<C2Component::Listener> c2listener =
+ std::shared_ptr<C2Component::Listener> c2listener;
+ if (mMultiAccessUnitIntf) {
+ mMultiAccessUnitHelper = std::make_shared<MultiAccessUnitHelper>(mMultiAccessUnitIntf);
+ }
+ c2listener = mMultiAccessUnitHelper ?
+ std::make_shared<MultiAccessUnitListener>(self, mMultiAccessUnitHelper) :
std::make_shared<Listener>(self);
c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
if (res != C2_OK) {
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index 9fac5d5..f89c835 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -194,6 +194,36 @@
}
#endif
+std::shared_ptr<MultiAccessUnitInterface> ComponentStore::tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface) {
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf = nullptr;
+ if (c2interface == nullptr) {
+ return nullptr;
+ }
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ c2_status_t err = C2_OK;
+ C2ComponentDomainSetting domain;
+ std::vector<std::unique_ptr<C2Param>> heapParams;
+ err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ std::vector<std::shared_ptr<C2ParamDescriptor>> params;
+ bool isComponentSupportsLargeAudioFrame = false;
+ c2interface->querySupportedParams_nb(¶ms);
+ for (const auto ¶mDesc : params) {
+ if (paramDesc->name().compare(C2_PARAMKEY_OUTPUT_LARGE_FRAME) == 0) {
+ isComponentSupportsLargeAudioFrame = true;
+ break;
+ }
+ }
+ if (!isComponentSupportsLargeAudioFrame) {
+ multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
+ c2interface, std::static_pointer_cast<C2ReflectorHelper>(mParamReflector));
+ }
+ }
+ }
+ return multiAccessUnitIntf;
+}
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
Return<void> ComponentStore::createComponent(
const hidl_string& name,
@@ -241,7 +271,9 @@
c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
#endif
onInterfaceLoaded(c2interface);
- interface = new ComponentInterface(c2interface, mParameterCache);
+ std::shared_ptr<MultiAccessUnitInterface> multiAccessUnitIntf =
+ tryCreateMultiAccessUnitInterface(c2interface);
+ interface = new ComponentInterface(c2interface, multiAccessUnitIntf, mParameterCache);
}
_hidl_cb(static_cast<Status>(res), interface);
return Void();
diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/Component.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/Component.h
index 6a73392..f2b77bc 100644
--- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/Component.h
+++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/Component.h
@@ -29,6 +29,8 @@
#include <hidl/Status.h>
#include <hwbinder/IBinder.h>
+#include <codec2/common/MultiAccessUnitHelper.h>
+
#include <C2Component.h>
#include <C2Buffer.h>
#include <C2.h>
@@ -57,6 +59,8 @@
using ::android::hardware::IBinder;
using ::android::sp;
using ::android::wp;
+using ::android::MultiAccessUnitInterface;
+using ::android::MultiAccessUnitHelper;
struct ComponentStore;
@@ -123,6 +127,8 @@
std::shared_ptr<C2Component> mComponent;
sp<ComponentInterface> mInterface;
sp<IComponentListener> mListener;
+ std::shared_ptr<MultiAccessUnitInterface> mMultiAccessUnitIntf;
+ std::shared_ptr<MultiAccessUnitHelper> mMultiAccessUnitHelper;
sp<ComponentStore> mStore;
::android::hardware::media::c2::V1_2::utils::DefaultBufferPoolSender
mBufferPoolSender;
@@ -145,6 +151,8 @@
struct Listener;
+ friend struct MultiAccessUnitListener;
+
using HwDeathRecipient = ::android::hardware::hidl_death_recipient;
sp<HwDeathRecipient> mDeathRecipient;
bool mClientDied{false};
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 e95a651..c08fce4 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
@@ -79,6 +79,9 @@
static std::shared_ptr<FilterWrapper> GetFilterWrapper();
+ std::shared_ptr<MultiAccessUnitInterface> tryCreateMultiAccessUnitInterface(
+ const std::shared_ptr<C2ComponentInterface> &c2interface);
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
virtual Return<void> createComponent(
const hidl_string& name,
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index d867eb1..18c2468 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -45,6 +45,7 @@
static_libs: [
"libSurfaceFlingerProperties",
+ "android.media.codec-aconfig-cc",
],
shared_libs: [
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6b45e0e..40656ff 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -90,6 +90,28 @@
return v == "true";
}
+// Flags can come with individual BufferInfos
+// when used with large frame audio
+constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
+ {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
+ {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
+ {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
+};
+
+static uint32_t convertFlags(uint32_t flags, bool toC2) {
+ return std::transform_reduce(
+ flagList.begin(), flagList.end(),
+ 0u,
+ std::bit_or{},
+ [flags, toC2](const std::pair<uint32_t, uint32_t> &entry) {
+ if (toC2) {
+ return (flags & entry.first) ? entry.second : 0;
+ } else {
+ return (flags & entry.second) ? entry.first : 0;
+ }
+ });
+}
+
} // namespace
CCodecBufferChannel::QueueGuard::QueueGuard(
@@ -245,7 +267,8 @@
if (buffer->meta()->findInt32("decode-only", &tmp) && tmp) {
flags |= C2FrameData::FLAG_DROP_FRAME;
}
- ALOGV("[%s] queueInputBuffer: buffer->size() = %zu", mName, buffer->size());
+ ALOGV("[%s] queueInputBuffer: buffer->size() = %zu time: %lld",
+ mName, buffer->size(), (long long)timeUs);
std::list<std::unique_ptr<C2Work>> items;
std::unique_ptr<C2Work> work(new C2Work);
work->input.ordinal.timestamp = timeUs;
@@ -296,6 +319,34 @@
uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
output->rotation[frameIndex] = rotation;
}
+ sp<RefBase> obj;
+ if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
+ ALOGV("Filling C2Info from multiple access units");
+ sp<WrapperObject<std::vector<AccessUnitInfo>>> infos{
+ (decltype(infos.get()))obj.get()};
+ std::vector<AccessUnitInfo> &accessUnitInfoVec = infos->value;
+ std::vector<C2AccessUnitInfosStruct> multipleAccessUnitInfos;
+ uint32_t outFlags = 0;
+ for (int i = 0; i < accessUnitInfoVec.size(); i++) {
+ outFlags = 0;
+ outFlags = convertFlags(accessUnitInfoVec[i].mFlags, true);
+ if (eos && (outFlags & C2FrameData::FLAG_END_OF_STREAM)) {
+ outFlags &= (~C2FrameData::FLAG_END_OF_STREAM);
+ }
+ multipleAccessUnitInfos.emplace_back(
+ outFlags,
+ accessUnitInfoVec[i].mSize,
+ accessUnitInfoVec[i].mTimestamp);
+ ALOGV("%d) flags: %d, size: %d, time: %llu",
+ i, outFlags, accessUnitInfoVec[i].mSize,
+ (long long)accessUnitInfoVec[i].mTimestamp);
+
+ }
+ const std::shared_ptr<C2AccessUnitInfos::input> c2AccessUnitInfos =
+ C2AccessUnitInfos::input::AllocShared(
+ multipleAccessUnitInfos.size(), 0u, multipleAccessUnitInfos);
+ c2buffer->setInfo(c2AccessUnitInfos);
+ }
work->input.buffers.push_back(c2buffer);
if (encryptedBlock) {
work->input.infoBuffers.emplace_back(C2InfoBuffer::CreateLinearBuffer(
@@ -432,6 +483,130 @@
return heapSeqNum;
}
+typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
+typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
+status_t CCodecBufferChannel::attachEncryptedBuffers(
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString* errorDetailMsg) {
+ static const C2MemoryUsage kDefaultReadWriteUsage{
+ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+ if (!hasCryptoOrDescrambler()) {
+ ALOGE("attachEncryptedBuffers requires Crypto/descrambler object");
+ return -ENOSYS;
+ }
+ size_t size = 0;
+ CHECK(buffer->meta()->findSize("ssize", &size));
+ if (size == 0) {
+ buffer->setRange(0, 0);
+ return OK;
+ }
+ sp<RefBase> obj;
+ CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
+ sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
+ CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
+ sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
+ if (secure || (mCrypto == nullptr)) {
+ if (cryptoInfos->value.size() != 1) {
+ ALOGE("Cannot decrypt multiple access units");
+ return -ENOSYS;
+ }
+ // we are dealing with just one cryptoInfo or descrambler.
+ std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
+ if (info == nullptr) {
+ ALOGE("Cannot decrypt, CryptoInfos are null.");
+ return -ENOSYS;
+ }
+ return attachEncryptedBuffer(
+ memory,
+ secure,
+ info->mKey,
+ info->mIv,
+ info->mMode,
+ info->mPattern,
+ offset,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ buffer,
+ errorDetailMsg);
+ }
+ std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
+ std::shared_ptr<C2LinearBlock> block;
+ c2_status_t err = pool->fetchLinearBlock(
+ size,
+ kDefaultReadWriteUsage,
+ &block);
+ if (err != C2_OK) {
+ ALOGI("[%s] attachEncryptedBuffers: fetchLinearBlock failed: size = %zu (%s) err = %d",
+ mName, size, secure ? "secure" : "non-secure", err);
+ return NO_MEMORY;
+ }
+ ensureDecryptDestination(size);
+ C2WriteView wView = block->map().get();
+ if (wView.error() != C2_OK) {
+ ALOGI("[%s] attachEncryptedBuffers: block map error: %d (non-secure)",
+ mName, wView.error());
+ return UNKNOWN_ERROR;
+ }
+
+ ssize_t result = -1;
+ ssize_t codecDataOffset = 0;
+ size_t inBufferOffset = 0;
+ size_t outBufferSize = 0;
+ uint32_t cryptoInfoIdx = 0;
+ int32_t heapSeqNum = getHeapSeqNum(memory);
+ hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
+ hardware::drm::V1_0::DestinationBuffer dst;
+ dst.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
+ for (int i = 0; i < bufferInfos->value.size(); i++) {
+ if (bufferInfos->value[i].mSize > 0) {
+ std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[cryptoInfoIdx++]);
+ result = mCrypto->decrypt(
+ (uint8_t*)info->mKey,
+ (uint8_t*)info->mIv,
+ info->mMode,
+ info->mPattern,
+ src,
+ inBufferOffset,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ dst,
+ errorDetailMsg);
+ inBufferOffset += bufferInfos->value[i].mSize;
+ if (result < 0) {
+ ALOGI("[%s] attachEncryptedBuffers: decrypt failed: result = %zd",
+ mName, result);
+ return result;
+ }
+ if (wView.error() == C2_OK) {
+ if (wView.size() < result) {
+ ALOGI("[%s] attachEncryptedBuffers: block size too small:"
+ "size=%u result=%zd (non-secure)", mName, wView.size(), result);
+ return UNKNOWN_ERROR;
+ }
+ memcpy(wView.data(), mDecryptDestination->unsecurePointer(), result);
+ bufferInfos->value[i].mSize = result;
+ wView.setOffset(wView.offset() + result);
+ }
+ outBufferSize += result;
+ }
+ }
+ if (wView.error() == C2_OK) {
+ wView.setOffset(0);
+ }
+ std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
+ block->share(codecDataOffset, outBufferSize - codecDataOffset, C2Fence{}))};
+ if (!buffer->copy(c2Buffer)) {
+ ALOGI("[%s] attachEncryptedBuffers: buffer copy failed", mName);
+ return -ENOSYS;
+ }
+ return OK;
+}
+
status_t CCodecBufferChannel::attachEncryptedBuffer(
const sp<hardware::HidlMemory> &memory,
bool secure,
@@ -726,6 +901,138 @@
return queueInputBufferInternal(buffer, block, bufferSize);
}
+status_t CCodecBufferChannel::queueSecureInputBuffers(
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString *errorDetailMsg) {
+ QueueGuard guard(mSync);
+ if (!guard.isRunning()) {
+ ALOGD("[%s] No more buffers should be queued at current state.", mName);
+ return -ENOSYS;
+ }
+
+ if (!hasCryptoOrDescrambler()) {
+ ALOGE("queueSecureInputBuffers requires a Crypto/descrambler Object");
+ return -ENOSYS;
+ }
+ sp<RefBase> obj;
+ CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
+ sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
+ CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
+ sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
+ if (secure || mCrypto == nullptr) {
+ if (cryptoInfos->value.size() != 1) {
+ ALOGE("Cannot decrypt multiple access units on native handles");
+ return -ENOSYS;
+ }
+ std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
+ if (info == nullptr) {
+ ALOGE("Cannot decrypt, CryptoInfos are null");
+ return -ENOSYS;
+ }
+ return queueSecureInputBuffer(
+ buffer,
+ secure,
+ info->mKey,
+ info->mIv,
+ info->mMode,
+ info->mPattern,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ errorDetailMsg);
+ }
+ sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
+
+ std::shared_ptr<C2LinearBlock> block;
+ size_t allocSize = buffer->size();
+ size_t bufferSize = 0;
+ c2_status_t blockRes = C2_OK;
+ bool copied = false;
+ ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
+ "CCodecBufferChannel::decrypt(%s)", mName).c_str());
+ if (mSendEncryptedInfoBuffer) {
+ static const C2MemoryUsage kDefaultReadWriteUsage{
+ C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+ constexpr int kAllocGranule0 = 1024 * 64;
+ constexpr int kAllocGranule1 = 1024 * 1024;
+ std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
+ // round up encrypted sizes to limit fragmentation and encourage buffer reuse
+ if (allocSize <= kAllocGranule1) {
+ bufferSize = align(allocSize, kAllocGranule0);
+ } else {
+ bufferSize = align(allocSize, kAllocGranule1);
+ }
+ blockRes = pool->fetchLinearBlock(
+ bufferSize, kDefaultReadWriteUsage, &block);
+
+ if (blockRes == C2_OK) {
+ C2WriteView view = block->map().get();
+ if (view.error() == C2_OK && view.size() == bufferSize) {
+ copied = true;
+ // TODO: only copy clear sections
+ memcpy(view.data(), buffer->data(), allocSize);
+ }
+ }
+ }
+
+ if (!copied) {
+ block.reset();
+ }
+ // size of cryptoInfo and accessUnitInfo should be the same?
+ ssize_t result = -1;
+ ssize_t codecDataOffset = 0;
+ size_t inBufferOffset = 0;
+ size_t outBufferSize = 0;
+ uint32_t cryptoInfoIdx = 0;
+ {
+ // scoped this block to enable destruction of mappedBlock
+ std::unique_ptr<EncryptedLinearBlockBuffer::MappedBlock> mappedBlock = nullptr;
+ hardware::drm::V1_0::DestinationBuffer destination;
+ destination.type = DrmBufferType::SHARED_MEMORY;
+ IMemoryToSharedBuffer(
+ mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
+ encryptedBuffer->getMappedBlock(&mappedBlock);
+ hardware::drm::V1_0::SharedBuffer source;
+ encryptedBuffer->fillSourceBuffer(&source);
+ for (int i = 0 ; i < bufferInfos->value.size(); i++) {
+ if (bufferInfos->value[i].mSize > 0) {
+ std::unique_ptr<CodecCryptoInfo> info =
+ std::move(cryptoInfos->value[cryptoInfoIdx++]);
+ if (info->mNumSubSamples == 1
+ && info->mSubSamples[0].mNumBytesOfClearData == 0
+ && info->mSubSamples[0].mNumBytesOfEncryptedData == 0) {
+ // no data so we only populate the bufferInfo
+ result = 0;
+ } else {
+ result = mCrypto->decrypt(
+ (uint8_t*)info->mKey,
+ (uint8_t*)info->mIv,
+ info->mMode,
+ info->mPattern,
+ source,
+ inBufferOffset,
+ info->mSubSamples,
+ info->mNumSubSamples,
+ destination,
+ errorDetailMsg);
+ inBufferOffset += bufferInfos->value[i].mSize;
+ if (result < 0) {
+ ALOGI("[%s] decrypt failed: result=%zd", mName, result);
+ return result;
+ }
+ if (destination.type == DrmBufferType::SHARED_MEMORY && mappedBlock) {
+ mappedBlock->copyDecryptedContent(mDecryptDestination, result);
+ }
+ bufferInfos->value[i].mSize = result;
+ outBufferSize += result;
+ }
+ }
+ }
+ buffer->setRange(codecDataOffset, outBufferSize - codecDataOffset);
+ }
+ return queueInputBufferInternal(buffer, block, bufferSize);
+}
+
void CCodecBufferChannel::feedInputBufferIfAvailable() {
QueueGuard guard(mSync);
if (!guard.isRunning()) {
@@ -1604,8 +1911,14 @@
padding = 0;
}
if (delay || padding) {
- // We need write access to the buffers, and we're already in
- // array mode.
+ // We need write access to the buffers, so turn them into array mode.
+ // TODO: b/321930152 - define SkipCutOutputBuffers that takes output from
+ // component, runs it through SkipCutBuffer and allocate local buffer to be
+ // used by fwk. Make initSkipCutBuffer() return OutputBuffers similar to
+ // toArrayMode().
+ if (!output->buffers->isArrayMode()) {
+ output->buffers = output->buffers->toArrayMode(numOutputSlots);
+ }
output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
}
}
@@ -2259,12 +2572,34 @@
case OutputBuffers::DISCARD:
break;
case OutputBuffers::NOTIFY_CLIENT:
+ {
// TRICKY: we want popped buffers reported in order, so sending
// the callback while holding the lock here. This assumes that
// onOutputBufferAvailable() does not block. onOutputBufferAvailable()
// callbacks are always sent with the Output lock held.
+ if (c2Buffer) {
+ std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
+ std::static_pointer_cast<const C2AccessUnitInfos::output>(
+ c2Buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
+ if (bufferMetadata && bufferMetadata->flexCount() > 0) {
+ uint32_t flag = 0;
+ std::vector<AccessUnitInfo> accessUnitInfos;
+ for (int nMeta = 0; nMeta < bufferMetadata->flexCount(); nMeta++) {
+ const C2AccessUnitInfosStruct &bufferMetadataStruct =
+ bufferMetadata->m.values[nMeta];
+ flag = convertFlags(bufferMetadataStruct.flags, false);
+ accessUnitInfos.emplace_back(flag,
+ static_cast<size_t>(bufferMetadataStruct.size),
+ static_cast<size_t>(bufferMetadataStruct.timestamp));
+ }
+ sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
+ new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
+ outBuffer->meta()->setObject("accessUnitInfo", obj);
+ }
+ }
mCallback->onOutputBufferAvailable(index, outBuffer);
break;
+ }
case OutputBuffers::REALLOCATE:
if (++reallocTryNum > kMaxReallocTry) {
output.unlock();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 8dc9fb6..b470655 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -73,6 +73,10 @@
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) override;
+ status_t queueSecureInputBuffers(
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString *errorDetailMsg) override;
status_t attachBuffer(
const std::shared_ptr<C2Buffer> &c2Buffer,
const sp<MediaCodecBuffer> &buffer) override;
@@ -88,6 +92,12 @@
size_t numSubSamples,
const sp<MediaCodecBuffer> &buffer,
AString* errorDetailMsg) override;
+ status_t attachEncryptedBuffers(
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString* errorDetailMsg) override;
status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
void pollForRenderedBuffers() override;
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 670923b..d313f33 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -18,11 +18,14 @@
#define LOG_TAG "CCodecBuffers"
#include <utils/Log.h>
+#include <numeric>
+
#include <C2AllocatorGralloc.h>
#include <C2PlatformSupport.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/CodecBase.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/SkipCutBuffer.h>
#include <mediadrm/ICrypto.h>
@@ -147,6 +150,171 @@
return copy;
}
+// MultiAccessUnitSkipCutBuffer for buffer and bufferInfos
+
+class MultiAccessUnitSkipCutBuffer : public SkipCutBuffer {
+
+public:
+ explicit MultiAccessUnitSkipCutBuffer(
+ int32_t skip, int32_t cut, size_t num16BitChannels):
+ SkipCutBuffer(skip, cut, num16BitChannels),
+ mFrontPaddingDelay(0), mSize(0) {
+ }
+ void clearAll() {
+ mInfos.clear();
+ mFrontPaddingDelay = 0;
+ mSize = 0;
+ SkipCutBuffer::clear();
+ }
+
+ virtual ~MultiAccessUnitSkipCutBuffer() {
+
+ }
+
+ void submitMultiAccessUnits(
+ const sp<MediaCodecBuffer>& buffer,
+ int32_t sampleRate, size_t num16BitChannels,
+ std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
+ if (infos == nullptr) {
+ // there is nothing to do more.
+ SkipCutBuffer::submit(buffer);
+ return;
+ }
+ typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
+ CHECK_EQ(mSize, SkipCutBuffer::size());
+ sp<BufferInfosWrapper> bufferInfos{new BufferInfosWrapper(decltype(bufferInfos->value)())};
+ uint32_t availableSize = buffer->size() + SkipCutBuffer::size();
+ uint32_t frontPadding = mFrontPadding;
+ int32_t lastEmptyAccessUnitIndex = -1;
+ int64_t byteInUs = 0;
+ if (sampleRate > 0 && num16BitChannels > 0) {
+ byteInUs = (1000000u / (sampleRate * num16BitChannels * 2));
+ }
+ if (frontPadding > 0) {
+ mInfos.clear();
+ mSize = 0;
+ }
+ for (int i = 0 ; i < infos->flexCount() && frontPadding > 0; i++) {
+ uint32_t flagsInPadding = 0;
+ int64_t timeInPadding = 0;
+ if (infos->m.values[i].size <= frontPadding) {
+ // we have more front padding so this buffer is not going to be used.
+ int32_t consumed = infos->m.values[i].size;
+ frontPadding -= consumed;
+ mFrontPaddingDelay += byteInUs * (consumed);
+ availableSize -= consumed;
+ flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
+ timeInPadding = infos->m.values[i].timestamp;
+ } else {
+ C2AccessUnitInfosStruct info = infos->m.values[i];
+ mFrontPaddingDelay += byteInUs * (frontPadding);
+ info.size -= frontPadding;
+ info.timestamp -= mFrontPaddingDelay;
+ availableSize -= frontPadding;
+ flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
+ timeInPadding = infos->m.values[i].timestamp;
+ frontPadding = 0;
+ mInfos.push_back(info);
+ mSize += info.size;
+ }
+ if (flagsInPadding != 0) {
+ bufferInfos->value.emplace_back(
+ flagsInPadding, 0, timeInPadding);
+ }
+ lastEmptyAccessUnitIndex = i;
+ }
+ if (frontPadding <= 0) {
+ // process what's already in the buffer first
+ auto it = mInfos.begin();
+ while (it != mInfos.end() && availableSize > mBackPadding) {
+ // we have samples to send out.
+ if ((availableSize - it->size) >= mBackPadding) {
+ // this is totally used here.
+ int32_t consumed = it->size;
+ bufferInfos->value.emplace_back(
+ toMediaCodecFlags(it->flags), consumed, it->timestamp);
+ availableSize -= consumed;
+ mSize -= consumed;
+ it = mInfos.erase(it);
+ } else {
+ int32_t consumed = availableSize - mBackPadding;
+ bufferInfos->value.emplace_back(
+ toMediaCodecFlags(it->flags),
+ consumed,
+ it->timestamp);
+ it->size -= consumed;
+ it->timestamp += consumed * byteInUs;
+ availableSize -= consumed;
+ mSize -= consumed;
+ it++;
+ }
+ }
+ // if buffer has more process all of it and keep the remaining info.
+ for (int i = (lastEmptyAccessUnitIndex + 1) ; i < infos->flexCount() ; i++) {
+ // upddate updatedInfo and mInfos
+ if (availableSize > mBackPadding) {
+ // we have to take data from the new buffer.
+ if (availableSize - infos->m.values[i].size >= mBackPadding) {
+ // we are using this info
+ int32_t consumed = infos->m.values[i].size;
+ bufferInfos->value.emplace_back(
+ toMediaCodecFlags(infos->m.values[i].flags),
+ consumed,
+ infos->m.values[i].timestamp - mFrontPaddingDelay);
+ availableSize -= consumed;
+ } else {
+ // if we need to update the size
+ C2AccessUnitInfosStruct info = infos->m.values[i];
+ int32_t consumed = availableSize - mBackPadding;
+ bufferInfos->value.emplace_back(
+ toMediaCodecFlags(infos->m.values[i].flags),
+ consumed,
+ infos->m.values[i].timestamp - mFrontPaddingDelay);
+ info.size -= consumed;
+ info.timestamp = info.timestamp - mFrontPaddingDelay +
+ consumed * byteInUs;
+ mInfos.push_back(info);
+ availableSize -= consumed;
+ mSize += info.size;
+ }
+ } else {
+ // we have to maintain infos
+ C2AccessUnitInfosStruct info = infos->m.values[i];
+ info.timestamp -= mFrontPaddingDelay;
+ mInfos.push_back(info);
+ mSize += info.size;
+ }
+ }
+ }
+ SkipCutBuffer::submit(buffer);
+ infos = nullptr;
+ if (!bufferInfos->value.empty()) {
+ buffer->meta()->setObject("accessUnitInfo", bufferInfos);
+ }
+ }
+protected:
+ // Flags can come with individual BufferInfos
+ // when used with large frame audio
+ constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
+ {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
+ {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
+ {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
+ };
+
+ static uint32_t toMediaCodecFlags(uint32_t flags) {
+ return std::transform_reduce(
+ flagList.begin(), flagList.end(),
+ 0u,
+ std::bit_or{},
+ [flags](const std::pair<uint32_t, uint32_t> &entry) {
+ return (flags & entry.second) ? entry.first : 0;
+ });
+ }
+ std::list<C2AccessUnitInfosStruct> mInfos;
+ int64_t mFrontPaddingDelay;
+ size_t mSize;
+};
+
// OutputBuffers
OutputBuffers::OutputBuffers(const char *componentName, const char *name)
@@ -201,6 +369,15 @@
}
}
+bool OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate,
+ int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
+ if (mSkipCutBuffer == nullptr) {
+ return false;
+ }
+ mSkipCutBuffer->submitMultiAccessUnits(buffer, sampleRate, channelCount, infos);
+ return true;
+}
+
void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
if (mSkipCutBuffer != nullptr) {
size_t prevSize = mSkipCutBuffer->size();
@@ -208,7 +385,7 @@
ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
}
}
- mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
+ mSkipCutBuffer = new MultiAccessUnitSkipCutBuffer(skip, cut, mChannelCount);
}
bool OutputBuffers::convert(
@@ -1160,7 +1337,16 @@
ALOGD("[%s] copy buffer failed", mName);
return WOULD_BLOCK;
}
- submit(c2Buffer);
+ if (buffer && buffer->hasInfo(C2AccessUnitInfos::output::PARAM_TYPE)) {
+ std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
+ std::static_pointer_cast<const C2AccessUnitInfos::output>(
+ buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
+ if (submit(c2Buffer, mSampleRate, mChannelCount, bufferMetadata)) {
+ buffer->removeInfo(C2AccessUnitInfos::output::PARAM_TYPE);
+ }
+ } else {
+ submit(c2Buffer);
+ }
handleImageData(c2Buffer);
*clientBuffer = c2Buffer;
ALOGV("[%s] grabbed buffer %zu", mName, *index);
@@ -1198,7 +1384,7 @@
(void)flushedWork;
mImpl.flush();
if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->clear();
+ mSkipCutBuffer->clearAll();
}
}
@@ -1356,7 +1542,7 @@
void LinearOutputBuffers::flush(
const std::list<std::unique_ptr<C2Work>> &flushedWork) {
if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->clear();
+ mSkipCutBuffer->clearAll();
}
FlexOutputBuffers::flush(flushedWork);
}
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index cbef644..f0936bc 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -20,6 +20,7 @@
#include <optional>
#include <string>
+#include <vector>
#include <C2Config.h>
#include <DataConverter.h>
@@ -33,6 +34,8 @@
struct ICrypto;
class MemoryDealer;
class SkipCutBuffer;
+class MultiAccessUnitSkipCutBuffer;
+struct AccessUnitInfo;
constexpr size_t kLinearBufferSize = 1048576;
// This can fit an 8K frame.
@@ -382,13 +385,17 @@
sp<MediaCodecBuffer>* outBuffer);
protected:
- sp<SkipCutBuffer> mSkipCutBuffer;
+
+ sp<MultiAccessUnitSkipCutBuffer> mSkipCutBuffer;
/**
* Update the SkipCutBuffer object. No-op if it's never initialized.
*/
void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount);
+ bool submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate,
+ int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos);
+
/**
* Submit buffer to SkipCutBuffer object, if initialized.
*/
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 6d49fa8..c22deca 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -402,10 +402,19 @@
add(ConfigMapper(KEY_MAX_INPUT_SIZE, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE, "value")
.limitTo(D::INPUT));
+
// remove when codecs switch to PARAMKEY
deprecated(ConfigMapper(KEY_MAX_INPUT_SIZE, "coded.max-frame-size", "value")
.limitTo(D::INPUT));
+ // large frame params
+ add(ConfigMapper(KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE,
+ C2_PARAMKEY_OUTPUT_LARGE_FRAME, "max-size")
+ .limitTo(D::AUDIO & D::OUTPUT));
+ add(ConfigMapper(KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE,
+ C2_PARAMKEY_OUTPUT_LARGE_FRAME, "threshold-size")
+ .limitTo(D::AUDIO & D::OUTPUT));
+
// Rotation
// Note: SDK rotation is clock-wise, while C2 rotation is counter-clock-wise
add(ConfigMapper(KEY_ROTATION, C2_PARAMKEY_VUI_ROTATION, "value")
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 5c1755e..9c514f2 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1036,6 +1036,37 @@
return const_cast<native_handle_t *>(mBlock->handle());
}
+void EncryptedLinearBlockBuffer::getMappedBlock(
+ std::unique_ptr<MappedBlock> * const mappedBlock) const {
+ if (mappedBlock) {
+ mappedBlock->reset(new EncryptedLinearBlockBuffer::MappedBlock(mBlock));
+ }
+ return;
+}
+
+EncryptedLinearBlockBuffer::MappedBlock::MappedBlock(
+ const std::shared_ptr<C2LinearBlock> &block) : mView(block->map().get()) {
+}
+
+bool EncryptedLinearBlockBuffer::MappedBlock::copyDecryptedContent(
+ const sp<IMemory> &decrypted, size_t length) {
+ if (mView.error() != C2_OK) {
+ return false;
+ }
+ if (mView.size() < length) {
+ ALOGE("View size(%d) less than decrypted length(%zu)",
+ mView.size(), length);
+ return false;
+ }
+ memcpy(mView.data(), decrypted->unsecurePointer(), length);
+ mView.setOffset(mView.offset() + length);
+ return true;
+}
+
+EncryptedLinearBlockBuffer::MappedBlock::~MappedBlock() {
+ mView.setOffset(0);
+}
+
using ::aidl::android::hardware::graphics::common::Cta861_3;
using ::aidl::android::hardware::graphics::common::Smpte2086;
@@ -1049,11 +1080,8 @@
// Unwrap raw buffer handle from the C2Handle
native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
if (!nh) {
- nh = UnwrapNativeCodec2AhwbHandle(handle);
- if (!nh) {
- ALOGE("handle is not compatible to neither C2HandleGralloc nor C2HandleAhwb");
- return;
- }
+ ALOGE("handle is not compatible to any gralloc C2Handle types");
+ return;
}
// Import the raw handle so IMapper can use the buffer. The imported
// handle must be freed when the client is done with the buffer.
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index b73acab..5e96921 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -384,6 +384,17 @@
*/
native_handle_t *handle() const;
+ class MappedBlock {
+ public:
+ explicit MappedBlock(const std::shared_ptr<C2LinearBlock> &block);
+ virtual ~MappedBlock();
+ bool copyDecryptedContent(const sp<IMemory> &decrypted, size_t length);
+ private:
+ C2WriteView mView;
+ };
+
+ void getMappedBlock(std::unique_ptr<MappedBlock> * const mappedBlock) const;
+
private:
std::shared_ptr<C2LinearBlock> mBlock;
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 453a0d2..8dce789 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -20,6 +20,8 @@
#include <strings.h>
+#include <android_media_codec.h>
+
#include <C2Component.h>
#include <C2Config.h>
#include <C2Debug.h>
@@ -752,6 +754,24 @@
}
addSupportedColorFormats(
intf, caps.get(), trait, mediaType, it->second);
+
+ if (android::media::codec::provider_->large_audio_frame_finish()) {
+ // Adding feature-multiple-frames when C2LargeFrame param is present
+ if (trait.domain == C2Component::DOMAIN_AUDIO) {
+ std::vector<std::shared_ptr<C2ParamDescriptor>> params;
+ c2_status_t err = intf->querySupportedParams(¶ms);
+ if (err == C2_OK) {
+ for (const auto ¶mDesc : params) {
+ if (C2LargeFrame::output::PARAM_TYPE == paramDesc->index()) {
+ std::string featureMultipleFrames =
+ std::string(KEY_FEATURE_) + FEATURE_MultipleFrames;
+ caps->addDetail(featureMultipleFrames.c_str(), 0);
+ break;
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/media/codec2/tests/C2ComponentInterface_test.cpp b/media/codec2/tests/C2ComponentInterface_test.cpp
index 67f733d..d1844b0 100644
--- a/media/codec2/tests/C2ComponentInterface_test.cpp
+++ b/media/codec2/tests/C2ComponentInterface_test.cpp
@@ -235,7 +235,7 @@
// |*heapParams[0]| is a parameter value. The size of |heapParams| has to be one.
ASSERT_EQ(1u, heapParams.size());
EXPECT_TRUE(heapParams[0]);
- EXPECT_EQ(*heapParams[0], expected);
+ EXPECT_EQ(*heapParams[0], (C2Param &)(expected));
}
template <typename T> void C2CompIntfTest::querySupportedParam() {
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 60b5b29..971b5a5 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -318,6 +318,14 @@
return reinterpret_cast<C2HandleAhwb *>(res);
}
+ static uint32_t getPixelFormat(const C2Handle *const handle) {
+ if (handle == nullptr) {
+ return 0;
+ }
+ const ExtraData *xd = GetExtraData(handle);
+ return xd->format;
+ }
+
static C2HandleAhwb* WrapNativeHandle(
const native_handle_t *const handle,
uint32_t width, uint32_t height, uint32_t format, uint64_t usage,
@@ -899,7 +907,17 @@
native_handle_t *UnwrapNativeCodec2GrallocHandle(const C2Handle *const handle) {
- return C2HandleGralloc::UnwrapNativeHandle(handle);
+ if (handle == nullptr) {
+ return nullptr;
+ }
+ if (C2AllocatorGralloc::CheckHandle(handle)) {
+ return C2HandleGralloc::UnwrapNativeHandle(handle);
+ }
+ if (C2AllocatorAhwb::CheckHandle(handle)) {
+ return C2HandleAhwb::UnwrapNativeHandle(handle);
+ }
+ ALOGE("tried to unwrap non c2 compatible handle");
+ return nullptr;
}
C2Handle *WrapNativeCodec2GrallocHandle(
@@ -911,7 +929,38 @@
}
uint32_t ExtractFormatFromCodec2GrallocHandle(const C2Handle *const handle) {
- return C2HandleGralloc::getPixelFormat(handle);
+ if (C2AllocatorGralloc::CheckHandle(handle)) {
+ return C2HandleGralloc::getPixelFormat(handle);
+ }
+ if (C2AllocatorAhwb::CheckHandle(handle)) {
+ return C2HandleAhwb::getPixelFormat(handle);
+ }
+ ALOGE("tried to extract pixelformat from non c2 compatible handle");
+ return 0;
+}
+
+bool ExtractMetadataFromCodec2GrallocHandle(
+ const C2Handle *const handle,
+ uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride) {
+ if (handle == nullptr) {
+ ALOGE("ExtractMetadata from nullptr");
+ return false;
+ }
+ if (C2AllocatorGralloc::CheckHandle(handle)) {
+ uint32_t generation;
+ uint64_t igbp_id;
+ uint32_t igbp_slot;
+ (void)C2HandleGralloc::Import(handle, width, height, format, usage, stride,
+ &generation, &igbp_id, &igbp_slot);
+ return true;
+ }
+ if (C2AllocatorAhwb::CheckHandle(handle)) {
+ uint64_t origId;
+ (void)C2HandleAhwb::Import(handle, width, height, format, usage, stride, &origId);
+ return true;
+ }
+ ALOGE("ExtractMetadata from non compatible handle");
+ return false;
}
bool MigrateNativeCodec2GrallocHandle(
@@ -1137,8 +1186,17 @@
const C2Handle *const handle,
uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride,
uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot) {
- (void)C2HandleGralloc::Import(handle, width, height, format, usage, stride,
- generation, igbp_id, igbp_slot);
+ if (C2AllocatorGralloc::CheckHandle(handle)) {
+ (void)C2HandleGralloc::Import(handle, width, height, format, usage, stride,
+ generation, igbp_id, igbp_slot);
+ return;
+ }
+ if (C2AllocatorAhwb::CheckHandle(handle)) {
+ uint64_t origId;
+ (void)C2HandleAhwb::Import(handle, width, height, format, usage, stride, &origId);
+ return;
+ }
+ ALOGE("Tried to extract metadata from non c2 compatible handle");
}
C2AllocatorGralloc::Impl::Impl(id_t id, bool bufferQueue)
@@ -1250,10 +1308,6 @@
}
-native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle) {
- return C2HandleAhwb::UnwrapNativeHandle(handle);
-}
-
C2Handle *WrapNativeCodec2AhwbHandle(
const native_handle_t *const handle,
uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
@@ -1477,13 +1531,6 @@
c2_status_t mInit;
};
-void _UnwrapNativeCodec2AhwbMetadata(
- const C2Handle *const handle,
- uint32_t *width, uint32_t *height, uint32_t *format,uint64_t *usage, uint32_t *stride,
- uint64_t *origId) {
- (void)C2HandleAhwb::Import(handle, width, height, format, usage, stride, origId);
-}
-
C2AllocatorAhwb::Impl::Impl(id_t id)
: mInit(C2_OK) {
// TODO: get this from allocator
diff --git a/media/codec2/vndk/include/C2AllocatorGralloc.h b/media/codec2/vndk/include/C2AllocatorGralloc.h
index 1a34c30..53b6262 100644
--- a/media/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/codec2/vndk/include/C2AllocatorGralloc.h
@@ -22,8 +22,25 @@
#include <C2Buffer.h>
namespace android {
+// VNDK
+/**
+ * Extract pixel format from the extra data of gralloc handle.
+ *
+ * @return 0 when no valid pixel format exists.
+ */
+uint32_t ExtractFormatFromCodec2GrallocHandle(const C2Handle *const handle);
/**
+ * Extract metadata from the extra data of gralloc handle.
+ *
+ * @return {@code false} if extraction was failed, {@code true} otherwise.
+ */
+bool ExtractMetadataFromCodec2GrallocHandle(
+ const C2Handle *const handle,
+ uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride);
+
+// Not for VNDK (system partition and inside vndk only)
+/**
* Unwrap the native handle from a Codec2 handle allocated by C2AllocatorGralloc.
*
* @param handle a handle allocated by C2AllocatorGralloc. This includes handles returned for a
@@ -46,13 +63,6 @@
uint32_t generation = 0, uint64_t igbp_id = 0, uint32_t igbp_slot = 0);
/**
- * Extract pixel format from the extra data of gralloc handle.
- *
- * @return 0 when no valid pixel format exists.
- */
-uint32_t ExtractFormatFromCodec2GrallocHandle(const C2Handle *const handle);
-
-/**
* When the gralloc handle is migrated to another bufferqueue, update
* bufferqueue information.
*
@@ -71,16 +81,6 @@
uint32_t *generation, uint64_t *igbp_id, uint32_t *igbp_slot);
/**
- * Unwrap the native handle from a Codec2 handle allocated by C2AllocatorAhwb.
- *
- * @param handle a handle allocated by C2AllocatorAhwb. This includes handles returned for a
- * graphic block allocation handle based on an AHardwareBuffer.
- *
- * @return a new NON-OWNING native handle that must be deleted using native_handle_delete.
- */
-native_handle_t *UnwrapNativeCodec2AhwbHandle(const C2Handle *const handle);
-
-/**
* Wrap the gralloc handle and metadata based on AHardwareBuffer into Codec2 handle
* recognized by C2AllocatorAhwb.
*
@@ -92,14 +92,6 @@
uint32_t width, uint32_t height, uint32_t format, uint64_t usage, uint32_t stride,
uint64_t origId);
-/**
- * \todo Get this from the buffer
- */
-void _UnwrapNativeCodec2AhwbMetadata(
- const C2Handle *const handle,
- uint32_t *width, uint32_t *height, uint32_t *format, uint64_t *usage, uint32_t *stride,
- uint64_t *origId);
-
class C2AllocatorGralloc : public C2Allocator {
public:
virtual id_t getId() const override;
diff --git a/media/codec2/vndk/platform/C2IgbaBuffer.cpp b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
index eafdb22..3622d5e 100644
--- a/media/codec2/vndk/platform/C2IgbaBuffer.cpp
+++ b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
@@ -192,28 +192,25 @@
c2_status_t res = _fetchGraphicBlock(
width, height, format, usage, kBlockingFetchTimeoutNs, &origId, block, &fence);
- if (res == C2_BLOCKING) {
+ if (res == C2_TIMED_OUT) {
+ // SyncFence waiting timeout.
+ // Usually HAL treats C2_TIMED_OUT as an irrecoverable error.
+ // We want HAL to re-try.
return C2_BLOCKING;
}
- if (res != C2_OK) {
- return res;
- }
- // TODO: bundle the fence to the block. Are API changes required?
- res = fence.wait(kSyncFenceWaitNs);
- if (res != C2_OK) {
- bool aidlRet = true;
- ::ndk::ScopedAStatus status = mIgba->deallocate(origId, &aidlRet);
- ALOGE("Waiting a sync fence failed %d aidl(%d: %d)",
- res, status.isOk(), aidlRet);
- }
- return C2_OK;
+ return res;
}
c2_status_t C2IgbaBlockPool::fetchGraphicBlock(
uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block, C2Fence *fence) {
uint64_t origId;
- return _fetchGraphicBlock(width, height, format, usage, 0LL, &origId, block, fence);
+ c2_status_t res = _fetchGraphicBlock(width, height, format, usage, 0LL, &origId, block, fence);
+ if (res == C2_TIMED_OUT) {
+ *fence = C2Fence();
+ return C2_BLOCKING;
+ }
+ return res;
}
c2_status_t C2IgbaBlockPool::_fetchGraphicBlock(
@@ -263,10 +260,27 @@
}
}
- *fence = _C2FenceFactory::CreateSyncFence(allocation.fence.release());
+ C2Fence syncFence = _C2FenceFactory::CreateSyncFence(allocation.fence.release());
AHardwareBuffer *ahwb = allocation.buffer.release(); // This is acquired.
CHECK(AHardwareBuffer_getId(ahwb, origId) == ::android::OK);
- c2_status_t res = CreateGraphicBlockFromAhwb(ahwb, mAllocator, mIgba, block);
+
+ // We are waiting for SyncFence here for backward compatibility.
+ // H/W based Sync Fence could be returned to improve pipeline latency.
+ //
+ // TODO: Add a component configuration for returning sync fence
+ // from fetchGraphicBlock() as the C2Fence output param(b/322283520).
+ // In the case C2_OK along with GraphicBlock must be returned together.
+ c2_status_t res = syncFence.wait(kSyncFenceWaitNs);
+ if (res != C2_OK) {
+ AHardwareBuffer_release(ahwb);
+ bool aidlRet = true;
+ ::ndk::ScopedAStatus status = mIgba->deallocate(*origId, &aidlRet);
+ ALOGE("Waiting a sync fence failed %d aidl(%d: %d)",
+ res, status.isOk(), aidlRet);
+ return C2_TIMED_OUT;
+ }
+
+ res = CreateGraphicBlockFromAhwb(ahwb, mAllocator, mIgba, block);
AHardwareBuffer_release(ahwb);
if (res != C2_OK) {
bool aidlRet = true;
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index a39e90e..430ba83 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -18,7 +18,6 @@
//#define LOG_NDEBUG 0
#include <log/log.h>
-#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdint.h>
#include <algorithm>
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index ae37152..660f161 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1699,29 +1699,42 @@
}
status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
+ status_t result = NO_ERROR;
AutoMutex lock(mLock);
- ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d mRoutedDeviceId %d",
- __func__, mPortId, deviceId, mSelectedDeviceId, mRoutedDeviceId);
+ ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d",
+ __func__, mPortId, deviceId, mSelectedDeviceId);
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
if (mStatus == NO_ERROR) {
- // allow track invalidation when track is not playing to propagate
- // the updated mSelectedDeviceId
- if (isPlaying_l()) {
- if (mSelectedDeviceId != mRoutedDeviceId) {
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
- mProxy->interrupt();
+ if (isOffloadedOrDirect_l()) {
+ if (mState == STATE_STOPPED || mState == STATE_FLUSHED) {
+ ALOGD("%s(%d): creating a new AudioTrack", __func__, mPortId);
+ result = restoreTrack_l("setOutputDevice", true /* forceRestore */);
+ } else {
+ ALOGW("%s(%d). Offloaded or Direct track is not STOPPED or FLUSHED. "
+ "State: %s.",
+ __func__, mPortId, stateToString(mState));
+ result = INVALID_OPERATION;
}
} else {
- // if the track is idle, try to restore now and
- // defer to next start if not possible
- if (restoreTrack_l("setOutputDevice") != OK) {
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ // allow track invalidation when track is not playing to propagate
+ // the updated mSelectedDeviceId
+ if (isPlaying_l()) {
+ if (mSelectedDeviceId != mRoutedDeviceId) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ mProxy->interrupt();
+ }
+ } else {
+ // if the track is idle, try to restore now and
+ // defer to next start if not possible
+ if (restoreTrack_l("setOutputDevice") != OK) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
}
}
}
}
- return NO_ERROR;
+ return result;
}
audio_port_handle_t AudioTrack::getOutputDevice() {
@@ -2835,7 +2848,7 @@
return 0;
}
-status_t AudioTrack::restoreTrack_l(const char *from)
+status_t AudioTrack::restoreTrack_l(const char *from, bool forceRestore)
{
status_t result = NO_ERROR; // logged: make sure to set this before returning.
const int64_t beginNs = systemTime();
@@ -2856,7 +2869,8 @@
// output parameters and new IAudioFlinger in createTrack_l()
AudioSystem::clearAudioConfigCache();
- if (isOffloadedOrDirect_l() || mDoNotReconnect) {
+ if (!forceRestore &&
+ (isOffloadedOrDirect_l() || mDoNotReconnect)) {
// FIXME re-creation of offloaded and direct tracks is not yet implemented;
// reconsider enabling for linear PCM encodings when position can be preserved.
result = DEAD_OBJECT;
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index 234e858..68dba34 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -43,10 +43,9 @@
}
],
"postsubmit": [
- // TODO(b/302036943): Enable once we make it pass with AIDL HAL on CF.
- // {
- // "name": "audioeffect_analysis"
- // },
+ {
+ "name": "audioeffect_analysis"
+ },
{
"name": "CtsVirtualDevicesTestCases",
"options" : [
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 8f712db..4ae7377 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1220,7 +1220,7 @@
void setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
// FIXME enum is faster than strcmp() for parameter 'from'
- status_t restoreTrack_l(const char *from);
+ status_t restoreTrack_l(const char *from, bool forceRestore = false);
uint32_t getUnderrunCount_l() const;
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 5b90158..a8c8010 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -133,6 +133,10 @@
"libaudioutils",
],
data: ["bbb*.raw"],
+ srcs: [
+ "audio_test_utils.cpp",
+ "test_execution_tracer.cpp",
+ ],
test_config_template: "audio_test_template.xml",
}
@@ -141,7 +145,6 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: [
"audiorecord_tests.cpp",
- "audio_test_utils.cpp",
],
}
@@ -150,7 +153,6 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: [
"audiotrack_tests.cpp",
- "audio_test_utils.cpp",
],
}
@@ -159,7 +161,6 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: [
"audioeffect_tests.cpp",
- "audio_test_utils.cpp",
],
}
@@ -172,7 +173,6 @@
],
srcs: [
"audioeffect_analyser.cpp",
- "audio_test_utils.cpp",
],
static_libs: [
"libpffft",
@@ -184,7 +184,6 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: [
"audiorouting_tests.cpp",
- "audio_test_utils.cpp",
],
}
@@ -193,14 +192,15 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: [
"audioclient_serialization_tests.cpp",
- "audio_test_utils.cpp",
],
}
cc_test {
name: "trackplayerbase_tests",
defaults: ["libaudioclient_gtests_defaults"],
- srcs: ["trackplayerbase_tests.cpp"],
+ srcs: [
+ "trackplayerbase_tests.cpp",
+ ],
}
cc_test {
@@ -208,6 +208,5 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: [
"audiosystem_tests.cpp",
- "audio_test_utils.cpp",
],
}
diff --git a/media/libaudioclient/tests/audio_test_utils.cpp b/media/libaudioclient/tests/audio_test_utils.cpp
index ee5489b..9a202cc3 100644
--- a/media/libaudioclient/tests/audio_test_utils.cpp
+++ b/media/libaudioclient/tests/audio_test_utils.cpp
@@ -565,12 +565,14 @@
int attempts = 5;
status_t status;
unsigned int generation1, generation;
- unsigned int numPorts = 0;
+ unsigned int numPorts;
do {
if (attempts-- < 0) {
status = TIMED_OUT;
break;
}
+ // query for number of ports.
+ numPorts = 0;
status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_NONE, &numPorts,
nullptr, &generation1);
if (status != NO_ERROR) {
@@ -622,12 +624,14 @@
int attempts = 5;
status_t status;
unsigned int generation1, generation;
- unsigned int numPatches = 0;
+ unsigned int numPatches;
do {
if (attempts-- < 0) {
status = TIMED_OUT;
break;
}
+ // query for number of patches.
+ numPatches = 0;
status = AudioSystem::listAudioPatches(&numPatches, nullptr, &generation1);
if (status != NO_ERROR) {
ALOGE("AudioSystem::listAudioPatches returned error %d", status);
diff --git a/media/libaudioclient/tests/audioclient_serialization_tests.cpp b/media/libaudioclient/tests/audioclient_serialization_tests.cpp
index 707b9b3..5debabc 100644
--- a/media/libaudioclient/tests/audioclient_serialization_tests.cpp
+++ b/media/libaudioclient/tests/audioclient_serialization_tests.cpp
@@ -15,18 +15,23 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "AudioClientSerializationUnitTests"
+#define LOG_TAG "AudioClientSerializationTests"
#include <cstdint>
#include <cstdlib>
#include <ctime>
-
-#include <gtest/gtest.h>
+#include <vector>
#include <android_audio_policy_configuration_V7_0-enums.h>
+#include <gtest/gtest.h>
+#include <media/AudioPolicy.h>
+#include <media/AudioProductStrategy.h>
+#include <media/AudioVolumeGroup.h>
+#include <media/VolumeGroupAttributes.h>
+#include <system/audio.h>
#include <xsdc/XsdcSupport.h>
-#include "audio_test_utils.h"
+#include "test_execution_tracer.h"
using namespace android;
namespace xsd {
@@ -310,3 +315,9 @@
// audioStream
INSTANTIATE_TEST_SUITE_P(SerializationParameterizedTests, AudioAttributesParameterizedTest,
::testing::Combine(testing::ValuesIn(kStreamtypes)));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libaudioclient/tests/audioeffect_analyser.cpp b/media/libaudioclient/tests/audioeffect_analyser.cpp
index 94accae..f4d37bc 100644
--- a/media/libaudioclient/tests/audioeffect_analyser.cpp
+++ b/media/libaudioclient/tests/audioeffect_analyser.cpp
@@ -14,23 +14,26 @@
* limitations under the License.
*/
-// #define LOG_NDEBUG 0
-#define LOG_TAG "AudioEffectAnalyser"
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-#include <media/AudioEffect.h>
-#include <system/audio_effects/effect_bassboost.h>
-#include <system/audio_effects/effect_equalizer.h>
#include <fstream>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
+// #define LOG_NDEBUG 0
+#define LOG_TAG "AudioEffectAnalyser"
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <media/AudioEffect.h>
+#include <system/audio_effects/effect_bassboost.h>
+#include <system/audio_effects/effect_equalizer.h>
+
#include "audio_test_utils.h"
#include "pffft.hpp"
+#include "test_execution_tracer.h"
#define CHECK_OK(expr, msg) \
mStatus = (expr); \
@@ -417,3 +420,10 @@
prevGain = diffB;
}
}
+
+int main(int argc, char** argv) {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libaudioclient/tests/audioeffect_tests.cpp b/media/libaudioclient/tests/audioeffect_tests.cpp
index e12ae23..59d0c6a 100644
--- a/media/libaudioclient/tests/audioeffect_tests.cpp
+++ b/media/libaudioclient/tests/audioeffect_tests.cpp
@@ -15,8 +15,9 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "AudioEffectUnitTests"
+#define LOG_TAG "AudioEffectTests"
+#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <media/AudioEffect.h>
#include <system/audio_effects/effect_hapticgenerator.h>
@@ -24,6 +25,7 @@
#include <system/audio_effects/effect_visualizer.h>
#include "audio_test_utils.h"
+#include "test_execution_tracer.h"
using namespace android;
@@ -563,3 +565,10 @@
EXPECT_TRUE(cb->receivedFramesProcessed)
<< "AudioEffect frames processed callback not received";
}
+
+int main(int argc, char** argv) {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libaudioclient/tests/audiorecord_tests.cpp b/media/libaudioclient/tests/audiorecord_tests.cpp
index 61edd4d..0bf2e82 100644
--- a/media/libaudioclient/tests/audiorecord_tests.cpp
+++ b/media/libaudioclient/tests/audiorecord_tests.cpp
@@ -24,6 +24,7 @@
#include <gtest/gtest.h>
#include "audio_test_utils.h"
+#include "test_execution_tracer.h"
using namespace android;
@@ -261,26 +262,6 @@
AUDIO_SOURCE_UNPROCESSED)),
GetRecordTestName);
-namespace {
-
-class TestExecutionTracer : public ::testing::EmptyTestEventListener {
- public:
- void OnTestStart(const ::testing::TestInfo& test_info) override {
- TraceTestState("Started", test_info);
- }
- void OnTestEnd(const ::testing::TestInfo& test_info) override {
- TraceTestState("Finished", test_info);
- }
- void OnTestPartResult(const ::testing::TestPartResult& result) override { LOG(INFO) << result; }
-
- private:
- static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
- LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
- }
-};
-
-} // namespace
-
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index fa990b5..764011b 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -17,13 +17,12 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioRoutingTest"
-#include <string.h>
-
#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
#include "audio_test_utils.h"
+#include "test_execution_tracer.h"
using namespace android;
@@ -267,21 +266,6 @@
playback->stop();
}
-class TestExecutionTracer : public ::testing::EmptyTestEventListener {
- public:
- void OnTestStart(const ::testing::TestInfo& test_info) override {
- TraceTestState("Started", test_info);
- }
- void OnTestEnd(const ::testing::TestInfo& test_info) override {
- TraceTestState("Completed", test_info);
- }
-
- private:
- static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
- ALOGI("%s %s::%s", state.c_str(), test_info.test_suite_name(), test_info.name());
- }
-};
-
int main(int argc, char** argv) {
android::ProcessState::self()->startThreadPool();
::testing::InitGoogleTest(&argc, argv);
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index d9789f1..03c15f4 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-#define LOG_TAG "AudioSystemTest"
-
#include <string.h>
#include <set>
+#define LOG_TAG "AudioSystemTest"
+
#include <gtest/gtest.h>
#include <log/log.h>
#include <media/AidlConversionCppNdk.h>
#include <media/IAudioFlinger.h>
#include "audio_test_utils.h"
+#include "test_execution_tracer.h"
using android::media::audio::common::AudioDeviceAddress;
using android::media::audio::common::AudioDeviceDescription;
@@ -706,21 +707,6 @@
}
}
-class TestExecutionTracer : public ::testing::EmptyTestEventListener {
- public:
- void OnTestStart(const ::testing::TestInfo& test_info) override {
- TraceTestState("Started", test_info);
- }
- void OnTestEnd(const ::testing::TestInfo& test_info) override {
- TraceTestState("Completed", test_info);
- }
-
- private:
- static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
- ALOGI("%s %s::%s", state.c_str(), test_info.test_suite_name(), test_info.name());
- }
-};
-
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
diff --git a/media/libaudioclient/tests/audiotrack_tests.cpp b/media/libaudioclient/tests/audiotrack_tests.cpp
index 2b68225..0282bd7 100644
--- a/media/libaudioclient/tests/audiotrack_tests.cpp
+++ b/media/libaudioclient/tests/audiotrack_tests.cpp
@@ -15,10 +15,13 @@
*/
//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioTrackTests"
+#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include "audio_test_utils.h"
+#include "test_execution_tracer.h"
using namespace android;
@@ -209,3 +212,10 @@
AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_FAST,
AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
::testing::Values(AUDIO_SESSION_NONE)));
+
+int main(int argc, char** argv) {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libaudioclient/tests/test_execution_tracer.cpp b/media/libaudioclient/tests/test_execution_tracer.cpp
new file mode 100644
index 0000000..797bb4b
--- /dev/null
+++ b/media/libaudioclient/tests/test_execution_tracer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 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_TAG "TestExecutionTracer"
+
+#include "test_execution_tracer.h"
+
+#include <android-base/logging.h>
+
+void TestExecutionTracer::OnTestStart(const ::testing::TestInfo& test_info) {
+ TraceTestState("Started", test_info);
+}
+
+void TestExecutionTracer::OnTestEnd(const ::testing::TestInfo& test_info) {
+ TraceTestState("Finished", test_info);
+}
+
+void TestExecutionTracer::OnTestPartResult(const ::testing::TestPartResult& result) {
+ if (result.failed()) {
+ LOG(ERROR) << result;
+ } else {
+ LOG(INFO) << result;
+ }
+}
+
+// static
+void TestExecutionTracer::TraceTestState(const std::string& state,
+ const ::testing::TestInfo& test_info) {
+ LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+}
diff --git a/media/libaudioclient/tests/test_execution_tracer.h b/media/libaudioclient/tests/test_execution_tracer.h
new file mode 100644
index 0000000..9031aaf
--- /dev/null
+++ b/media/libaudioclient/tests/test_execution_tracer.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <gtest/gtest.h>
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const ::testing::TestInfo& test_info) override;
+ void OnTestEnd(const ::testing::TestInfo& test_info) override;
+ void OnTestPartResult(const ::testing::TestPartResult& result) override;
+
+ private:
+ static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info);
+};
diff --git a/media/libaudioclient/tests/trackplayerbase_tests.cpp b/media/libaudioclient/tests/trackplayerbase_tests.cpp
index c9b704d..7317bf0 100644
--- a/media/libaudioclient/tests/trackplayerbase_tests.cpp
+++ b/media/libaudioclient/tests/trackplayerbase_tests.cpp
@@ -16,10 +16,12 @@
#define LOG_TAG "TrackPlayerBaseTest"
+#include <binder/ProcessState.h>
#include <gtest/gtest.h>
-
#include <media/TrackPlayerBase.h>
+#include "test_execution_tracer.h"
+
using namespace android;
using namespace android::media;
@@ -159,3 +161,10 @@
INSTANTIATE_TEST_SUITE_P(TrackPlayerTest, PauseTestParam,
::testing::Values(std::make_tuple(1.0, 75.0, 2, 24000)));
+
+int main(int argc, char** argv) {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
index ae0457f..6dbf284 100644
--- a/media/libaudiofoundation/AudioPort.cpp
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -192,7 +192,8 @@
dst->append(
base::StringPrintf("%*s extra audio descriptor %zu:\n", eadSpaces, "", i));
dst->append(base::StringPrintf(
- "%*s- standard: %u\n", descSpaces, "", mExtraAudioDescriptors[i].standard));
+ "%*s- standard: %u\n", descSpaces, "",
+ static_cast<unsigned>(mExtraAudioDescriptors[i].standard)));
dst->append(base::StringPrintf("%*s- descriptor:", descSpaces, ""));
for (auto v : mExtraAudioDescriptors[i].audioDescriptor) {
dst->append(base::StringPrintf(" %02x", v));
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 3c05b0b..b8d0998 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -23,7 +23,6 @@
],
required: [
- "libaudiohal@4.0",
"libaudiohal@5.0",
"libaudiohal@6.0",
"libaudiohal@7.0",
diff --git a/media/libaudiohal/FactoryHal.cpp b/media/libaudiohal/FactoryHal.cpp
index c414e19..15cb297 100644
--- a/media/libaudiohal/FactoryHal.cpp
+++ b/media/libaudiohal/FactoryHal.cpp
@@ -50,13 +50,12 @@
* This list need to keep sync with AudioHalVersionInfo.VERSIONS in
* media/java/android/media/AudioHalVersionInfo.java.
*/
-static const std::array<AudioHalVersionInfo, 6> sAudioHALVersions = {
+static const std::array<AudioHalVersionInfo, 5> sAudioHALVersions = {
AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, 1, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 1),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 6, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 5, 0),
- AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 4, 0),
};
static const std::map<AudioHalVersionInfo::Type, InterfaceName> sDevicesHALInterfaces = {
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index fb1cc34..4d81f77 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -41,7 +41,7 @@
],
header_libs: [
"android.hardware.audio.common.util@all-versions",
- ]
+ ],
}
cc_defaults {
@@ -71,7 +71,7 @@
],
header_libs: [
"libaudioclient_headers",
- "libaudiohal_headers"
+ "libaudiohal_headers",
],
defaults: [
"latest_android_media_audio_common_types_cpp_export_shared",
@@ -83,36 +83,10 @@
}
cc_library_shared {
- name: "libaudiohal@4.0",
- defaults: [
- "libaudiohal_default",
- "libaudiohal_hidl_default"
- ],
- srcs: [
- ":audio_core_hal_client_sources",
- ":audio_effect_hidl_hal_client_sources",
- "EffectsFactoryHalEntry.cpp",
- ],
- shared_libs: [
- "android.hardware.audio.common@4.0",
- "android.hardware.audio.common@4.0-util",
- "android.hardware.audio.effect@4.0",
- "android.hardware.audio.effect@4.0-util",
- "android.hardware.audio@4.0",
- "android.hardware.audio@4.0-util",
- ],
- cflags: [
- "-DMAJOR_VERSION=4",
- "-DMINOR_VERSION=0",
- "-include common/all-versions/VersionMacro.h",
- ]
-}
-
-cc_library_shared {
name: "libaudiohal@5.0",
defaults: [
"libaudiohal_default",
- "libaudiohal_hidl_default"
+ "libaudiohal_hidl_default",
],
srcs: [
":audio_core_hal_client_sources",
@@ -131,14 +105,14 @@
"-DMAJOR_VERSION=5",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_library_shared {
name: "libaudiohal@6.0",
defaults: [
"libaudiohal_default",
- "libaudiohal_hidl_default"
+ "libaudiohal_hidl_default",
],
srcs: [
":audio_core_hal_client_sources",
@@ -157,14 +131,14 @@
"-DMAJOR_VERSION=6",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_library_static {
name: "libaudiohal.effect@7.0",
defaults: [
"libaudiohal_default",
- "libaudiohal_hidl_default"
+ "libaudiohal_hidl_default",
],
srcs: [
":audio_effect_hidl_hal_client_sources",
@@ -179,14 +153,14 @@
"-DMAJOR_VERSION=7",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_library_shared {
name: "libaudiohal@7.0",
defaults: [
"libaudiohal_default",
- "libaudiohal_hidl_default"
+ "libaudiohal_hidl_default",
],
srcs: [
":audio_core_hal_client_sources",
@@ -206,7 +180,7 @@
"-DMAJOR_VERSION=7",
"-DMINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_library_shared {
@@ -215,7 +189,7 @@
"latest_android_hardware_audio_core_sounddose_ndk_shared",
"latest_android_hardware_audio_sounddose_ndk_shared",
"libaudiohal_default",
- "libaudiohal_hidl_default"
+ "libaudiohal_hidl_default",
],
srcs: [
":audio_core_hal_client_sources",
@@ -242,7 +216,7 @@
"-DCOMMON_TYPES_MINOR_VERSION=0",
"-DCORE_TYPES_MINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
- ]
+ ],
}
cc_defaults {
@@ -257,7 +231,7 @@
shared_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
- "av-audio-types-aidl-ndk",
+ "av-audio-types-aidl-V1-ndk",
"libaudio_aidl_conversion_common_cpp",
"libaudio_aidl_conversion_common_ndk",
"libaudio_aidl_conversion_common_ndk_cpp",
@@ -287,9 +261,30 @@
],
srcs: [
"DevicesFactoryHalEntry.cpp",
+ "EffectsFactoryHalEntry.cpp",
+ ":audio_effect_hal_aidl_src_files",
+ ":core_audio_hal_aidl_src_files",
+ ],
+}
+
+filegroup {
+ name: "core_audio_hal_aidl_src_files",
+ srcs: [
+ "ConversionHelperAidl.cpp",
+ "DeviceHalAidl.cpp",
+ "DevicesFactoryHalAidl.cpp",
+ "Hal2AidlMapper.cpp",
+ "StreamHalAidl.cpp",
+ ],
+}
+
+filegroup {
+ name: "audio_effect_hal_aidl_src_files",
+ srcs: [
"EffectConversionHelperAidl.cpp",
"EffectBufferHalAidl.cpp",
"EffectHalAidl.cpp",
+ "EffectsFactoryHalAidl.cpp",
"effectsAidlConversion/AidlConversionAec.cpp",
"effectsAidlConversion/AidlConversionAgc1.cpp",
"effectsAidlConversion/AidlConversionAgc2.cpp",
@@ -306,21 +301,7 @@
"effectsAidlConversion/AidlConversionVendorExtension.cpp",
"effectsAidlConversion/AidlConversionVirtualizer.cpp",
"effectsAidlConversion/AidlConversionVisualizer.cpp",
- "EffectsFactoryHalAidl.cpp",
- "EffectsFactoryHalEntry.cpp",
":audio_effectproxy_src_files",
- ":core_audio_hal_aidl_src_files",
- ],
-}
-
-filegroup {
- name: "core_audio_hal_aidl_src_files",
- srcs: [
- "ConversionHelperAidl.cpp",
- "DeviceHalAidl.cpp",
- "DevicesFactoryHalAidl.cpp",
- "Hal2AidlMapper.cpp",
- "StreamHalAidl.cpp",
],
}
diff --git a/media/libaudiohal/impl/ConversionHelperAidl.cpp b/media/libaudiohal/impl/ConversionHelperAidl.cpp
index 46abfda..7a32811 100644
--- a/media/libaudiohal/impl/ConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/ConversionHelperAidl.cpp
@@ -37,10 +37,6 @@
using ParameterScope = IHalAdapterVendorExtension::ParameterScope;
if (parameterKeys.size() == 0) return OK;
const String8 rawKeys = parameterKeys.keysToString();
- if (vendorExt == nullptr) {
- ALOGW("%s: unknown parameters, ignored: \"%s\"", __func__, rawKeys.c_str());
- return OK;
- }
std::vector<std::string> parameterIds;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(vendorExt->parseVendorParameterIds(
@@ -85,10 +81,6 @@
using ParameterScope = IHalAdapterVendorExtension::ParameterScope;
if (parameters.size() == 0) return OK;
const String8 rawKeysAndValues = parameters.toString();
- if (vendorExt == nullptr) {
- ALOGW("%s: unknown parameters, ignored: \"%s\"", __func__, rawKeysAndValues.c_str());
- return OK;
- }
std::vector<VendorParameter> syncParameters, asyncParameters;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(vendorExt->parseVendorParameters(
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 2af18cc..af06581 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -271,15 +271,16 @@
return parseAndGetVendorParameters(mVendorExt, mModule, parameterKeys, values);
}
-status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
+status_t DeviceHalAidl::getInputBufferSize(struct audio_config* config, size_t* size) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (mModule == nullptr) return NO_INIT;
if (config == nullptr || size == nullptr) {
return BAD_VALUE;
}
+ constexpr bool isInput = true;
AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
+ ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, isInput));
AudioDevice aidlDevice;
aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
AudioSource aidlSource = AudioSource::DEFAULT;
@@ -293,6 +294,9 @@
0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
&cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
}
+ *config = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
+ if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
*size = aidlConfig.frameCount *
getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
// Do not disarm cleanups to release temporary port configs.
@@ -398,8 +402,7 @@
*static_cast<StreamCallbackBase*>(this)),
StreamCallbackBaseHelper<StreamOutHalInterfaceLatencyModeCallback>(
*static_cast<StreamCallbackBase*>(this)) {}
- ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& in_audioMetadata) override {
- std::basic_string<uint8_t> halMetadata(in_audioMetadata.begin(), in_audioMetadata.end());
+ ndk::ScopedAStatus onCodecFormatChanged(const std::vector<uint8_t>& halMetadata) override {
return StreamCallbackBaseHelper<StreamOutHalInterfaceEventCallback>::runCb(
[&halMetadata](auto cb) { cb->onCodecFormatChanged(halMetadata); });
}
@@ -1024,15 +1027,11 @@
(void)VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<String8>(
parameters, String8(AudioParameter::keyReconfigA2dp),
[&](const String8& value) -> status_t {
- if (mVendorExt != nullptr) {
- std::vector<VendorParameter> result;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
- mVendorExt->parseBluetoothA2dpReconfigureOffload(
- std::string(value.c_str()), &result)));
- reconfigureOffload = std::move(result);
- } else {
- reconfigureOffload = std::vector<VendorParameter>();
- }
+ std::vector<VendorParameter> result;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mVendorExt->parseBluetoothA2dpReconfigureOffload(
+ std::string(value.c_str()), &result)));
+ reconfigureOffload = std::move(result);
return OK;
}));
if (mBluetoothA2dp != nullptr && a2dpEnabled.has_value()) {
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 9493e47..6f8afe5 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -113,7 +113,7 @@
status_t getParameters(const String8& keys, String8 *values) override;
// Returns audio input buffer size according to parameters passed.
- status_t getInputBufferSize(const struct audio_config* config, size_t* size) override;
+ status_t getInputBufferSize(struct audio_config* config, size_t* size) override;
// Creates and opens the audio hardware output stream. The stream is closed
// by releasing all references to the returned object.
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index e8e1f46..478e0f0 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -236,7 +236,7 @@
}
status_t DeviceHalHidl::getInputBufferSize(
- const struct audio_config *config, size_t *size) {
+ struct audio_config *config, size_t *size) {
TIME_CHECK();
if (mDevice == 0) return NO_INIT;
AudioConfig hidlConfig;
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 7a712df..1362dab 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -67,7 +67,7 @@
status_t getParameters(const String8& keys, String8 *values) override;
// Returns audio input buffer size according to parameters passed.
- status_t getInputBufferSize(const struct audio_config* config, size_t* size) override;
+ status_t getInputBufferSize(struct audio_config* config, size_t* size) override;
// Creates and opens the audio hardware output stream. The stream is closed
// by releasing all references to the returned object.
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
index 3dbc14a..347afa6 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
@@ -17,13 +17,16 @@
#include <algorithm>
#include <map>
#include <memory>
+#include <mutex>
#include <string>
#define LOG_TAG "DevicesFactoryHalAidl"
//#define LOG_NDEBUG 0
#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/media/audio/BnHalAdapterVendorExtension.h>
#include <android/binder_manager.h>
+#include <cutils/properties.h>
#include <media/AidlConversionNdkCpp.h>
#include <media/AidlConversionUtil.h>
#include <utils/Log.h>
@@ -35,6 +38,7 @@
using aidl::android::hardware::audio::core::IConfig;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::SurroundSoundConfig;
+using aidl::android::hardware::audio::core::VendorParameter;
using aidl::android::media::audio::common::AudioHalEngineConfig;
using aidl::android::media::audio::IHalAdapterVendorExtension;
using android::detail::AudioHalVersionInfo;
@@ -62,10 +66,84 @@
return cpp;
}
+class HalAdapterVendorExtensionWrapper :
+ public ::aidl::android::media::audio::BnHalAdapterVendorExtension {
+ private:
+ template<typename F>
+ ndk::ScopedAStatus callWithRetryOnCrash(F method) {
+ ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
+ for (auto service = getService(); service != nullptr; service = getService(true)) {
+ status = method(service);
+ if (status.getStatus() != STATUS_DEAD_OBJECT) break;
+ }
+ return status;
+ }
+
+ ndk::ScopedAStatus parseVendorParameterIds(ParameterScope in_scope,
+ const std::string& in_rawKeys,
+ std::vector<std::string>* _aidl_return) override {
+ return callWithRetryOnCrash([&](auto service) {
+ return service->parseVendorParameterIds(in_scope, in_rawKeys, _aidl_return);
+ });
+ }
+
+ ndk::ScopedAStatus parseVendorParameters(
+ ParameterScope in_scope, const std::string& in_rawKeysAndValues,
+ std::vector<VendorParameter>* out_syncParameters,
+ std::vector<VendorParameter>* out_asyncParameters) override {
+ return callWithRetryOnCrash([&](auto service) {
+ return service->parseVendorParameters(in_scope, in_rawKeysAndValues,
+ out_syncParameters, out_asyncParameters);
+ });
+ }
+
+ ndk::ScopedAStatus parseBluetoothA2dpReconfigureOffload(
+ const std::string& in_rawValue, std::vector<VendorParameter>* _aidl_return) override {
+ return callWithRetryOnCrash([&](auto service) {
+ return service->parseBluetoothA2dpReconfigureOffload(in_rawValue, _aidl_return);
+ });
+ }
+
+ ndk::ScopedAStatus parseBluetoothLeReconfigureOffload(const std::string& in_rawValue,
+ std::vector<VendorParameter>* _aidl_return) override {
+ return callWithRetryOnCrash([&](auto service) {
+ return service->parseBluetoothLeReconfigureOffload(in_rawValue, _aidl_return);
+ });
+ }
+
+ ndk::ScopedAStatus processVendorParameters(ParameterScope in_scope,
+ const std::vector<VendorParameter>& in_parameters,
+ std::string* _aidl_return) override {
+ return callWithRetryOnCrash([&](auto service) {
+ return service->processVendorParameters(in_scope, in_parameters, _aidl_return);
+ });
+ }
+
+ std::shared_ptr<IHalAdapterVendorExtension> getService(bool reset = false) {
+ std::lock_guard l(mLock);
+ if (reset || !mVendorExt.has_value()) {
+ if (property_get_bool("ro.audio.ihaladaptervendorextension_enabled", false)) {
+ auto serviceName = std::string(IHalAdapterVendorExtension::descriptor) + "/default";
+ mVendorExt = std::shared_ptr<IHalAdapterVendorExtension>(
+ IHalAdapterVendorExtension::fromBinder(ndk::SpAIBinder(
+ AServiceManager_waitForService(serviceName.c_str()))));
+ } else {
+ mVendorExt = nullptr;
+ }
+ }
+ return mVendorExt.value();
+ }
+
+ std::mutex mLock;
+ std::optional<std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension>>
+ mVendorExt GUARDED_BY(mLock);
+};
+
} // namespace
DevicesFactoryHalAidl::DevicesFactoryHalAidl(std::shared_ptr<IConfig> config)
- : mConfig(std::move(config)) {
+ : mConfig(std::move(config)),
+ mVendorExt(ndk::SharedRefBase::make<HalAdapterVendorExtensionWrapper>()) {
}
status_t DevicesFactoryHalAidl::getDeviceNames(std::vector<std::string> *names) {
@@ -110,7 +188,7 @@
ALOGE("%s fromBinder %s failed", __func__, serviceName.c_str());
return NO_INIT;
}
- *device = sp<DeviceHalAidl>::make(name, service, getVendorExtension());
+ *device = sp<DeviceHalAidl>::make(name, service, mVendorExt);
return OK;
}
@@ -149,20 +227,6 @@
return OK;
}
-std::shared_ptr<IHalAdapterVendorExtension> DevicesFactoryHalAidl::getVendorExtension() {
- if (!mVendorExt.has_value()) {
- auto serviceName = std::string(IHalAdapterVendorExtension::descriptor) + "/default";
- if (AServiceManager_isDeclared(serviceName.c_str())) {
- mVendorExt = std::shared_ptr<IHalAdapterVendorExtension>(
- IHalAdapterVendorExtension::fromBinder(ndk::SpAIBinder(
- AServiceManager_waitForService(serviceName.c_str()))));
- } else {
- mVendorExt = nullptr;
- }
- }
- return mVendorExt.value();
-}
-
// Main entry-point to the shared library.
extern "C" __attribute__((visibility("default"))) void* createIDevicesFactoryImpl() {
auto serviceName = std::string(IConfig::descriptor) + "/default";
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.h b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
index 17bfe43..2a3a9e7 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
@@ -45,10 +45,7 @@
private:
const std::shared_ptr<::aidl::android::hardware::audio::core::IConfig> mConfig;
- std::optional<std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension>>
- mVendorExt;
-
- std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> getVendorExtension();
+ const std::shared_ptr<::aidl::android::media::audio::IHalAdapterVendorExtension> mVendorExt;
~DevicesFactoryHalAidl() = default;
};
diff --git a/media/libaudiohal/impl/EffectBufferHalAidl.cpp b/media/libaudiohal/impl/EffectBufferHalAidl.cpp
index a701852..33fe3ed 100644
--- a/media/libaudiohal/impl/EffectBufferHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectBufferHalAidl.cpp
@@ -58,25 +58,14 @@
}
EffectBufferHalAidl::~EffectBufferHalAidl() {
+ if (mAudioBuffer.raw) free(mAudioBuffer.raw);
}
status_t EffectBufferHalAidl::init() {
- int fd = ashmem_create_region("audioEffectAidl", mBufferSize);
- if (fd < 0) {
- ALOGE("%s create ashmem failed %d", __func__, fd);
- return fd;
+ if (0 != posix_memalign(&mAudioBuffer.raw, 32, mBufferSize)) {
+ return NO_MEMORY;
}
- ScopedFileDescriptor tempFd(fd);
- mAudioBuffer.raw = mmap(nullptr /* address */, mBufferSize /* length */, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0 /* offset */);
- if (mAudioBuffer.raw == MAP_FAILED) {
- ALOGE("mmap failed for fd %d", fd);
- mAudioBuffer.raw = nullptr;
- return INVALID_OPERATION;
- }
-
- mMemory = {std::move(tempFd), static_cast<int64_t>(mBufferSize)};
return OK;
}
diff --git a/media/libaudiohal/impl/EffectBufferHalAidl.h b/media/libaudiohal/impl/EffectBufferHalAidl.h
index 035314b..cf6031f 100644
--- a/media/libaudiohal/impl/EffectBufferHalAidl.h
+++ b/media/libaudiohal/impl/EffectBufferHalAidl.h
@@ -50,7 +50,6 @@
const size_t mBufferSize;
bool mFrameCountChanged;
void* mExternalData;
- aidl::android::hardware::common::Ashmem mMemory;
audio_buffer_t mAudioBuffer;
// Can not be constructed directly by clients.
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 39999a5..e1a82f8 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -187,13 +187,7 @@
IEffect::OpenEffectReturn openReturn;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn)));
- updateMqs(openReturn);
-
- if (status_t status = updateEventFlags(); status != OK) {
- ALOGV("%s closing at status %d", __func__, status);
- mEffect->close();
- return status;
- }
+ updateMqsAndEventFlags(openReturn);
} else if (mCommon != common) {
ALOGI("%s at state %s, setParameter", __func__, android::internal::ToString(state).c_str());
Parameter aidlParam = UNION_MAKE(Parameter, common, common);
@@ -204,13 +198,21 @@
return *static_cast<int32_t*>(pReplyData) = OK;
}
-void EffectConversionHelperAidl::updateMqs(const IEffect::OpenEffectReturn& ret) {
+void EffectConversionHelperAidl::updateMqsAndEventFlags(const IEffect::OpenEffectReturn& ret) {
if (mIsProxyEffect) {
mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
+ } else {
+ mStatusQ = std::make_shared<StatusMQ>(ret.statusMQ);
+ }
+ updateEventFlags();
+ updateDataMqs(ret);
+}
+
+void EffectConversionHelperAidl::updateDataMqs(const IEffect::OpenEffectReturn& ret) {
+ if (mIsProxyEffect) {
mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
} else {
- mStatusQ = std::make_shared<StatusMQ>(ret.statusMQ);
mInputQ = std::make_shared<DataMQ>(ret.inputDataMQ);
mOutputQ = std::make_shared<DataMQ>(ret.outputDataMQ);
}
@@ -407,10 +409,8 @@
}
// update FMQs if the effect instance already open
if (State state; effectProxy->getState(&state).isOk() && state != State::INIT) {
- mStatusQ = effectProxy->getStatusMQ();
- mInputQ = effectProxy->getInputMQ();
- mOutputQ = effectProxy->getOutputMQ();
- updateEventFlags();
+ IEffect::OpenEffectReturn openReturn;
+ updateMqsAndEventFlags(openReturn);
}
}
return *static_cast<int32_t*>(pReplyData) = OK;
@@ -512,7 +512,8 @@
IEffect::OpenEffectReturn openReturn;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->reopen(&openReturn)));
- updateMqs(openReturn);
+ // status MQ won't be changed after open
+ updateDataMqs(openReturn);
return OK;
}
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 8b9efb3..0c0184e 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -69,9 +69,6 @@
void* pReplyData);
private:
- const aidl::android::media::audio::common::AudioFormatDescription kDefaultFormatDescription = {
- .type = aidl::android::media::audio::common::AudioFormatType::PCM,
- .pcm = aidl::android::media::audio::common::PcmType::FLOAT_32_BIT};
const bool mIsProxyEffect;
static constexpr int kDefaultframeCount = 0x100;
@@ -81,13 +78,16 @@
return pt ? std::to_string(*pt) : "nullptr";
}
- using AudioChannelLayout = aidl::android::media::audio::common::AudioChannelLayout;
const aidl::android::media::audio::common::AudioConfig kDefaultAudioConfig = {
.base = {.sampleRate = 44100,
- .channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
- AudioChannelLayout::LAYOUT_STEREO),
- .format = kDefaultFormatDescription},
+ .channelMask = aidl::android::media::audio::common::AudioChannelLayout::make<
+ aidl::android::media::audio::common::AudioChannelLayout::layoutMask>(
+ aidl::android::media::audio::common::AudioChannelLayout::
+ LAYOUT_STEREO),
+ .format = {.type = aidl::android::media::audio::common::AudioFormatType::PCM,
+ .pcm = aidl::android::media::audio::common::PcmType::FLOAT_32_BIT}},
.frameCount = kDefaultframeCount};
+
// command handler map
typedef status_t (EffectConversionHelperAidl::*CommandHandler)(uint32_t /* cmdSize */,
const void* /* pCmdData */,
@@ -98,7 +98,6 @@
std::shared_ptr<StatusMQ> mStatusQ = nullptr;
std::shared_ptr<DataMQ> mInputQ = nullptr, mOutputQ = nullptr;
-
struct EventFlagDeleter {
void operator()(::android::hardware::EventFlag* flag) const {
if (flag) {
@@ -108,8 +107,10 @@
};
std::shared_ptr<android::hardware::EventFlag> mEfGroup = nullptr;
status_t updateEventFlags();
-
- void updateMqs(const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn& ret);
+ void updateDataMqs(
+ const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn& ret);
+ void updateMqsAndEventFlags(
+ const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn& ret);
status_t handleInit(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
void* pReplyData);
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index 2836727..ebda86a 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -57,20 +57,22 @@
using ::aidl::android::hardware::audio::effect::IEffect;
using ::aidl::android::hardware::audio::effect::IFactory;
using ::aidl::android::hardware::audio::effect::kEventFlagDataMqUpdate;
+using ::aidl::android::hardware::audio::effect::kReopenSupportedVersion;
using ::aidl::android::hardware::audio::effect::State;
namespace android {
namespace effect {
EffectHalAidl::EffectHalAidl(const std::shared_ptr<IFactory>& factory,
- const std::shared_ptr<IEffect>& effect,
- int32_t sessionId, int32_t ioId, const Descriptor& desc,
- bool isProxyEffect)
+ const std::shared_ptr<IEffect>& effect, int32_t sessionId,
+ int32_t ioId, const Descriptor& desc, bool isProxyEffect)
: mFactory(factory),
mEffect(effect),
mSessionId(sessionId),
mIoId(ioId),
mIsProxyEffect(isProxyEffect) {
+ assert(mFactory != nullptr);
+ assert(mEffect != nullptr);
createAidlConversion(effect, sessionId, ioId, desc);
}
@@ -184,10 +186,18 @@
return INVALID_OPERATION;
}
- if (uint32_t efState = 0;
- ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState, 1 /* ns */,
- true /* retry */)) {
- ALOGI("%s %s receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str());
+ // 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;
+ }();
+
+ if (uint32_t efState = 0; halVersion >= kReopenSupportedVersion &&
+ ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
+ 1 /* ns */, true /* retry */) &&
+ efState & kEventFlagDataMqUpdate) {
+ ALOGI("%s %s V%d receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str(),
+ halVersion);
mConversion->reopen();
}
auto statusQ = mConversion->getStatusMQ();
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 5f525d7..2a8ebc6 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -788,7 +788,7 @@
if (VALUE_OR_RETURN_STATUS(filterOutAndProcessParameter<int>(
parameters, String8(AudioParameter::keyOffloadCodecAverageBitRate),
[&](int value) {
- return value > 0 ?
+ return value >= 0 ?
mOffloadMetadata.averageBitRatePerSecond = value, OK : BAD_VALUE;
}))) {
updateMetadata = true;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index 72eadc6..77c75db 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -840,7 +840,7 @@
const android::hardware::hidl_vec<uint8_t>& audioMetadata) override {
sp<StreamOutHalHidl> stream = mStream.promote();
if (stream != nullptr) {
- std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
+ std::vector<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
stream->onCodecFormatChanged(metadataBs);
}
return Void();
@@ -967,7 +967,7 @@
callback->onError();
}
-void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
+void StreamOutHalHidl::onCodecFormatChanged(const std::vector<uint8_t>& metadataBs) {
sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
if (callback == nullptr) return;
ALOGV("asyncCodecFormatCallback %s", __func__);
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index 5361047..48da633 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -194,7 +194,7 @@
status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
// Methods used by StreamCodecFormatCallback (HIDL).
- void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+ void onCodecFormatChanged(const std::vector<uint8_t>& metadataBs);
status_t setLatencyMode(audio_latency_mode_t mode) override;
status_t getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) override;
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
index 49e6827..d1794f0 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
@@ -16,17 +16,17 @@
#include <cstdint>
#include <cstring>
-#include <optional>
#define LOG_TAG "AidlConversionSpatializer"
//#define LOG_NDEBUG 0
#include <aidl/android/hardware/audio/effect/DefaultExtension.h>
#include <aidl/android/hardware/audio/effect/VendorExtension.h>
#include <error/expected_utils.h>
-#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionCppNdk.h>
#include <media/AidlConversionEffect.h>
+#include <media/AidlConversionNdk.h>
+#include <system/audio_effects/aidl_effects_utils.h>
#include <system/audio_effects/effect_spatializer.h>
-
#include <utils/Log.h>
#include "AidlConversionSpatializer.h"
@@ -34,38 +34,321 @@
namespace android {
namespace effect {
-using ::aidl::android::aidl_utils::statusTFromBinderStatus;
-using ::aidl::android::hardware::audio::effect::DefaultExtension;
-using ::aidl::android::hardware::audio::effect::Parameter;
-using ::aidl::android::hardware::audio::effect::VendorExtension;
-using ::android::status_t;
+using aidl::android::getParameterSpecificField;
+using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::effect::DefaultExtension;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Range;
+using aidl::android::hardware::audio::effect::Spatializer;
+using aidl::android::hardware::audio::effect::VendorExtension;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::HeadTracking;
+using aidl::android::media::audio::common::Spatialization;
+using aidl::android::media::audio::common::toString;
+using android::status_t;
using utils::EffectParamReader;
using utils::EffectParamWriter;
+bool AidlConversionSpatializer::isSpatializerParameterSupported() {
+ return mIsSpatializerAidlParamSupported.value_or(
+ (mIsSpatializerAidlParamSupported =
+ [&]() {
+ ::aidl::android::hardware::audio::effect::Parameter aidlParam;
+ auto id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
+ Spatializer::vendor);
+ // No range defined in descriptor capability means no Spatializer AIDL
+ // implementation BAD_VALUE return from getParameter indicates the
+ // parameter is not supported by HAL
+ return mDesc.capability.range.getTag() == Range::spatializer &&
+ mEffect->getParameter(id, &aidlParam).getStatus() !=
+ android::BAD_VALUE;
+ }())
+ .value());
+}
+
status_t AidlConversionSpatializer::setParameter(EffectParamReader& param) {
- Parameter aidlParam = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_EffectParameterReader_Parameter(param));
+ Parameter aidlParam;
+ if (isSpatializerParameterSupported()) {
+ uint32_t command = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int8_t)) ||
+ OK != param.readFromParameter(&command)) {
+ ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ switch (command) {
+ case SPATIALIZER_PARAM_LEVEL: {
+ Spatialization::Level level = Spatialization::Level::NONE;
+ if (OK != param.readFromValue(&level)) {
+ ALOGE("%s invalid level value %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer,
+ spatializationLevel, level);
+ break;
+ }
+ case SPATIALIZER_PARAM_HEADTRACKING_MODE: {
+ HeadTracking::Mode mode = HeadTracking::Mode::DISABLED;
+ if (OK != param.readFromValue(&mode)) {
+ ALOGE("%s invalid mode value %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, headTrackingMode,
+ mode);
+ break;
+ }
+ case SPATIALIZER_PARAM_HEAD_TO_STAGE: {
+ const size_t valueSize = param.getValueSize();
+ if (valueSize / sizeof(float) > 6 || valueSize % sizeof(float) != 0) {
+ ALOGE("%s invalid parameter value size %zu", __func__, valueSize);
+ return BAD_VALUE;
+ }
+ std::array<float, 6> headToStage = {};
+ for (size_t i = 0; i < valueSize / sizeof(float); i++) {
+ if (OK != param.readFromValue(&headToStage[i])) {
+ ALOGE("%s failed to read headToStage from %s", __func__,
+ param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+ HeadTracking::SensorData sensorData =
+ HeadTracking::SensorData::make<HeadTracking::SensorData::headToStage>(
+ headToStage);
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer,
+ headTrackingSensorData, sensorData);
+ break;
+ }
+ case SPATIALIZER_PARAM_HEADTRACKING_CONNECTION: {
+ int32_t modeInt32 = 0;
+ int32_t sensorId = -1;
+ if (OK != param.readFromValue(&modeInt32) || OK != param.readFromValue(&sensorId)) {
+ ALOGE("%s %d invalid parameter value %s", __func__, __LINE__,
+ param.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ const auto mode = static_cast<HeadTracking::ConnectionMode>(modeInt32);
+ if (mode < *ndk::enum_range<HeadTracking::ConnectionMode>().begin() ||
+ mode > *ndk::enum_range<HeadTracking::ConnectionMode>().end()) {
+ ALOGE("%s %d invalid mode %d", __func__, __LINE__, modeInt32);
+ return BAD_VALUE;
+ }
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer,
+ headTrackingConnectionMode, mode);
+ if (status_t status = statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+ status != OK) {
+ ALOGE("%s failed to set headTrackingConnectionMode %s", __func__,
+ toString(mode).c_str());
+ return status;
+ }
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, headTrackingSensorId,
+ sensorId);
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+ }
+ default: {
+ ALOGE("%s %d invalid command %u", __func__, __LINE__, command);
+ return BAD_VALUE;
+ }
+ }
+ } else {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_EffectParameterReader_Parameter(param));
+ }
+
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
}
status_t AidlConversionSpatializer::getParameter(EffectParamWriter& param) {
- DefaultExtension defaultExt;
- // read parameters into DefaultExtension vector<uint8_t>
- defaultExt.bytes.resize(param.getParameterSize());
- if (OK != param.readFromParameter(defaultExt.bytes.data(), param.getParameterSize())) {
- ALOGE("%s invalid param %s", __func__, param.toString().c_str());
- param.setStatus(BAD_VALUE);
- return BAD_VALUE;
- }
+ if (isSpatializerParameterSupported()) {
+ uint32_t command = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int8_t)) ||
+ OK != param.readFromParameter(&command)) {
+ ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
+ return BAD_VALUE;
+ }
- VendorExtension idTag;
- idTag.extension.setParcelable(defaultExt);
- Parameter::Id id = UNION_MAKE(Parameter::Id, vendorEffectTag, idTag);
- Parameter aidlParam;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
- // copy the AIDL extension data back to effect_param_t
- return VALUE_OR_RETURN_STATUS(
- ::aidl::android::aidl2legacy_Parameter_EffectParameterWriter(aidlParam, param));
+ switch (command) {
+ case SPATIALIZER_PARAM_SUPPORTED_LEVELS: {
+ const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
+ mDesc.capability, Spatializer::spatializationLevel);
+ if (!range) {
+ return BAD_VALUE;
+ }
+ for (const auto level : ::ndk::enum_range<Spatialization::Level>()) {
+ const auto spatializer =
+ Spatializer::make<Spatializer::spatializationLevel>(level);
+ if (spatializer >= range->min && spatializer <= range->max) {
+ if (status_t status = param.writeToValue(&level); status != OK) {
+ ALOGI("%s %d: write level %s to value failed %d", __func__, __LINE__,
+ toString(level).c_str(), status);
+ return status;
+ }
+ }
+ }
+ return OK;
+ }
+ case SPATIALIZER_PARAM_LEVEL: {
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
+ Spatializer::spatializationLevel);
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ const auto level = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, Spatializer, spatializer, Spatializer::spatializationLevel,
+ Spatialization::Level));
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
+ return param.writeToValue(&level);
+ }
+ case SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED: {
+ const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
+ mDesc.capability, Spatializer::spatializationLevel);
+ if (!range) {
+ ALOGE("%s %d: range not defined for spatializationLevel", __func__, __LINE__);
+ return BAD_VALUE;
+ }
+ const auto& nonSupport = Spatializer::make<Spatializer::spatializationLevel>(
+ Spatialization::Level::NONE);
+ const bool support = (range->min > range->max ||
+ (range->min == nonSupport && range->max == nonSupport))
+ ? false
+ : true;
+ return param.writeToValue(&support);
+ }
+ case SPATIALIZER_PARAM_HEADTRACKING_MODE: {
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
+ Spatializer::headTrackingMode);
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, Spatializer, spatializer, Spatializer::headTrackingMode,
+ HeadTracking::Mode));
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
+ return param.writeToValue(&mode);
+ }
+ case SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS: {
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
+ Spatializer::supportedChannelLayout);
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ const auto& supportedLayouts = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, Spatializer, spatializer, Spatializer::supportedChannelLayout,
+ std::vector<AudioChannelLayout>));
+ for (const auto& layout : supportedLayouts) {
+ audio_channel_mask_t mask = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+ layout, false /* isInput */));
+ if (status_t status = param.writeToValue(&mask); status != OK) {
+ ALOGI("%s %d: write mask %s to value failed %d", __func__, __LINE__,
+ layout.toString().c_str(), status);
+ return status;
+ }
+ }
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
+ return OK;
+ }
+ case SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES: {
+ const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
+ mDesc.capability, Spatializer::spatializationMode);
+ if (!range) {
+ return BAD_VALUE;
+ }
+ for (const auto mode : ::ndk::enum_range<Spatialization::Mode>()) {
+ if (const auto spatializer =
+ Spatializer::make<Spatializer::spatializationMode>(mode);
+ spatializer >= range->min && spatializer <= range->max) {
+ if (status_t status = param.writeToValue(&mode); status != OK) {
+ ALOGI("%s %d: write mode %s to value failed %d", __func__, __LINE__,
+ toString(mode).c_str(), status);
+ return status;
+ }
+ }
+ }
+ return OK;
+ }
+ case SPATIALIZER_PARAM_SUPPORTED_HEADTRACKING_CONNECTION: {
+ const auto& range = getRange<Range::spatializer, Range::SpatializerRange>(
+ mDesc.capability, Spatializer::headTrackingConnectionMode);
+ if (!range) {
+ return BAD_VALUE;
+ }
+ for (const auto mode : ::ndk::enum_range<HeadTracking::ConnectionMode>()) {
+ if (const auto spatializer =
+ Spatializer::make<Spatializer::headTrackingConnectionMode>(mode);
+ spatializer < range->min || spatializer > range->max) {
+ continue;
+ }
+ if (status_t status = param.writeToValue(&mode); status != OK) {
+ ALOGI("%s %d: write mode %s to value failed %d", __func__, __LINE__,
+ toString(mode).c_str(), status);
+ return status;
+ }
+ }
+ return OK;
+ }
+ case SPATIALIZER_PARAM_HEADTRACKING_CONNECTION: {
+ status_t status = OK;
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(
+ Spatializer, spatializerTag, Spatializer::headTrackingConnectionMode);
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ const auto mode = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, Spatializer, spatializer,
+ Spatializer::headTrackingConnectionMode, HeadTracking::ConnectionMode));
+
+ id = MAKE_SPECIFIC_PARAMETER_ID(Spatializer, spatializerTag,
+ Spatializer::headTrackingSensorId);
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ const auto sensorId = VALUE_OR_RETURN_STATUS(
+ GET_PARAMETER_SPECIFIC_FIELD(aidlParam, Spatializer, spatializer,
+ Spatializer::headTrackingSensorId, int32_t));
+ uint32_t modeInt32 = static_cast<int32_t>(mode);
+ if (status = param.writeToValue(&modeInt32); status != OK) {
+ ALOGI("%s %d: write mode %s to value failed %d", __func__, __LINE__,
+ toString(mode).c_str(), status);
+ return status;
+ }
+ if (status = param.writeToValue(&sensorId); status != OK) {
+ ALOGI("%s %d: write sensorId %d to value failed %d", __func__, __LINE__,
+ sensorId, status);
+ return status;
+ }
+ ALOGI("%s %d: %s", __func__, __LINE__, aidlParam.toString().c_str());
+ return OK;
+ }
+ default: {
+ ALOGE("%s %d invalid command %u", __func__, __LINE__, command);
+ return BAD_VALUE;
+ }
+ }
+ } else {
+ Parameter aidlParam;
+ DefaultExtension defaultExt;
+ // read parameters into DefaultExtension vector<uint8_t>
+ defaultExt.bytes.resize(param.getParameterSize());
+ if (OK != param.readFromParameter(defaultExt.bytes.data(), param.getParameterSize())) {
+ ALOGE("%s %d invalid param %s", __func__, __LINE__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+
+ VendorExtension idTag;
+ idTag.extension.setParcelable(defaultExt);
+ Parameter::Id id = UNION_MAKE(Parameter::Id, vendorEffectTag, idTag);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ ALOGI("%s %d: %s", __func__, __LINE__,
+ aidlParam.get<Parameter::specific>().toString().c_str());
+ // copy the AIDL extension data back to effect_param_t
+ return VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_Parameter_EffectParameterWriter(aidlParam, param));
+ }
}
} // namespace effect
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
index 7c60b14..444e5a7 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
@@ -32,6 +32,8 @@
~AidlConversionSpatializer() {}
private:
+ std::optional<bool> mIsSpatializerAidlParamSupported;
+ bool isSpatializerParameterSupported();
status_t setParameter(utils::EffectParamReader& param) override;
status_t getParameter(utils::EffectParamWriter& param) override;
};
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index bb5f851..7f6c1fb 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -78,8 +78,9 @@
virtual status_t getParameters(const String8& keys, String8 *values) = 0;
// Returns audio input buffer size according to parameters passed.
- virtual status_t getInputBufferSize(const struct audio_config *config,
- size_t *size) = 0;
+ // If there is no possibility for the HAL to open an input with the provided
+ // parameters, the method will return BAD_VALUE and modify the provided `config`.
+ virtual status_t getInputBufferSize(struct audio_config *config, size_t *size) = 0;
// Creates and opens the audio hardware output stream. The stream is closed
// by releasing all references to the returned object.
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index a780a17..37615af 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -116,7 +116,7 @@
class StreamOutHalInterfaceEventCallback : public virtual RefBase {
public:
- virtual void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) = 0;
+ virtual void onCodecFormatChanged(const std::vector<uint8_t>& metadataBs) = 0;
protected:
StreamOutHalInterfaceEventCallback() = default;
diff --git a/media/libaudiohal/tests/Android.bp b/media/libaudiohal/tests/Android.bp
index 8f011c8..1a54500 100644
--- a/media/libaudiohal/tests/Android.bp
+++ b/media/libaudiohal/tests/Android.bp
@@ -49,6 +49,7 @@
shared_libs: [
"libvibrator",
],
+ test_config_template: "AudioHalTestTemplate.xml",
}
cc_test {
@@ -63,3 +64,14 @@
],
header_libs: ["libaudiohalimpl_headers"],
}
+
+cc_test {
+ name: "EffectHalVersionCompatibilityTest",
+ srcs: [
+ "EffectHalVersionCompatibility_test.cpp",
+ ":audio_effect_hal_aidl_src_files",
+ ],
+ defaults: ["libaudiohal_aidl_test_default"],
+ header_libs: ["libaudiohalimpl_headers"],
+ static_libs: ["libgmock"],
+}
diff --git a/media/libaudiohal/tests/AudioHalTestTemplate.xml b/media/libaudiohal/tests/AudioHalTestTemplate.xml
new file mode 100644
index 0000000..b1cb2f0
--- /dev/null
+++ b/media/libaudiohal/tests/AudioHalTestTemplate.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs {MODULE}.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="{MODULE}" />
+ <option name="native-test-timeout" value="10m" />
+ </test>
+</configuration>
diff --git a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
index 1204a3b..3541078 100644
--- a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
+++ b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
@@ -443,21 +443,6 @@
EXPECT_EQ(ScreenRotation::DEG_0, mModule->getScreenRotation());
}
-// Without a vendor extension, any unrecognized parameters must be ignored.
-TEST_F(DeviceHalAidlTest, VendorParameterIgnored) {
- EXPECT_EQ(0UL, mModule->getAsyncParameters().size());
- EXPECT_EQ(0UL, mModule->getSyncParameters().size());
- EXPECT_EQ(OK, mDevice->setParameters(createParameterString("random_name", "random_value")));
- EXPECT_EQ(0UL, mModule->getAsyncParameters().size());
- EXPECT_EQ(0UL, mModule->getSyncParameters().size());
-
- EXPECT_EQ(0UL, mModule->getRetrievedParameterIds().size());
- String8 values;
- EXPECT_EQ(OK, mDevice->getParameters(String8("random_name"), &values));
- EXPECT_EQ(0UL, mModule->getRetrievedParameterIds().size());
- EXPECT_EQ(0UL, values.length());
-}
-
class DeviceHalAidlVendorParametersTest : public testing::Test {
public:
void SetUp() override {
diff --git a/media/libaudiohal/tests/EffectHalVersionCompatibility_test.cpp b/media/libaudiohal/tests/EffectHalVersionCompatibility_test.cpp
new file mode 100644
index 0000000..e8731ea
--- /dev/null
+++ b/media/libaudiohal/tests/EffectHalVersionCompatibility_test.cpp
@@ -0,0 +1,319 @@
+/*
+ * 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.
+ */
+
+#include <cstddef>
+#include <unordered_map>
+#define LOG_TAG "EffectHalVersionCompatibilityTest"
+
+#include <EffectHalAidl.h>
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <system/audio_aidl_utils.h>
+#include <system/audio_config.h>
+#include <system/audio_effects/audio_effects_utils.h>
+#include <system/audio_effects/effect_uuid.h>
+#include <utils/Log.h>
+
+using aidl::android::hardware::audio::effect::CommandId;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kReopenSupportedVersion;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Processing;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+using android::OK;
+using android::sp;
+using android::effect::EffectHalAidl;
+using testing::_;
+using testing::Eq;
+
+namespace {
+
+/**
+ * Maps of parameter and the version it was introduced.
+ */
+// parameters defined directly in the Parameter union, except Parameter::specific (defined in
+// kParamIdEffectVersionMap).
+static const std::unordered_map<Parameter::Tag, int /* version */> kParamTagVersionMap = {
+ {Parameter::common, 1}, {Parameter::deviceDescription, 1},
+ {Parameter::mode, 1}, {Parameter::source, 1},
+ {Parameter::offload, 1}, {Parameter::volumeStereo, 1},
+ {Parameter::sourceMetadata, 2}, {Parameter::sinkMetadata, 2},
+};
+
+// Map of the version a specific effect type introduction
+// Id tags defined Parameter::Id union, except Parameter::Id::commonTag (defined in
+// kParamTagVersionMap).
+static const std::unordered_map<Parameter::Id::Tag, int /* version */> kParamIdEffectVersionMap = {
+ {Parameter::Id::vendorEffectTag, 1},
+ {Parameter::Id::acousticEchoCancelerTag, 1},
+ {Parameter::Id::automaticGainControlV1Tag, 1},
+ {Parameter::Id::automaticGainControlV2Tag, 1},
+ {Parameter::Id::bassBoostTag, 1},
+ {Parameter::Id::downmixTag, 1},
+ {Parameter::Id::dynamicsProcessingTag, 1},
+ {Parameter::Id::environmentalReverbTag, 1},
+ {Parameter::Id::equalizerTag, 1},
+ {Parameter::Id::hapticGeneratorTag, 1},
+ {Parameter::Id::loudnessEnhancerTag, 1},
+ {Parameter::Id::noiseSuppressionTag, 1},
+ {Parameter::Id::presetReverbTag, 1},
+ {Parameter::Id::virtualizerTag, 1},
+ {Parameter::Id::visualizerTag, 1},
+ {Parameter::Id::volumeTag, 1},
+ {Parameter::Id::spatializerTag, 2},
+};
+// Tags defined Parameter::Specific union.
+static const std::unordered_map<Parameter::Specific::Tag, int /* version */>
+ kParamEffectVersionMap = {
+ {Parameter::Specific::vendorEffect, 1},
+ {Parameter::Specific::acousticEchoCanceler, 1},
+ {Parameter::Specific::automaticGainControlV1, 1},
+ {Parameter::Specific::automaticGainControlV2, 1},
+ {Parameter::Specific::bassBoost, 1},
+ {Parameter::Specific::downmix, 1},
+ {Parameter::Specific::dynamicsProcessing, 1},
+ {Parameter::Specific::environmentalReverb, 1},
+ {Parameter::Specific::equalizer, 1},
+ {Parameter::Specific::hapticGenerator, 1},
+ {Parameter::Specific::loudnessEnhancer, 1},
+ {Parameter::Specific::noiseSuppression, 1},
+ {Parameter::Specific::presetReverb, 1},
+ {Parameter::Specific::virtualizer, 1},
+ {Parameter::Specific::visualizer, 1},
+ {Parameter::Specific::volume, 1},
+ {Parameter::Specific::spatializer, 2},
+};
+
+class MockFactory : public IFactory {
+ public:
+ explicit MockFactory(int version) : IFactory(), mVersion(version) {}
+ MOCK_METHOD(ndk::ScopedAStatus, queryEffects,
+ (const std::optional<AudioUuid>& in_type_uuid,
+ const std::optional<AudioUuid>& in_impl_uuid,
+ const std::optional<AudioUuid>& in_proxy_uuid,
+ std::vector<Descriptor>* _aidl_return),
+ (override));
+
+ MOCK_METHOD(ndk::ScopedAStatus, queryProcessing,
+ (const std::optional<Processing::Type>& in_type,
+ std::vector<Processing>* _aidl_return),
+ (override));
+
+ MOCK_METHOD(ndk::ScopedAStatus, createEffect,
+ (const AudioUuid& in_impl_uuid, std::shared_ptr<IEffect>* _aidl_return),
+ (override));
+
+ MOCK_METHOD(ndk::ScopedAStatus, destroyEffect, (const std::shared_ptr<IEffect>& in_handle),
+ (override));
+
+ ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) {
+ *_aidl_return = mVersion;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ // these must be implemented but won't be used in this testing
+ ::ndk::SpAIBinder asBinder() { return ::ndk::SpAIBinder(); }
+ bool isRemote() { return false; }
+ ::ndk::ScopedAStatus getInterfaceHash(std::string*) { return ndk::ScopedAStatus::ok(); }
+
+ private:
+ const int mVersion;
+};
+
+class MockEffect : public IEffect {
+ public:
+ explicit MockEffect(int version) : IEffect(), mVersion(version) {}
+ MOCK_METHOD(ndk::ScopedAStatus, open,
+ (const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ IEffect::OpenEffectReturn* ret),
+ (override));
+ MOCK_METHOD(ndk::ScopedAStatus, close, (), (override));
+ MOCK_METHOD(binder_status_t, dump, (int fd, const char** args, uint32_t numArgs), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, command, (CommandId id), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getState, (State * state), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, getDescriptor, (Descriptor * desc), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, destroy, (), ());
+
+ // reopen introduced in version kReopenSupportedVersion
+ ndk::ScopedAStatus reopen(IEffect::OpenEffectReturn*) override {
+ return mVersion < kReopenSupportedVersion
+ ? ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION)
+ : ndk::ScopedAStatus::ok();
+ }
+
+ // for all parameters introduced
+ ndk::ScopedAStatus setParameter(const Parameter& param) override {
+ const auto paramTag = param.getTag();
+ switch (paramTag) {
+ case Parameter::common:
+ case Parameter::deviceDescription:
+ case Parameter::mode:
+ case Parameter::source:
+ case Parameter::offload:
+ case Parameter::volumeStereo:
+ case Parameter::sinkMetadata:
+ FALLTHROUGH_INTENDED;
+ case Parameter::sourceMetadata: {
+ if (kParamTagVersionMap.find(paramTag) != kParamTagVersionMap.end() &&
+ kParamTagVersionMap.at(paramTag) >= mVersion) {
+ return ndk::ScopedAStatus::ok();
+ }
+ break;
+ }
+ case Parameter::specific: {
+ // TODO
+ break;
+ }
+ }
+ return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ }
+
+ /**
+ * Only care about version compatibility here:
+ * @return BAD_VALUE if a tag is not supported by current AIDL version.
+ * @return OK if a tag is supported by current AIDL version.
+ */
+ ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter*) override {
+ const auto idTag = id.getTag();
+ switch (idTag) {
+ case Parameter::Id::commonTag: {
+ const auto paramTag = id.get<Parameter::Id::commonTag>();
+ if (kParamTagVersionMap.find(paramTag) != kParamTagVersionMap.end() &&
+ kParamTagVersionMap.at(paramTag) >= mVersion) {
+ return ndk::ScopedAStatus::ok();
+ }
+ break;
+ }
+ case Parameter::Id::vendorEffectTag:
+ case Parameter::Id::acousticEchoCancelerTag:
+ case Parameter::Id::automaticGainControlV1Tag:
+ case Parameter::Id::automaticGainControlV2Tag:
+ case Parameter::Id::bassBoostTag:
+ case Parameter::Id::downmixTag:
+ case Parameter::Id::dynamicsProcessingTag:
+ case Parameter::Id::environmentalReverbTag:
+ case Parameter::Id::equalizerTag:
+ case Parameter::Id::hapticGeneratorTag:
+ case Parameter::Id::loudnessEnhancerTag:
+ case Parameter::Id::noiseSuppressionTag:
+ case Parameter::Id::presetReverbTag:
+ case Parameter::Id::virtualizerTag:
+ case Parameter::Id::visualizerTag:
+ case Parameter::Id::volumeTag:
+ FALLTHROUGH_INTENDED;
+ case Parameter::Id::spatializerTag: {
+ if (kParamIdEffectVersionMap.find(idTag) != kParamIdEffectVersionMap.end() &&
+ kParamIdEffectVersionMap.at(idTag) >= mVersion) {
+ return ndk::ScopedAStatus::ok();
+ }
+ break;
+ }
+ }
+ return ndk::ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ }
+
+ ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) {
+ *_aidl_return = mVersion;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ // these must be implemented but won't be used in this testing
+ ::ndk::SpAIBinder asBinder() { return ::ndk::SpAIBinder(); }
+ bool isRemote() { return false; }
+ ::ndk::ScopedAStatus getInterfaceHash(std::string*) { return ndk::ScopedAStatus::ok(); }
+
+ private:
+ const int mVersion;
+};
+
+static const std::vector<AudioUuid> kTestParamUUIDs = {
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidAcousticEchoCanceler(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidAutomaticGainControlV1(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidAutomaticGainControlV2(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidBassBoost(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidDownmix(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidEqualizer(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidNoiseSuppression(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidSpatializer(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidVirtualizer(),
+ ::aidl::android::hardware::audio::effect::getEffectTypeUuidVisualizer(),
+ ::aidl::android::hardware::audio::effect::getEffectUuidNull(),
+};
+static const std::vector<int> kTestParamVersion = {1, 2}; // Effect AIDL HAL versions to test
+
+enum ParamName { UUID, VERSION };
+using TestParam = std::tuple<AudioUuid, int /* version */>;
+
+class EffectHalVersionCompatibilityTest : public ::testing::TestWithParam<TestParam> {
+ public:
+ void SetUp() override {
+ mMockFactory = ndk::SharedRefBase::make<MockFactory>(mVersion);
+ ASSERT_NE(mMockFactory, nullptr);
+ mMockEffect = ndk::SharedRefBase::make<MockEffect>(mVersion);
+ ASSERT_NE(mMockEffect, nullptr);
+ mEffectHalAidl = sp<EffectHalAidl>::make(mMockFactory, mMockEffect, 0, 0, mDesc, false);
+ ASSERT_NE(mEffectHalAidl, nullptr);
+ }
+
+ void TearDown() override {
+ EXPECT_CALL(*mMockFactory, destroyEffect(_));
+ mEffectHalAidl.clear();
+ mMockEffect.reset();
+ mMockFactory.reset();
+ }
+
+ protected:
+ const int mVersion = std::get<VERSION>(GetParam());
+ const AudioUuid mTypeUuid = std::get<UUID>(GetParam());
+ const Descriptor mDesc = {.common.id.type = mTypeUuid};
+ std::shared_ptr<MockFactory> mMockFactory = nullptr;
+ std::shared_ptr<MockEffect> mMockEffect = nullptr;
+ sp<EffectHalAidl> mEffectHalAidl = nullptr;
+};
+
+TEST_P(EffectHalVersionCompatibilityTest, testEffectAidlHalCreateDestroy) {
+ // do nothing
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EffectHalVersionCompatibilityTestWithVersion, EffectHalVersionCompatibilityTest,
+ ::testing::Combine(testing::ValuesIn(kTestParamUUIDs),
+ testing::ValuesIn(kTestParamVersion)),
+ [](const testing::TestParamInfo<EffectHalVersionCompatibilityTest::ParamType>& info) {
+ auto version = std::to_string(std::get<VERSION>(info.param));
+ auto uuid = android::audio::utils::toString(std::get<UUID>(info.param));
+ std::string name = "EffectHalVersionCompatibilityTest_V" + version + "_" + uuid;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+} // namespace
\ No newline at end of file
diff --git a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
index 0cb654c..d783c64 100644
--- a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
+++ b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
@@ -21,10 +21,13 @@
#include <cstdint>
#include <cstring>
#include <memory>
+#include <string>
#include <utility>
#define LOG_TAG "EffectsFactoryHalInterfaceTest"
#include <aidl/android/media/audio/common/AudioUuid.h>
+#include <android/media/audio/common/HeadTracking.h>
+#include <android/media/audio/common/Spatialization.h>
#include <gtest/gtest.h>
#include <media/AidlConversionCppNdk.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
@@ -40,15 +43,18 @@
#include <system/audio_effects/effect_hapticgenerator.h>
#include <system/audio_effects/effect_loudnessenhancer.h>
#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_spatializer.h>
#include <utils/RefBase.h>
#include <vibrator/ExternalVibrationUtils.h>
namespace android {
-using ::aidl::android::media::audio::common::AudioUuid;
-using ::android::audio::utils::toString;
+using aidl::android::media::audio::common::AudioUuid;
+using android::audio::utils::toString;
using effect::utils::EffectParamReader;
using effect::utils::EffectParamWriter;
+using media::audio::common::HeadTracking;
+using media::audio::common::Spatialization;
// EffectsFactoryHalInterface
TEST(libAudioHalTest, createEffectsFactoryHalInterface) {
@@ -144,34 +150,68 @@
EXPECT_NE(0, version.getMajorVersion());
}
+enum ParamSetGetType { SET_N_GET, SET_ONLY, GET_ONLY };
class EffectParamCombination {
public:
template <typename P, typename V>
- void init(const P& p, const V& v, size_t len) {
- setBuffer.resize(sizeof(effect_param_t) + sizeof(p) + sizeof(v) + 4);
- getBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4);
- expectBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4);
- parameterSet =
- std::make_shared<EffectParamReader>(createEffectParam(setBuffer.data(), p, v));
- parameterGet =
- std::make_shared<EffectParamReader>(createEffectParam(getBuffer.data(), p, v));
- parameterExpect =
- std::make_shared<EffectParamReader>(createEffectParam(expectBuffer.data(), p, v));
- valueSize = len;
+ void init(const P& p, const V& v, size_t len, ParamSetGetType type) {
+ if (type != GET_ONLY) {
+ mSetBuffer.resize(sizeof(effect_param_t) + sizeof(p) + sizeof(v) + 4);
+ mParameterSet =
+ std::make_shared<EffectParamReader>(createEffectParam(mSetBuffer.data(), p, v));
+ }
+
+ if (type != SET_ONLY) {
+ mGetBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4);
+ mExpectBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4);
+ mParameterGet =
+ std::make_shared<EffectParamReader>(createEffectParam(mGetBuffer.data(), p, v));
+ mParameterExpect = std::make_shared<EffectParamReader>(
+ createEffectParam(mExpectBuffer.data(), p, v));
+ mValueSize = len;
+ }
+ mType = type;
}
- std::shared_ptr<EffectParamReader> parameterSet; /* setParameter */
- std::shared_ptr<EffectParamReader> parameterGet; /* getParameter */
- std::shared_ptr<EffectParamReader> parameterExpect; /* expected from getParameter */
- size_t valueSize; /* ValueSize expect to write in reply data buffer */
+ std::shared_ptr<EffectParamReader> mParameterSet; /* setParameter */
+ std::shared_ptr<EffectParamReader> mParameterGet; /* getParameter */
+ std::shared_ptr<EffectParamReader> mParameterExpect; /* expected from getParameter */
+ size_t mValueSize = 0ul; /* ValueSize expect to write in reply data buffer */
+ ParamSetGetType mType = SET_N_GET;
+
+ std::string toString() {
+ uint32_t command = 0;
+ std::string str = "Command: ";
+ if (mType != GET_ONLY) {
+ str += (OK == mParameterSet->readFromParameter(&command) ? std::to_string(command)
+ : mParameterSet->toString());
+ } else {
+ str += (OK == mParameterGet->readFromParameter(&command) ? std::to_string(command)
+ : mParameterSet->toString());
+ }
+ str += "_";
+ str += toString(mType);
+ return str;
+ }
+
+ static std::string toString(ParamSetGetType type) {
+ switch (type) {
+ case SET_N_GET:
+ return "Type:SetAndGet";
+ case SET_ONLY:
+ return "Type:SetOnly";
+ case GET_ONLY:
+ return "Type:GetOnly";
+ }
+ }
private:
- std::vector<uint8_t> setBuffer;
- std::vector<uint8_t> getBuffer;
- std::vector<uint8_t> expectBuffer;
+ std::vector<uint8_t> mSetBuffer;
+ std::vector<uint8_t> mGetBuffer;
+ std::vector<uint8_t> mExpectBuffer;
template <typename P, typename V>
- EffectParamReader createEffectParam(void* buf, const P& p, const V& v) {
+ static EffectParamReader createEffectParam(void* buf, const P& p, const V& v) {
effect_param_t* paramRet = (effect_param_t*)buf;
paramRet->psize = sizeof(P);
paramRet->vsize = sizeof(V);
@@ -184,48 +224,106 @@
};
template <typename P, typename V>
-std::shared_ptr<EffectParamCombination> createEffectParamCombination(const P& p, const V& v,
- size_t len) {
+std::shared_ptr<EffectParamCombination> createEffectParamCombination(
+ const P& p, const V& v, size_t len, ParamSetGetType type = SET_N_GET) {
auto comb = std::make_shared<EffectParamCombination>();
- comb->init(p, v, len);
+ comb->init(p, v, len, type);
return comb;
}
-enum ParamName { TUPLE_UUID, TUPLE_PARAM_COMBINATION };
-using EffectParamTestTuple =
- std::tuple<const effect_uuid_t* /* type UUID */, std::shared_ptr<EffectParamCombination>>;
-
+enum ParamName { TUPLE_UUID, TUPLE_IS_INPUT, TUPLE_PARAM_COMBINATION };
+using EffectParamTestTuple = std::tuple<const effect_uuid_t* /* type UUID */, bool /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>>;
static const effect_uuid_t EXTEND_EFFECT_TYPE_UUID = {
0xfa81dbde, 0x588b, 0x11ed, 0x9b6a, {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
constexpr std::array<uint8_t, 10> kVendorExtensionData({0xff, 0x5, 0x50, 0xab, 0xcd, 0x00, 0xbd,
0xdb, 0xee, 0xff});
-std::vector<EffectParamTestTuple> testPairs = {
- std::make_tuple(FX_IID_AEC,
- createEffectParamCombination(AEC_PARAM_ECHO_DELAY, 0xff /* echoDelayMs */,
- sizeof(int32_t) /* returnValueSize */)),
- std::make_tuple(FX_IID_AGC,
- createEffectParamCombination(AGC_PARAM_TARGET_LEVEL, 20 /* targetLevel */,
- sizeof(int16_t) /* returnValueSize */)),
- std::make_tuple(SL_IID_BASSBOOST,
- createEffectParamCombination(BASSBOOST_PARAM_STRENGTH, 20 /* strength */,
- sizeof(int16_t) /* returnValueSize */)),
- std::make_tuple(EFFECT_UIID_DOWNMIX,
- createEffectParamCombination(DOWNMIX_PARAM_TYPE, DOWNMIX_TYPE_FOLD,
- sizeof(int16_t) /* returnValueSize */)),
- std::make_tuple(SL_IID_DYNAMICSPROCESSING,
- createEffectParamCombination(
- std::array<uint32_t, 2>({DP_PARAM_INPUT_GAIN, 0 /* channel */}),
- 30 /* gainDb */, sizeof(int32_t) /* returnValueSize */)),
+static std::vector<EffectParamTestTuple> testPairs = {
std::make_tuple(
- FX_IID_LOUDNESS_ENHANCER,
- createEffectParamCombination(LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB, 5 /* gain */,
- sizeof(int32_t) /* returnValueSize */)),
- std::make_tuple(FX_IID_NS,
- createEffectParamCombination(NS_PARAM_LEVEL, 1 /* level */,
- sizeof(int32_t) /* returnValueSize */)),
- std::make_tuple(&EXTEND_EFFECT_TYPE_UUID,
- createEffectParamCombination(8, kVendorExtensionData,
- sizeof(kVendorExtensionData)))};
+ FX_IID_AEC, true /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{
+ createEffectParamCombination(AEC_PARAM_ECHO_DELAY, 0xff /* echoDelayMs */,
+ sizeof(int32_t) /* returnValueSize */)}),
+ std::make_tuple(
+ FX_IID_AGC, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{
+ createEffectParamCombination(AGC_PARAM_TARGET_LEVEL, 20 /* targetLevel */,
+ sizeof(int16_t) /* returnValueSize */)}),
+ std::make_tuple(
+ SL_IID_BASSBOOST, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{
+ createEffectParamCombination(BASSBOOST_PARAM_STRENGTH, 20 /* strength */,
+ sizeof(int16_t) /* returnValueSize */)}),
+ std::make_tuple(
+ EFFECT_UIID_DOWNMIX, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{
+ createEffectParamCombination(DOWNMIX_PARAM_TYPE, DOWNMIX_TYPE_FOLD,
+ sizeof(int16_t) /* returnValueSize */)}),
+ std::make_tuple(
+ SL_IID_DYNAMICSPROCESSING, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{createEffectParamCombination(
+ std::array<uint32_t, 2>({DP_PARAM_INPUT_GAIN, 0 /* channel */}),
+ 30 /* gainDb */, sizeof(int32_t) /* returnValueSize */)}),
+ std::make_tuple(
+ FX_IID_LOUDNESS_ENHANCER, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{createEffectParamCombination(
+ LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB, 5 /* gain */,
+ sizeof(int32_t) /* returnValueSize */)}),
+ std::make_tuple(
+ FX_IID_NS, true /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{createEffectParamCombination(
+ NS_PARAM_LEVEL, 1 /* level */, sizeof(int32_t) /* returnValueSize */)}),
+ std::make_tuple(
+ FX_IID_SPATIALIZER, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{
+ createEffectParamCombination(SPATIALIZER_PARAM_LEVEL,
+ SPATIALIZATION_LEVEL_MULTICHANNEL,
+ sizeof(uint8_t), SET_N_GET),
+ createEffectParamCombination(SPATIALIZER_PARAM_HEADTRACKING_MODE,
+ HeadTracking::Mode::RELATIVE_WORLD,
+ sizeof(uint8_t), SET_N_GET),
+ createEffectParamCombination(
+ SPATIALIZER_PARAM_HEAD_TO_STAGE,
+ std::array<float, 6>{.55f, 0.2f, 1.f, .999f, .43f, 19.f},
+ sizeof(std::array<float, 6>), SET_ONLY),
+ createEffectParamCombination(
+ SPATIALIZER_PARAM_HEADTRACKING_CONNECTION,
+ std::array<uint32_t, 2>{
+ static_cast<uint32_t>(HeadTracking::ConnectionMode::
+ DIRECT_TO_SENSOR_TUNNEL),
+ 0x5e /* sensorId */},
+ sizeof(std::array<uint32_t, 2>), SET_N_GET),
+ createEffectParamCombination(
+ SPATIALIZER_PARAM_SUPPORTED_LEVELS,
+ std::array<Spatialization::Level, 3>{
+ Spatialization::Level::NONE,
+ Spatialization::Level::MULTICHANNEL,
+ Spatialization::Level::BED_PLUS_OBJECTS},
+ sizeof(std::array<uint8_t, 3>), GET_ONLY),
+ createEffectParamCombination(SPATIALIZER_PARAM_HEADTRACKING_SUPPORTED, true,
+ sizeof(bool), GET_ONLY),
+ createEffectParamCombination(SPATIALIZER_PARAM_SUPPORTED_CHANNEL_MASKS,
+ AUDIO_CHANNEL_OUT_5POINT1, sizeof(uint8_t),
+ GET_ONLY),
+ createEffectParamCombination(
+ SPATIALIZER_PARAM_SUPPORTED_SPATIALIZATION_MODES,
+ std::array<Spatialization::Mode, 2>{
+ Spatialization::Mode::BINAURAL,
+ Spatialization::Mode::TRANSAURAL},
+ sizeof(std::array<uint8_t, 2>), GET_ONLY),
+ createEffectParamCombination(
+ SPATIALIZER_PARAM_SUPPORTED_HEADTRACKING_CONNECTION,
+ std::array<HeadTracking::ConnectionMode, 3>{
+ HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED,
+ HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_SW,
+ HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL},
+ sizeof(std::array<uint8_t, 3>), GET_ONLY),
+ }),
+ std::make_tuple(
+ &EXTEND_EFFECT_TYPE_UUID, false /* isInput */,
+ std::vector<std::shared_ptr<EffectParamCombination>>{createEffectParamCombination(
+ uint32_t{8}, kVendorExtensionData, sizeof(kVendorExtensionData))}),
+};
class libAudioHalEffectParamTest : public ::testing::TestWithParam<EffectParamTestTuple> {
public:
@@ -233,13 +331,8 @@
: mParamTuple(GetParam()),
mFactory(EffectsFactoryHalInterface::create()),
mTypeUuid(std::get<TUPLE_UUID>(mParamTuple)),
- mCombination(std::get<TUPLE_PARAM_COMBINATION>(mParamTuple)),
- mExpectedValue([&]() {
- std::vector<uint8_t> expectData(mCombination->valueSize);
- mCombination->parameterExpect->readFromValue(expectData.data(),
- mCombination->valueSize);
- return expectData;
- }()),
+ mCombinations(std::get<TUPLE_PARAM_COMBINATION>(mParamTuple)),
+ mIsInput(std::get<TUPLE_IS_INPUT>(mParamTuple)),
mDescs([&]() {
std::vector<effect_descriptor_t> descs;
if (mFactory && mTypeUuid && OK == mFactory->getDescriptors(mTypeUuid, &descs)) {
@@ -263,7 +356,8 @@
uint32_t reply = 0;
uint32_t replySize = sizeof(reply);
ASSERT_EQ(OK, interface->command(EFFECT_CMD_INIT, 0, nullptr, &replySize, &reply));
- ASSERT_EQ(OK, interface->command(EFFECT_CMD_SET_CONFIG, sizeof(mEffectConfig),
+
+ ASSERT_EQ(OK, interface->command(EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
&mEffectConfig, &replySize, &reply));
}
@@ -284,60 +378,85 @@
}
void setAndGetParameter(const sp<EffectHalInterface>& interface) {
- uint32_t replySize = sizeof(uint32_t);
- uint8_t reply[replySize];
- auto parameterSet = mCombination->parameterSet;
- ASSERT_EQ(OK,
- interface->command(EFFECT_CMD_SET_PARAM, (uint32_t)parameterSet->getTotalSize(),
- const_cast<effect_param_t*>(¶meterSet->getEffectParam()),
- &replySize, &reply))
- << parameterSet->toString();
- ASSERT_EQ(replySize, sizeof(uint32_t));
+ for (const auto combination : mCombinations) {
+ uint32_t replySize = kSetParamReplySize;
+ uint8_t reply[replySize];
+ const auto type = combination->mType;
+ if (type != GET_ONLY) {
+ const auto& set = combination->mParameterSet;
+ ASSERT_EQ(OK,
+ interface->command(EFFECT_CMD_SET_PARAM, (uint32_t)set->getTotalSize(),
+ const_cast<effect_param_t*>(&set->getEffectParam()),
+ &replySize, &reply))
+ << set->toString();
+ ASSERT_EQ(replySize, kSetParamReplySize);
+ }
- effect_param_t* getParam =
- const_cast<effect_param_t*>(&mCombination->parameterGet->getEffectParam());
- size_t maxReplySize = mCombination->valueSize + sizeof(effect_param_t) +
- sizeof(parameterSet->getPaddedParameterSize());
- replySize = maxReplySize;
- EXPECT_EQ(OK,
- interface->command(EFFECT_CMD_GET_PARAM, (uint32_t)parameterSet->getTotalSize(),
- const_cast<effect_param_t*>(¶meterSet->getEffectParam()),
- &replySize, getParam));
- EffectParamReader parameterGet(*getParam);
- EXPECT_EQ(replySize, parameterGet.getTotalSize()) << parameterGet.toString();
- if (mCombination->valueSize) {
- std::vector<uint8_t> response(mCombination->valueSize);
- EXPECT_EQ(OK, parameterGet.readFromValue(response.data(), mCombination->valueSize))
- << " try get valueSize " << mCombination->valueSize << " from "
- << parameterGet.toString() << " set " << parameterSet->toString();
- EXPECT_EQ(response, mExpectedValue);
+ if (type != SET_ONLY) {
+ auto get = combination->mParameterGet;
+ auto expect = combination->mParameterExpect;
+ effect_param_t* getParam = const_cast<effect_param_t*>(&get->getEffectParam());
+ size_t maxReplySize = combination->mValueSize + sizeof(effect_param_t) +
+ sizeof(expect->getPaddedParameterSize());
+ replySize = maxReplySize;
+ EXPECT_EQ(OK,
+ interface->command(EFFECT_CMD_GET_PARAM, (uint32_t)expect->getTotalSize(),
+ const_cast<effect_param_t*>(&expect->getEffectParam()),
+ &replySize, getParam));
+
+ EffectParamReader getReader(*getParam);
+ EXPECT_EQ(replySize, getReader.getTotalSize()) << getReader.toString();
+ if (combination->mValueSize) {
+ std::vector<uint8_t> expectedData(combination->mValueSize);
+ EXPECT_EQ(OK, expect->readFromValue(expectedData.data(), expectedData.size()))
+ << combination->toString();
+ std::vector<uint8_t> response(combination->mValueSize);
+ EXPECT_EQ(OK, getReader.readFromValue(response.data(), combination->mValueSize))
+ << " try get valueSize " << combination->mValueSize << " from:\n"
+ << getReader.toString() << "\nexpect:\n"
+ << expect->toString();
+ EXPECT_EQ(expectedData, response) << combination->toString();
+ }
+ }
}
}
+ static constexpr size_t kSetParamReplySize = sizeof(uint32_t);
const EffectParamTestTuple mParamTuple;
const sp<EffectsFactoryHalInterface> mFactory;
const effect_uuid_t* mTypeUuid;
- std::shared_ptr<EffectParamCombination> mCombination;
- const std::vector<uint8_t> mExpectedValue;
+ std::vector<std::shared_ptr<EffectParamCombination>> mCombinations{};
+ const bool mIsInput;
const std::vector<effect_descriptor_t> mDescs;
- std::vector<sp<EffectHalInterface>> mHalInterfaces;
- effect_config_t mEffectConfig = {.inputCfg = {.accessMode = EFFECT_BUFFER_ACCESS_READ,
- .format = AUDIO_FORMAT_PCM_FLOAT,
- .bufferProvider.getBuffer = nullptr,
- .bufferProvider.releaseBuffer = nullptr,
- .bufferProvider.cookie = nullptr,
- .mask = EFFECT_CONFIG_ALL,
- .samplingRate = 48000,
- .channels = AUDIO_CHANNEL_IN_STEREO},
-
- .outputCfg = {.accessMode = EFFECT_BUFFER_ACCESS_WRITE,
- .format = AUDIO_FORMAT_PCM_FLOAT,
- .bufferProvider.getBuffer = nullptr,
- .bufferProvider.releaseBuffer = nullptr,
- .bufferProvider.cookie = nullptr,
- .mask = EFFECT_CONFIG_ALL,
- .samplingRate = 48000,
- .channels = AUDIO_CHANNEL_OUT_STEREO}};
+ std::vector<sp<EffectHalInterface>> mHalInterfaces{};
+ effect_config_t mEffectConfig = {
+ .inputCfg =
+ {
+ .buffer = {.frameCount = 0x100},
+ .samplingRate = 48000,
+ .channels = mIsInput ? AUDIO_CHANNEL_IN_VOICE_CALL_MONO
+ : AUDIO_CHANNEL_IN_STEREO,
+ .bufferProvider = {.getBuffer = nullptr,
+ .releaseBuffer = nullptr,
+ .cookie = nullptr},
+ .format = AUDIO_FORMAT_PCM_FLOAT,
+ .accessMode = EFFECT_BUFFER_ACCESS_READ,
+ .mask = EFFECT_CONFIG_ALL,
+ },
+ .outputCfg =
+ {
+ .buffer = {.frameCount = 0x100},
+ .samplingRate = 48000,
+ .channels = mIsInput ? AUDIO_CHANNEL_IN_VOICE_CALL_MONO
+ : AUDIO_CHANNEL_OUT_STEREO,
+ .bufferProvider = {.getBuffer = nullptr,
+ .releaseBuffer = nullptr,
+ .cookie = nullptr},
+ .format = AUDIO_FORMAT_PCM_FLOAT,
+ .accessMode = EFFECT_BUFFER_ACCESS_WRITE,
+ .mask = EFFECT_CONFIG_ALL,
+ },
+ };
};
TEST_P(libAudioHalEffectParamTest, setAndGetParam) {
@@ -392,7 +511,8 @@
AudioUuid uuid = ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(
*std::get<TUPLE_UUID>(info.param))
.value();
- std::string name = "UUID_" + toString(uuid);
+ std::string name = "UUID_" + toString(uuid) + "_";
+ name += std::get<TUPLE_IS_INPUT>(info.param) ? "_input" : "_output";
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
@@ -404,6 +524,4 @@
return RUN_ALL_TESTS();
}
-// TODO: b/263986405 Add multi-thread testing
-
} // namespace android
diff --git a/media/libaudioprocessing/AudioResamplerSinc.cpp b/media/libaudioprocessing/AudioResamplerSinc.cpp
index f2c386d..1a08a03 100644
--- a/media/libaudioprocessing/AudioResamplerSinc.cpp
+++ b/media/libaudioprocessing/AudioResamplerSinc.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "AudioResamplerSinc"
//#define LOG_NDEBUG 0
-#define __STDC_CONSTANT_MACROS
#include <malloc.h>
#include <pthread.h>
#include <string.h>
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.cpp b/media/libeffects/downmix/aidl/EffectDownmix.cpp
index c82c23b..46156ce 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.cpp
+++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp
@@ -195,6 +195,8 @@
const auto availableToWrite = outputMQ->availableToWrite() *
mImplContext->getInputFrameSize() /
mImplContext->getOutputFrameSize();
+ assert(mImplContext->getWorkBufferSize() >=
+ std::max(availableToRead(), availableToWrite));
auto processSamples = std::min(availableToRead, availableToWrite);
if (processSamples) {
inputMQ->read(buffer, processSamples);
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index 1fedea4..7e1549d 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -215,6 +215,10 @@
RETURN_OK_IF(mState != State::INIT);
mImplContext = createContext(common);
RETURN_IF(!mContext || !mImplContext, EX_NULL_POINTER, "createContextFailed");
+ int version = 0;
+ RETURN_IF(!getInterfaceVersion(&version).isOk(), EX_UNSUPPORTED_OPERATION,
+ "FailedToGetInterfaceVersion");
+ mImplContext->setVersion(version);
mEventFlag = mImplContext->getStatusEventFlag();
if (specific.has_value()) {
diff --git a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
index d8cf20e..bd43994 100644
--- a/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/EffectHapticGenerator.cpp
@@ -317,7 +317,7 @@
}
int id = *(int *) value;
os::HapticScale hapticIntensity = static_cast<os::HapticScale>(*((int *) value + 1));
- ALOGD("Setting haptic intensity as %d", hapticIntensity);
+ ALOGD("Setting haptic intensity as %d", static_cast<int>(hapticIntensity));
if (hapticIntensity == os::HapticScale::MUTE) {
context->param.id2Intensity.erase(id);
} else {
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
index 031477f..2d3bdd0 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -185,7 +185,7 @@
IEffect::Status HapticGeneratorImpl::effectProcessImpl(float* in, float* out, int samples) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!mContext, status, "nullContext");
- return mContext->lvmProcess(in, out, samples);
+ return mContext->process(in, out, samples);
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
index 354ee00..e671543 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -118,7 +118,7 @@
return RetCode::SUCCESS;
}
-IEffect::Status HapticGeneratorContext::lvmProcess(float* in, float* out, int samples) {
+IEffect::Status HapticGeneratorContext::process(float* in, float* out, int samples) {
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
index 26e69e4..8618b7b 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
@@ -75,7 +75,7 @@
RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo);
HapticGenerator::VibratorInformation getHgVibratorInformation();
- IEffect::Status lvmProcess(float* in, float* out, int samples);
+ IEffect::Status process(float* in, float* out, int samples);
private:
static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
index a7d9282..bcf0db6 100644
--- a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
@@ -178,7 +178,7 @@
IEffect::Status LoudnessEnhancerImpl::effectProcessImpl(float* in, float* out, int samples) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!mContext, status, "nullContext");
- return mContext->lvmProcess(in, out, samples);
+ return mContext->process(in, out, samples);
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
index bc3fa45..be914bf 100644
--- a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
+++ b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
@@ -65,7 +65,7 @@
return RetCode::SUCCESS;
}
-IEffect::Status LoudnessEnhancerContext::lvmProcess(float* in, float* out, int samples) {
+IEffect::Status LoudnessEnhancerContext::process(float* in, float* out, int samples) {
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
diff --git a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
index 9a1ec4c..fd688d7 100644
--- a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
+++ b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
@@ -42,7 +42,7 @@
RetCode setLeGain(int gainMb);
int getLeGain() const { return mGain; }
- IEffect::Status lvmProcess(float* in, float* out, int samples);
+ IEffect::Status process(float* in, float* out, int samples);
private:
std::mutex mMutex;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index bb7e4c6..aa18deb 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -284,15 +284,15 @@
// roundoff
int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
- if (maxLevelRound + mVolume > 0) {
- gainCorrection = maxLevelRound + mVolume;
+ if (maxLevelRound + mVolumedB > 0) {
+ gainCorrection = maxLevelRound + mVolumedB;
}
- params.VC_EffectLevel = mVolume - gainCorrection;
+ params.VC_EffectLevel = mVolumedB - gainCorrection;
if (params.VC_EffectLevel < -96) {
params.VC_EffectLevel = -96;
}
- LOG(INFO) << "\tVol: " << mVolume << ", GainCorrection: " << gainCorrection
+ LOG(INFO) << "\tVol: " << mVolumedB << ", GainCorrection: " << gainCorrection
<< ", Actual vol: " << params.VC_EffectLevel;
/* Activate the initial settings */
@@ -576,25 +576,25 @@
RetCode BundleContext::setVolumeLevel(float level) {
if (mMuteEnabled) {
- mLevelSaved = level;
+ mLevelSaveddB = level;
} else {
- mVolume = level;
+ mVolumedB = level;
}
LOG(INFO) << __func__ << " success with level " << level;
return limitLevel();
}
float BundleContext::getVolumeLevel() const {
- return (mMuteEnabled ? mLevelSaved : mVolume);
+ return (mMuteEnabled ? mLevelSaveddB : mVolumedB);
}
RetCode BundleContext::setVolumeMute(bool mute) {
mMuteEnabled = mute;
if (mMuteEnabled) {
- mLevelSaved = mVolume;
- mVolume = -96;
+ mLevelSaveddB = mVolumedB;
+ mVolumedB = -96;
} else {
- mVolume = mLevelSaved;
+ mVolumedB = mLevelSaveddB;
}
return limitLevel();
}
@@ -747,7 +747,7 @@
return angles;
}
-IEffect::Status BundleContext::lvmProcess(float* in, float* out, int samples) {
+IEffect::Status BundleContext::process(float* in, float* out, int samples) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!in, status, "nullInput");
RETURN_VALUE_IF(!out, status, "nullOutput");
@@ -854,21 +854,34 @@
LOG(DEBUG) << "Effect_process() processing last frame";
}
mNumberEffectsCalled = 0;
- float* outTmp = (accumulate ? getWorkBuffer() : out);
- /* Process the samples */
- LVM_ReturnStatus_en lvmStatus;
- {
- std::lock_guard lg(mMutex);
-
- lvmStatus = LVM_Process(mInstance, in, outTmp, inputFrameCount, 0);
- if (lvmStatus != LVM_SUCCESS) {
- LOG(ERROR) << __func__ << lvmStatus;
- return {EX_UNSUPPORTED_OPERATION, 0, 0};
- }
- if (accumulate) {
- for (int i = 0; i < samples; i++) {
- out[i] += outTmp[i];
+ int frames = samples * sizeof(float) / frameSize;
+ int bufferIndex = 0;
+ // LVM library supports max of int16_t frames at a time and should be multiple of
+ // kBlockSizeMultiple.
+ constexpr int kBlockSizeMultiple = 4;
+ constexpr int kMaxBlockFrames =
+ (std::numeric_limits<int16_t>::max() / kBlockSizeMultiple) * kBlockSizeMultiple;
+ while (frames > 0) {
+ float* outTmp = (accumulate ? getWorkBuffer() : out);
+ /* Process the samples */
+ LVM_ReturnStatus_en lvmStatus;
+ {
+ std::lock_guard lg(mMutex);
+ int processFrames = std::min(frames, kMaxBlockFrames);
+ lvmStatus = LVM_Process(mInstance, in + bufferIndex, outTmp + bufferIndex,
+ processFrames, 0);
+ if (lvmStatus != LVM_SUCCESS) {
+ LOG(ERROR) << "LVM lib failed with error: " << lvmStatus;
+ return {EX_UNSUPPORTED_OPERATION, 0, 0};
}
+ if (accumulate) {
+ for (int i = 0; i < samples; i++) {
+ out[i] += outTmp[i];
+ }
+ }
+ frames -= processFrames;
+ int processedSize = processFrames * frameSize / sizeof(float);
+ bufferIndex += processedSize;
}
}
} else {
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 809f402..d823030 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -85,7 +85,7 @@
RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) override;
Parameter::VolumeStereo getVolumeStereo() override { return {1.0f, 1.0f}; }
- IEffect::Status lvmProcess(float* in, float* out, int samples);
+ IEffect::Status process(float* in, float* out, int samples);
IEffect::Status processEffect(float* in, float* out, int sampleToProcess);
@@ -124,8 +124,8 @@
bool mVirtualizerTempDisabled = false;
::aidl::android::media::audio::common::AudioDeviceDescription mForceDevice;
// Volume
- float mLevelSaved = 0; /* for when mute is set, level must be saved */
- float mVolume = 0;
+ float mLevelSaveddB = 0; /* for when mute is set, level must be saved */
+ float mVolumedB = 0;
bool mMuteEnabled = false; /* Must store as mute = -96dB level */
RetCode initControlParameter(LVM_ControlParams_t& params) const;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index 143329d..daabdb7 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -129,8 +129,7 @@
.implementor = "NXP Software Ltd."},
.capability = kVirtualizerCap};
-static const std::vector<Range::VolumeRange> kVolumeRanges = {
- MAKE_RANGE(Volume, levelDb, -9600, 0)};
+static const std::vector<Range::VolumeRange> kVolumeRanges = {MAKE_RANGE(Volume, levelDb, -96, 0)};
static const Capability kVolumeCap = {.range = kVolumeRanges};
static const std::string kVolumeEffectName = "Volume";
static const Descriptor kVolumeDesc = {
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index 257e972..755f57c 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -458,7 +458,7 @@
IEffect::Status EffectBundleAidl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!mContext, status, "nullContext");
- return mContext->lvmProcess(in, out, sampleToProcess);
+ return mContext->process(in, out, sampleToProcess);
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index a50ba93..62837b9 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -120,7 +120,6 @@
shared_libs: [
"libaudio_aidl_conversion_common_ndk",
"libaudioutils",
- "libbinder",
"liblog",
"libstagefright_foundation",
],
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
index f9afe69..c714bc9 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -390,7 +390,7 @@
IEffect::Status EffectReverb::effectProcessImpl(float* in, float* out, int sampleToProcess) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!mContext, status, "nullContext");
- return mContext->lvmProcess(in, out, sampleToProcess);
+ return mContext->process(in, out, sampleToProcess);
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
index 468b268..1c66c78 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
@@ -352,7 +352,7 @@
return kDefaultLPF;
}
-IEffect::Status ReverbContext::lvmProcess(float* in, float* out, int samples) {
+IEffect::Status ReverbContext::process(float* in, float* out, int samples) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!in, status, "nullInput");
RETURN_VALUE_IF(!out, status, "nullOutput");
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
index d11a081..7d0ccff 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
@@ -100,7 +100,7 @@
}
bool getReflectionsLevel() const { return mReflectionsLevelMb; }
- IEffect::Status lvmProcess(float* in, float* out, int samples);
+ IEffect::Status process(float* in, float* out, int samples);
private:
static constexpr inline float kUnitVolume = 1;
@@ -161,7 +161,7 @@
std::mutex mMutex;
const lvm::ReverbEffectType mType;
bool mEnabled = false;
- LVREV_Handle_t mInstance GUARDED_BY(mMutex);
+ LVREV_Handle_t mInstance GUARDED_BY(mMutex) = LVM_NULL;
int mRoomLevel = 0;
int mRoomHfLevel = 0;
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
index 7552804..1675d97 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -446,7 +446,7 @@
IEffect::Status EffectPreProcessing::effectProcessImpl(float* in, float* out, int sampleToProcess) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!mContext, status, "nullContext");
- return mContext->lvmProcess(in, out, sampleToProcess);
+ return mContext->process(in, out, sampleToProcess);
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
index 2c44e5c..6f671f0 100644
--- a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
@@ -268,7 +268,7 @@
return mLevel;
}
-IEffect::Status PreProcessingContext::lvmProcess(float* in, float* out, int samples) {
+IEffect::Status PreProcessingContext::process(float* in, float* out, int samples) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!in, status, "nullInput");
RETURN_VALUE_IF(!out, status, "nullOutput");
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.h b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
index 9ba1bbe..811bacf 100644
--- a/media/libeffects/preprocessing/aidl/PreProcessingContext.h
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
@@ -76,7 +76,7 @@
RetCode setNoiseSuppressionLevel(NoiseSuppression::Level level);
NoiseSuppression::Level getNoiseSuppressionLevel() const;
- IEffect::Status lvmProcess(float* in, float* out, int samples);
+ IEffect::Status process(float* in, float* out, int samples);
private:
static constexpr inline int kAgcDefaultTargetLevel = 3;
diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp
index 0303842..9b1bac6 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.cpp
+++ b/media/libeffects/visualizer/aidl/Visualizer.cpp
@@ -59,10 +59,11 @@
const std::string VisualizerImpl::kEffectName = "Visualizer";
const std::vector<Range::VisualizerRange> VisualizerImpl::kRanges = {
MAKE_RANGE(Visualizer, latencyMs, 0, VisualizerContext::kMaxLatencyMs),
- MAKE_RANGE(Visualizer, captureSamples, 0, VisualizerContext::kMaxCaptureBufSize),
+ MAKE_RANGE(Visualizer, captureSamples, VisualizerContext::kMinCaptureBufSize,
+ VisualizerContext::kMaxCaptureBufSize),
/* get only parameters, set invalid range (min > max) to indicate not support set */
- MAKE_RANGE(Visualizer, measurement, Visualizer::Measurement({.peak = 1, .rms = 1}),
- Visualizer::Measurement({.peak = 0, .rms = 0})),
+ MAKE_RANGE(Visualizer, measurement, Visualizer::Measurement({.rms = 1, .peak = 1}),
+ Visualizer::Measurement({.rms = 0, .peak = 0})),
MAKE_RANGE(Visualizer, captureSampleBuffer, std::vector<uint8_t>({1}),
std::vector<uint8_t>({0}))};
const Capability VisualizerImpl::kCapability = {
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.cpp b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
index 5d2bb3a..c763b1a 100644
--- a/media/libeffects/visualizer/aidl/VisualizerContext.cpp
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
@@ -93,7 +93,7 @@
mCaptureSamples = samples;
return RetCode::SUCCESS;
}
-int VisualizerContext::getCaptureSamples() {
+int32_t VisualizerContext::getCaptureSamples() {
std::lock_guard lg(mMutex);
return mCaptureSamples;
}
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.h b/media/libeffects/visualizer/aidl/VisualizerContext.h
index 958035f..b03e038 100644
--- a/media/libeffects/visualizer/aidl/VisualizerContext.h
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.h
@@ -18,6 +18,7 @@
#include <android-base/thread_annotations.h>
#include <audio_effects/effect_dynamicsprocessing.h>
+#include <system/audio_effects/effect_visualizer.h>
#include "effect-impl/EffectContext.h"
@@ -25,8 +26,11 @@
class VisualizerContext final : public EffectContext {
public:
- static const uint32_t kMaxCaptureBufSize = 65536;
- static const uint32_t kMaxLatencyMs = 3000; // 3 seconds of latency for audio pipeline
+ // need align the min/max capture size to VISUALIZER_CAPTURE_SIZE_MIN and
+ // VISUALIZER_CAPTURE_SIZE_MAX because of limitation in audio_utils fixedfft.
+ static constexpr int32_t kMinCaptureBufSize = VISUALIZER_CAPTURE_SIZE_MIN;
+ static constexpr int32_t kMaxCaptureBufSize = VISUALIZER_CAPTURE_SIZE_MAX;
+ static constexpr uint32_t kMaxLatencyMs = 3000; // 3 seconds of latency for audio pipeline
VisualizerContext(int statusDepth, const Parameter::Common& common);
~VisualizerContext();
@@ -38,8 +42,8 @@
// keep all parameters and reset buffer.
void reset();
- RetCode setCaptureSamples(int captureSize);
- int getCaptureSamples();
+ RetCode setCaptureSamples(int32_t captureSize);
+ int32_t getCaptureSamples();
RetCode setMeasurementMode(Visualizer::MeasurementMode mode);
Visualizer::MeasurementMode getMeasurementMode();
RetCode setScalingMode(Visualizer::ScalingMode mode);
@@ -86,7 +90,7 @@
// capture buf with 8 bits mono PCM samples
std::array<uint8_t, kMaxCaptureBufSize> mCaptureBuf GUARDED_BY(mMutex);
uint32_t mDownstreamLatency GUARDED_BY(mMutex) = 0;
- uint32_t mCaptureSamples GUARDED_BY(mMutex) = kMaxCaptureBufSize;
+ int32_t mCaptureSamples GUARDED_BY(mMutex) = kMaxCaptureBufSize;
// to avoid recomputing it every time a buffer is processed
uint8_t mChannelCount GUARDED_BY(mMutex) = 0;
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index b511372..507da29 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -124,14 +124,19 @@
],
defaults: [
"libmediaplayerserviceFuzzer_defaults",
+ "libmediaplayerservice_defaults",
],
static_libs: [
"libplayerservice_datasource",
],
shared_libs: [
+ "libmediaplayerservice",
"libdatasource",
"libdrmframework",
+ "libstagefright_httplive",
+ "libmediaextractorservice",
],
+ include_dirs: ["frameworks/av/services/mediaextractor"],
}
cc_fuzz {
diff --git a/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp
index a7cb689..857223d 100644
--- a/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/metadataretriever_fuzzer.cpp
@@ -15,6 +15,8 @@
*
*/
+#include <MediaExtractorService.h>
+#include <MediaPlayerService.h>
#include <StagefrightMetadataRetriever.h>
#include <binder/ProcessState.h>
#include <datasource/FileSource.h>
@@ -54,58 +56,96 @@
MEDIA_MIMETYPE_CONTAINER_MPEG2PS, MEDIA_MIMETYPE_CONTAINER_HEIF,
MEDIA_MIMETYPE_TEXT_3GPP, MEDIA_MIMETYPE_TEXT_SUBRIP,
MEDIA_MIMETYPE_TEXT_VTT, MEDIA_MIMETYPE_TEXT_CEA_608,
- MEDIA_MIMETYPE_TEXT_CEA_708, MEDIA_MIMETYPE_DATA_TIMED_ID3};
+ MEDIA_MIMETYPE_TEXT_CEA_708, MEDIA_MIMETYPE_DATA_TIMED_ID3,
+ MEDIA_MIMETYPE_IMAGE_AVIF, MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1, MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L3,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L4, MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L3,
+ MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L4, MEDIA_MIMETYPE_AUDIO_DTS,
+ MEDIA_MIMETYPE_AUDIO_DTS_HD, MEDIA_MIMETYPE_AUDIO_DTS_HD_MA,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD, MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1,
+ MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2, MEDIA_MIMETYPE_AUDIO_EVRC,
+ MEDIA_MIMETYPE_AUDIO_EVRCB, MEDIA_MIMETYPE_AUDIO_EVRCWB,
+ MEDIA_MIMETYPE_AUDIO_EVRCNW, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ MEDIA_MIMETYPE_AUDIO_APTX, MEDIA_MIMETYPE_AUDIO_DRA,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT, MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_1_0,MEDIA_MIMETYPE_AUDIO_AAC_MP4,
+ MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_0,MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_1,
+ MEDIA_MIMETYPE_AUDIO_AAC_MAIN, MEDIA_MIMETYPE_AUDIO_AAC_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_SSR, MEDIA_MIMETYPE_AUDIO_AAC_LTP,
+ MEDIA_MIMETYPE_AUDIO_AAC_HE_V1, MEDIA_MIMETYPE_AUDIO_AAC_SCALABLE,
+ MEDIA_MIMETYPE_AUDIO_AAC_ERLC, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_MAIN,
+ MEDIA_MIMETYPE_AUDIO_AAC_HE_V2, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_XHE, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_AAC_LD, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SSR, MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LTP,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADIF, MEDIA_MIMETYPE_AUDIO_IEC60958,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ERLC,MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LD,
+ MEDIA_MIMETYPE_AUDIO_AAC_ELD, MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V1,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_XHE, MEDIA_MIMETYPE_AUDIO_AAC_LATM_LC,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ELD, MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V2,
+ MEDIA_MIMETYPE_AUDIO_IEC61937,
+ MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SCALABLE,};
+
+constexpr size_t kMaxSize = 100;
class MetadataRetrieverFuzzer {
public:
MetadataRetrieverFuzzer(const uint8_t *data, size_t size)
- : mFdp(data, size),
- mMdRetriever(new StagefrightMetadataRetriever()),
- mDataSourceFd(memfd_create("InputFile", MFD_ALLOW_SEALING)) {}
- ~MetadataRetrieverFuzzer() { close(mDataSourceFd); }
+ : mFdp(data, size), mMdRetriever(new StagefrightMetadataRetriever()) {}
bool setDataSource(const uint8_t *data, size_t size);
void getData();
private:
FuzzedDataProvider mFdp;
sp<StagefrightMetadataRetriever> mMdRetriever = nullptr;
- const int32_t mDataSourceFd;
+ int32_t mDataSourceFd;
};
void MetadataRetrieverFuzzer::getData() {
- int64_t timeUs = mFdp.ConsumeIntegral<int64_t>();
- int32_t option = mFdp.ConsumeIntegral<int32_t>();
- int32_t colorFormat = mFdp.ConsumeIntegral<int32_t>();
- bool metaOnly = mFdp.ConsumeBool();
- mMdRetriever->getFrameAtTime(timeUs, option, colorFormat, metaOnly);
-
- int32_t index = mFdp.ConsumeIntegral<int32_t>();
- colorFormat = mFdp.ConsumeIntegral<int32_t>();
- metaOnly = mFdp.ConsumeBool();
- bool thumbnail = mFdp.ConsumeBool();
- mMdRetriever->getImageAtIndex(index, colorFormat, metaOnly, thumbnail);
-
- index = mFdp.ConsumeIntegral<int32_t>();
- colorFormat = mFdp.ConsumeIntegral<int32_t>();
- int32_t left = mFdp.ConsumeIntegral<int32_t>();
- int32_t top = mFdp.ConsumeIntegral<int32_t>();
- int32_t right = mFdp.ConsumeIntegral<int32_t>();
- int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
- mMdRetriever->getImageRectAtIndex(index, colorFormat, left, top, right, bottom);
-
- index = mFdp.ConsumeIntegral<int32_t>();
- colorFormat = mFdp.ConsumeIntegral<int32_t>();
- metaOnly = mFdp.ConsumeBool();
- mMdRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
-
- mMdRetriever->extractAlbumArt();
-
- int32_t keyCode = mFdp.ConsumeIntegral<int32_t>();
- mMdRetriever->extractMetadata(keyCode);
+ while (mFdp.remaining_bytes()) {
+ auto invokeMediaApi = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ mMdRetriever->getFrameAtTime(mFdp.ConsumeIntegral<int64_t>() /* timeUs */,
+ mFdp.ConsumeIntegral<int32_t>() /* option */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeBool() /* metaOnly */);
+ },
+ [&]() {
+ mMdRetriever->getImageAtIndex(mFdp.ConsumeIntegral<int32_t>() /* index */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeBool() /* metaOnly */,
+ mFdp.ConsumeBool() /* thumbnail */);
+ },
+ [&]() {
+ mMdRetriever->getImageRectAtIndex(
+ mFdp.ConsumeIntegral<int32_t>() /* index */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeIntegral<int32_t>() /* left */,
+ mFdp.ConsumeIntegral<int32_t>() /* top */,
+ mFdp.ConsumeIntegral<int32_t>() /* right */,
+ mFdp.ConsumeIntegral<int32_t>() /* bottom */);
+ },
+ [&]() {
+ mMdRetriever->getFrameAtIndex(mFdp.ConsumeIntegral<int32_t>() /* index */,
+ mFdp.ConsumeIntegral<int32_t>() /* colorFormat */,
+ mFdp.ConsumeBool() /* metaOnly */);
+ },
+ [&]() { mMdRetriever->extractAlbumArt(); },
+ [&]() {
+ mMdRetriever->extractMetadata(mFdp.ConsumeIntegral<int32_t>() /* keyCode */);
+ },
+ });
+ invokeMediaApi();
+ }
}
bool MetadataRetrieverFuzzer::setDataSource(const uint8_t *data, size_t size) {
status_t status = -1;
+ std::unique_ptr<std::FILE, decltype(&fclose)> fp(tmpfile(), &fclose);
+ mDataSourceFd = fileno(fp.get());
+ if (mDataSourceFd < 0) {
+ return false;
+ }
enum DataSourceChoice {FromHttp, FromFd, FromFileSource, kMaxValue = FromFileSource};
switch (mFdp.ConsumeEnum<DataSourceChoice>()) {
@@ -114,7 +154,7 @@
mHeaders.add(String8(mFdp.ConsumeRandomLengthString().c_str()),
String8(mFdp.ConsumeRandomLengthString().c_str()));
- uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, size);
+ uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, min(kMaxSize,size));
vector<uint8_t> uriSuffix = mFdp.ConsumeBytes<uint8_t>(dataBlobSize);
string uri("data:");
@@ -146,6 +186,12 @@
return true;
}
+extern "C" int LLVMFuzzerInitialize(int* /* argc */, char*** /* argv */) {
+ MediaPlayerService::instantiate();
+ MediaExtractorService::instantiate();
+ return 0;
+}
+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
MetadataRetrieverFuzzer mrtFuzzer(data, size);
ProcessState::self()->startThreadPool();
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index d58619f..157ebd7 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -32,7 +32,7 @@
// negotiate with source
NBAIO_Format counterOffers[1];
size_t numCounterOffers = 1;
- ssize_t index = source->negotiate(NULL, 0, counterOffers, numCounterOffers);
+ [[maybe_unused]] ssize_t index = source->negotiate(NULL, 0, counterOffers, numCounterOffers);
ALOG_ASSERT(index == (ssize_t) NEGOTIATE && numCounterOffers > 0);
numCounterOffers = 0;
index = source->negotiate(counterOffers, 1, NULL, numCounterOffers);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 2145dd9..f9ceef2 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2188,7 +2188,7 @@
int32_t colorFormat = OMX_COLOR_FormatUnused;
OMX_U32 flexibleEquivalent = OMX_COLOR_FormatUnused;
if (!outputFormat->findInt32("color-format", &colorFormat)) {
- ALOGE("ouptut port did not have a color format (wrong domain?)");
+ ALOGE("output port did not have a color format (wrong domain?)");
return BAD_VALUE;
}
ALOGD("[%s] Requested output format %#x and got %#x.",
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 712b405..896e021 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -315,6 +315,7 @@
"libaudioclient_aidl_conversion",
"packagemanager_aidl-cpp",
"server_configurable_flags",
+ "aconfig_mediacodec_flags_c_lib",
],
static_libs: [
diff --git a/media/libstagefright/CryptoAsync.cpp b/media/libstagefright/CryptoAsync.cpp
index 8b5c8ed..0fc78ec 100644
--- a/media/libstagefright/CryptoAsync.cpp
+++ b/media/libstagefright/CryptoAsync.cpp
@@ -30,6 +30,36 @@
namespace android {
+CryptoAsync::CryptoAsyncInfo::CryptoAsyncInfo(const std::unique_ptr<CodecCryptoInfo> &info) {
+ if (info == nullptr) {
+ return;
+ }
+ size_t key_len = (info->mKey != nullptr)? 16 : 0;
+ size_t iv_len = (info->mIv != nullptr)? 16 : 0;
+ mNumSubSamples = info->mNumSubSamples;
+ mMode = info->mMode;
+ mPattern = info->mPattern;
+ if (key_len > 0) {
+ mKeyBuffer = ABuffer::CreateAsCopy((void*)info->mKey, key_len);
+ mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
+ }
+ if (iv_len > 0) {
+ mIvBuffer = ABuffer::CreateAsCopy((void*)info->mIv, iv_len);
+ mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
+ }
+ mSubSamplesBuffer =
+ new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
+ if (mSubSamplesBuffer.get()) {
+ CryptoPlugin::SubSample * samples =
+ (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
+ for (int s = 0 ; s < mNumSubSamples ; s++) {
+ samples[s].mNumBytesOfClearData = info->mSubSamples[s].mNumBytesOfClearData;
+ samples[s].mNumBytesOfEncryptedData = info->mSubSamples[s].mNumBytesOfEncryptedData;
+ }
+ mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
+ }
+}
+
CryptoAsync::~CryptoAsync() {
}
@@ -79,23 +109,27 @@
sp<ABuffer> keyBuffer;
sp<ABuffer> ivBuffer;
sp<ABuffer> subSamplesBuffer;
- msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
- msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
- msg->findBuffer("key", &keyBuffer);
- msg->findBuffer("iv", &ivBuffer);
- msg->findBuffer("subSamples", &subSamplesBuffer);
- msg->findInt32("secure", &secure);
- msg->findSize("numSubSamples", &numSubSamples);
- msg->findObject("buffer", &obj);
- msg->findInt32("mode", (int32_t*)&mode);
AString errorDetailMsg;
- const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
- const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
- const CryptoPlugin::SubSample * subSamples =
- (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
+ msg->findObject("buffer", &obj);
+ msg->findInt32("secure", &secure);
sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
- err = channel->queueSecureInputBuffer(buffer, secure, key, iv, mode,
- pattern, subSamples, numSubSamples, &errorDetailMsg);
+ if (buffer->meta()->findObject("cryptoInfos", &obj)) {
+ err = channel->queueSecureInputBuffers(buffer, secure, &errorDetailMsg);
+ } else {
+ msg->findInt32("encryptBlocks", (int32_t*)&pattern.mEncryptBlocks);
+ msg->findInt32("skipBlocks", (int32_t*)&pattern.mSkipBlocks);
+ msg->findBuffer("key", &keyBuffer);
+ msg->findBuffer("iv", &ivBuffer);
+ msg->findBuffer("subSamples", &subSamplesBuffer);
+ msg->findSize("numSubSamples", &numSubSamples);
+ msg->findInt32("mode", (int32_t*)&mode);
+ const uint8_t * key = keyBuffer.get() != nullptr ? keyBuffer.get()->data() : nullptr;
+ const uint8_t * iv = ivBuffer.get() != nullptr ? ivBuffer.get()->data() : nullptr;
+ const CryptoPlugin::SubSample * subSamples =
+ (CryptoPlugin::SubSample *)(subSamplesBuffer.get()->data());
+ err = channel->queueSecureInputBuffer(buffer, secure, key, iv, mode,
+ pattern, subSamples, numSubSamples, &errorDetailMsg);
+ }
if (err != OK) {
std::list<sp<AMessage>> errorList;
msg->removeEntryByName("buffer");
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a0a2891..a18dbfe 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -172,6 +172,7 @@
const char *getTrackType() const;
void resetInternal();
int64_t trackMetaDataSize();
+ bool isTimestampValid(int64_t timeUs);
private:
// A helper class to handle faster write box with table entries
@@ -1639,6 +1640,11 @@
ALOGV("buffer->range_length:%lld", (long long)buffer->range_length());
if (buffer->meta_data().findInt64(kKeySampleFileOffset, &offset)) {
ALOGV("offset:%lld, old_offset:%lld", (long long)offset, (long long)old_offset);
+ if (mMaxOffsetAppend > offset) {
+ // This has already been appended, skip updating mOffset value.
+ *bytesWritten = buffer->range_length();
+ return offset;
+ }
if (old_offset == offset) {
mOffset += buffer->range_length();
} else {
@@ -2430,6 +2436,47 @@
return OK;
}
+bool MPEG4Writer::isSampleMetadataValid(size_t trackIndex, int64_t timeUs) {
+ // Track Index starts from zero, so it should be at least 1 less than size.
+ if (trackIndex >= mTracks.size()) {
+ ALOGE("Incorrect trackIndex %zu, mTracks->size() %zu", trackIndex, mTracks.size());
+ return false;
+ }
+
+ List<Track *>::iterator it = mTracks.begin();
+
+ // (*it) is already pointing to trackIndex 0.
+ for (int i = 1; i <= trackIndex; i++) {
+ it++;
+ }
+
+ return (*it)->isTimestampValid(timeUs);
+}
+
+bool MPEG4Writer::Track::isTimestampValid(int64_t timeUs) {
+ // No timescale if HEIF
+ if (mIsHeif) {
+ return true;
+ }
+
+ // Make sure abs(timeUs) does not overflow
+ if (timeUs == INT64_MIN) {
+ return false;
+ }
+
+ // Ensure that the timeUs value does not have extremely low or high values
+ // that would cause an underflow or overflow, like in the calculation -
+ // mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6
+ if (abs(timeUs) >= (INT64_MAX - 5E5) / mTimeScale) {
+ return false;
+ }
+ // Limit check for calculations in ctts box
+ if (abs(timeUs) + kMaxCttsOffsetTimeUs >= INT64_MAX / mTimeScale) {
+ return false;
+ }
+ return true;
+}
+
bool MPEG4Writer::Track::isExifData(
MediaBufferBase *buffer, uint32_t *tiffHdrOffset) const {
if (!mIsHeif) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 6aac0e5..305d42f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -273,6 +273,37 @@
// XXX suppress until we get our representation right
static bool kEmitHistogram = false;
+typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
+
+// Multi access unit helpers
+static status_t generateFlagsFromAccessUnitInfo(
+ sp<AMessage> &msg, const sp<BufferInfosWrapper> &bufferInfos) {
+ msg->setInt64("timeUs", bufferInfos->value[0].mTimestamp);
+ msg->setInt32("flags", bufferInfos->value[0].mFlags);
+ // will prevent any access-unit info copy.
+ if (bufferInfos->value.size() > 1) {
+ uint32_t bufferFlags = 0;
+ uint32_t flagsInAllAU = BUFFER_FLAG_DECODE_ONLY | BUFFER_FLAG_CODEC_CONFIG;
+ uint32_t andFlags = flagsInAllAU;
+ int infoIdx = 0;
+ bool foundEndOfStream = false;
+ for ( ; infoIdx < bufferInfos->value.size() && !foundEndOfStream; ++infoIdx) {
+ bufferFlags |= bufferInfos->value[infoIdx].mFlags;
+ andFlags &= bufferInfos->value[infoIdx].mFlags;
+ if (bufferFlags & BUFFER_FLAG_END_OF_STREAM) {
+ foundEndOfStream = true;
+ }
+ }
+ bufferFlags = bufferFlags & (andFlags | (~flagsInAllAU));
+ if (infoIdx != bufferInfos->value.size()) {
+ ALOGE("Error: incorrect access-units");
+ return -EINVAL;
+ }
+ msg->setInt32("flags", bufferFlags);
+ }
+ return OK;
+}
+
static int64_t getId(IResourceManagerClient const * client) {
return (int64_t) client;
}
@@ -2224,7 +2255,10 @@
static void mapFormat(AString componentName, const sp<AMessage> &format, const char *kind,
bool reverse);
-mediametrics_handle_t MediaCodec::createMediaMetrics(const sp<AMessage>& format, uint32_t flags) {
+mediametrics_handle_t MediaCodec::createMediaMetrics(const sp<AMessage>& format,
+ uint32_t flags,
+ status_t* err) {
+ *err = OK;
mediametrics_handle_t nextMetricsHandle = mediametrics_create(kCodecKeyName);
bool isEncoder = (flags & CONFIGURE_FLAG_ENCODE);
@@ -2304,7 +2338,9 @@
mErrorLog.log(LOG_TAG, base::StringPrintf(
"Invalid size(s), width=%d, height=%d", mWidth, mHeight));
mediametrics_delete(nextMetricsHandle);
- return BAD_VALUE;
+ // Set the error code and return null handle.
+ *err = BAD_VALUE;
+ return 0;
}
} else {
@@ -2387,7 +2423,11 @@
updateCodecImportance(format);
// Create and set up metrics for this codec.
- mediametrics_handle_t nextMetricsHandle = createMediaMetrics(format, flags);
+ status_t err = OK;
+ mediametrics_handle_t nextMetricsHandle = createMediaMetrics(format, flags, &err);
+ if (err != OK) {
+ return err;
+ }
sp<AMessage> msg = new AMessage(kWhatConfigure, this);
msg->setMessage("format", format);
@@ -2422,7 +2462,6 @@
sp<AMessage> callback = mCallback;
- status_t err;
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure,
toMediaResourceSubType(mIsHardware, mDomain)));
@@ -3176,7 +3215,49 @@
msg->setInt64("timeUs", presentationTimeUs);
msg->setInt32("flags", flags);
msg->setPointer("errorDetailMsg", errorDetailMsg);
+ sp<AMessage> response;
+ return PostAndAwaitResponse(msg, &response);
+}
+status_t MediaCodec::queueInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &infos,
+ AString *errorDetailMsg) {
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
+ uint32_t bufferFlags = 0;
+ uint32_t flagsinAllAU = BUFFER_FLAG_DECODE_ONLY | BUFFER_FLAG_CODECCONFIG;
+ uint32_t andFlags = flagsinAllAU;
+ if (infos == nullptr || infos->value.empty()) {
+ ALOGE("ERROR: Large Audio frame with no BufferInfo");
+ return BAD_VALUE;
+ }
+ int infoIdx = 0;
+ std::vector<AccessUnitInfo> &accessUnitInfo = infos->value;
+ int64_t minTimeUs = accessUnitInfo.front().mTimestamp;
+ bool foundEndOfStream = false;
+ for ( ; infoIdx < accessUnitInfo.size() && !foundEndOfStream; ++infoIdx) {
+ bufferFlags |= accessUnitInfo[infoIdx].mFlags;
+ andFlags &= accessUnitInfo[infoIdx].mFlags;
+ if (bufferFlags & BUFFER_FLAG_END_OF_STREAM) {
+ foundEndOfStream = true;
+ }
+ }
+ bufferFlags = bufferFlags & (andFlags | (~flagsinAllAU));
+ if (infoIdx != accessUnitInfo.size()) {
+ ALOGE("queueInputBuffers has incorrect access-units");
+ return -EINVAL;
+ }
+ msg->setSize("index", index);
+ msg->setSize("offset", offset);
+ msg->setSize("size", size);
+ msg->setInt64("timeUs", minTimeUs);
+ // Make this represent flags for the entire buffer
+ // decodeOnly Flag is set only when all buffers are decodeOnly
+ msg->setInt32("flags", bufferFlags);
+ msg->setObject("accessUnitInfo", infos);
+ msg->setPointer("errorDetailMsg", errorDetailMsg);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
@@ -3217,27 +3298,50 @@
return err;
}
-status_t MediaCodec::queueBuffer(
+status_t MediaCodec::queueSecureInputBuffers(
size_t index,
- const std::shared_ptr<C2Buffer> &buffer,
- int64_t presentationTimeUs,
- uint32_t flags,
- const sp<AMessage> &tunings,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &auInfo,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
AString *errorDetailMsg) {
if (errorDetailMsg != NULL) {
errorDetailMsg->clear();
}
-
sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
- msg->setSize("index", index);
- sp<WrapperObject<std::shared_ptr<C2Buffer>>> obj{
- new WrapperObject<std::shared_ptr<C2Buffer>>{buffer}};
- msg->setObject("c2buffer", obj);
- msg->setInt64("timeUs", presentationTimeUs);
- msg->setInt32("flags", flags);
- if (tunings && tunings->countEntries() > 0) {
- msg->setMessage("tunings", tunings);
+ uint32_t bufferFlags = 0;
+ uint32_t flagsinAllAU = BUFFER_FLAG_DECODE_ONLY | BUFFER_FLAG_CODECCONFIG;
+ uint32_t andFlags = flagsinAllAU;
+ if (auInfo == nullptr
+ || auInfo->value.empty()
+ || cryptoInfos == nullptr
+ || cryptoInfos->value.empty()) {
+ ALOGE("ERROR: Large Audio frame with no BufferInfo/CryptoInfo");
+ return BAD_VALUE;
}
+ int infoIdx = 0;
+ std::vector<AccessUnitInfo> &accessUnitInfo = auInfo->value;
+ int64_t minTimeUs = accessUnitInfo.front().mTimestamp;
+ bool foundEndOfStream = false;
+ for ( ; infoIdx < accessUnitInfo.size() && !foundEndOfStream; ++infoIdx) {
+ bufferFlags |= accessUnitInfo[infoIdx].mFlags;
+ andFlags &= accessUnitInfo[infoIdx].mFlags;
+ if (bufferFlags & BUFFER_FLAG_END_OF_STREAM) {
+ foundEndOfStream = true;
+ }
+ }
+ bufferFlags = bufferFlags & (andFlags | (~flagsinAllAU));
+ if (infoIdx != accessUnitInfo.size()) {
+ ALOGE("queueInputBuffers has incorrect access-units");
+ return -EINVAL;
+ }
+ msg->setSize("index", index);
+ msg->setSize("offset", offset);
+ msg->setSize("ssize", size);
+ msg->setInt64("timeUs", minTimeUs);
+ msg->setInt32("flags", bufferFlags);
+ msg->setObject("accessUnitInfo", auInfo);
+ msg->setObject("cryptoInfos", cryptoInfos);
msg->setPointer("errorDetailMsg", errorDetailMsg);
sp<AMessage> response;
@@ -3246,46 +3350,76 @@
return err;
}
-status_t MediaCodec::queueEncryptedBuffer(
+status_t MediaCodec::queueBuffer(
size_t index,
- const sp<hardware::HidlMemory> &buffer,
- size_t offset,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- const uint8_t key[16],
- const uint8_t iv[16],
- CryptoPlugin::Mode mode,
- const CryptoPlugin::Pattern &pattern,
- int64_t presentationTimeUs,
- uint32_t flags,
+ const std::shared_ptr<C2Buffer> &buffer,
+ const sp<BufferInfosWrapper> &bufferInfos,
const sp<AMessage> &tunings,
AString *errorDetailMsg) {
if (errorDetailMsg != NULL) {
errorDetailMsg->clear();
}
+ if (bufferInfos == nullptr || bufferInfos->value.empty()) {
+ return BAD_VALUE;
+ }
+ status_t err = OK;
+ sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
+ msg->setSize("index", index);
+ sp<WrapperObject<std::shared_ptr<C2Buffer>>> obj{
+ new WrapperObject<std::shared_ptr<C2Buffer>>{buffer}};
+ msg->setObject("c2buffer", obj);
+ if (OK != (err = generateFlagsFromAccessUnitInfo(msg, bufferInfos))) {
+ return err;
+ }
+ msg->setObject("accessUnitInfo", bufferInfos);
+ if (tunings && tunings->countEntries() > 0) {
+ msg->setMessage("tunings", tunings);
+ }
+ msg->setPointer("errorDetailMsg", errorDetailMsg);
+ sp<AMessage> response;
+ err = PostAndAwaitResponse(msg, &response);
+ return err;
+}
+
+status_t MediaCodec::queueEncryptedBuffer(
+ size_t index,
+ const sp<hardware::HidlMemory> &buffer,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &bufferInfos,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
+ const sp<AMessage> &tunings,
+ AString *errorDetailMsg) {
+ if (errorDetailMsg != NULL) {
+ errorDetailMsg->clear();
+ }
+ if (bufferInfos == nullptr || bufferInfos->value.empty()) {
+ return BAD_VALUE;
+ }
+ if (cryptoInfos == nullptr || cryptoInfos->value.empty()) {
+ return BAD_VALUE;
+ }
+ status_t err = OK;
sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, this);
msg->setSize("index", index);
sp<WrapperObject<sp<hardware::HidlMemory>>> memory{
new WrapperObject<sp<hardware::HidlMemory>>{buffer}};
msg->setObject("memory", memory);
msg->setSize("offset", offset);
- msg->setPointer("subSamples", (void *)subSamples);
- msg->setSize("numSubSamples", numSubSamples);
- msg->setPointer("key", (void *)key);
- msg->setPointer("iv", (void *)iv);
- msg->setInt32("mode", mode);
- msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
- msg->setInt32("skipBlocks", pattern.mSkipBlocks);
- msg->setInt64("timeUs", presentationTimeUs);
- msg->setInt32("flags", flags);
+ msg->setSize("ssize", size);
+ msg->setObject("cryptoInfos", cryptoInfos);
+ msg->setObject("accessUnitInfo", bufferInfos);
+ if (OK != (err = generateFlagsFromAccessUnitInfo(msg, bufferInfos))) {
+ return err;
+ }
if (tunings && tunings->countEntries() > 0) {
msg->setMessage("tunings", tunings);
}
msg->setPointer("errorDetailMsg", errorDetailMsg);
sp<AMessage> response;
- status_t err = PostAndAwaitResponse(msg, &response);
+ err = PostAndAwaitResponse(msg, &response);
return err;
}
@@ -4760,6 +4894,35 @@
}
}
}
+ int32_t largeFrameParamMax = 0, largeFrameParamThreshold = 0;
+ if (format->findInt32(KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE, &largeFrameParamMax) ||
+ format->findInt32(KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE,
+ &largeFrameParamThreshold)) {
+ if (largeFrameParamMax > 0 || largeFrameParamThreshold > 0) {
+ if(mComponentName.startsWith("OMX")) {
+ mErrorLog.log(LOG_TAG,
+ "Large Frame params are not supported on OMX codecs."
+ "Currently only supported on C2 audio codec.");
+ PostReplyWithError(replyID, INVALID_OPERATION);
+ break;
+ }
+ AString mime;
+ CHECK(format->findString("mime", &mime));
+ if (!mime.startsWith("audio")) {
+ mErrorLog.log(LOG_TAG,
+ "Large Frame params only works with audio codec");
+ PostReplyWithError(replyID, INVALID_OPERATION);
+ break;
+ }
+ if (!(mFlags & kFlagIsAsync)) {
+ mErrorLog.log(LOG_TAG, "Large Frame audio" \
+ "config works only with async mode");
+ PostReplyWithError(replyID, INVALID_OPERATION);
+ break;
+ }
+ }
+ }
+
mReplyID = replyID;
setState(CONFIGURING);
@@ -5908,10 +6071,10 @@
status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
size_t index;
- size_t offset;
- size_t size;
- int64_t timeUs;
- uint32_t flags;
+ size_t offset = 0;
+ size_t size = 0;
+ int64_t timeUs = 0;
+ uint32_t flags = 0;
CHECK(msg->findSize("index", &index));
CHECK(msg->findInt64("timeUs", &timeUs));
CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -5956,22 +6119,26 @@
mErrorLog.log(LOG_TAG, "queuing secure buffer without mCrypto or mDescrambler!");
return -EINVAL;
}
- CHECK(msg->findPointer("subSamples", (void **)&subSamples));
- CHECK(msg->findSize("numSubSamples", &numSubSamples));
- CHECK(msg->findPointer("key", (void **)&key));
- CHECK(msg->findPointer("iv", (void **)&iv));
- CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
- CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
+ sp<RefBase> obj;
+ if (msg->findObject("cryptoInfos", &obj)) {
+ CHECK(msg->findSize("ssize", &size));
+ } else {
+ CHECK(msg->findPointer("subSamples", (void **)&subSamples));
+ CHECK(msg->findSize("numSubSamples", &numSubSamples));
+ CHECK(msg->findPointer("key", (void **)&key));
+ CHECK(msg->findPointer("iv", (void **)&iv));
+ CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
+ CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
- int32_t tmp;
- CHECK(msg->findInt32("mode", &tmp));
+ int32_t tmp;
+ CHECK(msg->findInt32("mode", &tmp));
- mode = (CryptoPlugin::Mode)tmp;
-
- size = 0;
- for (size_t i = 0; i < numSubSamples; ++i) {
- size += subSamples[i].mNumBytesOfClearData;
- size += subSamples[i].mNumBytesOfEncryptedData;
+ mode = (CryptoPlugin::Mode)tmp;
+ size = 0;
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ size += subSamples[i].mNumBytesOfClearData;
+ size += subSamples[i].mNumBytesOfEncryptedData;
+ }
}
}
@@ -5993,9 +6160,13 @@
"client does not own the buffer #%zu", index));
return -EACCES;
}
- auto setInputBufferParams = [this, &buffer]
+ auto setInputBufferParams = [this, &msg, &buffer]
(int64_t timeUs, uint32_t flags = 0) -> status_t {
status_t err = OK;
+ sp<RefBase> obj;
+ if (msg->findObject("accessUnitInfo", &obj)) {
+ buffer->meta()->setObject("accessUnitInfo", obj);
+ }
buffer->meta()->setInt64("timeUs", timeUs);
if (flags & BUFFER_FLAG_EOS) {
buffer->meta()->setInt32("eos", true);
@@ -6032,35 +6203,48 @@
return err;
};
auto buildCryptoInfoAMessage = [&](const sp<AMessage> & cryptoInfo, int32_t action) {
- size_t key_len = (key != nullptr)? 16 : 0;
- size_t iv_len = (iv != nullptr)? 16 : 0;
- sp<ABuffer> shared_key;
- sp<ABuffer> shared_iv;
- if (key_len > 0) {
- shared_key = ABuffer::CreateAsCopy((void*)key, key_len);
- }
- if (iv_len > 0) {
- shared_iv = ABuffer::CreateAsCopy((void*)iv, iv_len);
- }
- sp<ABuffer> subSamples_buffer =
- new ABuffer(sizeof(CryptoPlugin::SubSample) * numSubSamples);
- CryptoPlugin::SubSample * samples =
- (CryptoPlugin::SubSample *)(subSamples_buffer.get()->data());
- for (int s = 0 ; s < numSubSamples ; s++) {
- samples[s].mNumBytesOfClearData = subSamples[s].mNumBytesOfClearData;
- samples[s].mNumBytesOfEncryptedData = subSamples[s].mNumBytesOfEncryptedData;
- }
// set decrypt Action
cryptoInfo->setInt32("action", action);
cryptoInfo->setObject("buffer", buffer);
cryptoInfo->setInt32("secure", mFlags & kFlagIsSecure);
- cryptoInfo->setBuffer("key", shared_key);
- cryptoInfo->setBuffer("iv", shared_iv);
- cryptoInfo->setInt32("mode", (int)mode);
- cryptoInfo->setInt32("encryptBlocks", pattern.mEncryptBlocks);
- cryptoInfo->setInt32("skipBlocks", pattern.mSkipBlocks);
- cryptoInfo->setBuffer("subSamples", subSamples_buffer);
- cryptoInfo->setSize("numSubSamples", numSubSamples);
+ sp<RefBase> obj;
+ if (msg->findObject("cryptoInfos", &obj)) {
+ sp<CryptoInfosWrapper> infos{(CryptoInfosWrapper*)obj.get()};
+ sp<CryptoInfosWrapper> asyncInfos{
+ new CryptoInfosWrapper(std::vector<std::unique_ptr<CodecCryptoInfo>>())};
+ for (std::unique_ptr<CodecCryptoInfo> &info : infos->value) {
+ if (info) {
+ asyncInfos->value.emplace_back(new CryptoAsync::CryptoAsyncInfo(info));
+ }
+ }
+ buffer->meta()->setObject("cryptoInfos", asyncInfos);
+ } else {
+ size_t key_len = (key != nullptr)? 16 : 0;
+ size_t iv_len = (iv != nullptr)? 16 : 0;
+ sp<ABuffer> shared_key;
+ sp<ABuffer> shared_iv;
+ if (key_len > 0) {
+ shared_key = ABuffer::CreateAsCopy((void*)key, key_len);
+ }
+ if (iv_len > 0) {
+ shared_iv = ABuffer::CreateAsCopy((void*)iv, iv_len);
+ }
+ sp<ABuffer> subSamples_buffer =
+ new ABuffer(sizeof(CryptoPlugin::SubSample) * numSubSamples);
+ CryptoPlugin::SubSample * samples =
+ (CryptoPlugin::SubSample *)(subSamples_buffer.get()->data());
+ for (int s = 0 ; s < numSubSamples ; s++) {
+ samples[s].mNumBytesOfClearData = subSamples[s].mNumBytesOfClearData;
+ samples[s].mNumBytesOfEncryptedData = subSamples[s].mNumBytesOfEncryptedData;
+ }
+ cryptoInfo->setBuffer("key", shared_key);
+ cryptoInfo->setBuffer("iv", shared_iv);
+ cryptoInfo->setInt32("mode", (int)mode);
+ cryptoInfo->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+ cryptoInfo->setInt32("skipBlocks", pattern.mSkipBlocks);
+ cryptoInfo->setBuffer("subSamples", subSamples_buffer);
+ cryptoInfo->setSize("numSubSamples", numSubSamples);
+ }
};
if (c2Buffer || memory) {
sp<AMessage> tunings = NULL;
@@ -6070,15 +6254,37 @@
status_t err = OK;
if (c2Buffer) {
err = mBufferChannel->attachBuffer(c2Buffer, buffer);
+ // to prevent unnecessary copy for single info case.
+ if (msg->findObject("accessUnitInfo", &obj)) {
+ sp<BufferInfosWrapper> infos{(BufferInfosWrapper*)(obj.get())};
+ if (infos->value.size() == 1) {
+ msg->removeEntryByName("accessUnitInfo");
+ }
+ }
} else if (memory) {
AString errorDetailMsg;
- err = mBufferChannel->attachEncryptedBuffer(
- memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
- offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
+ if (msg->findObject("cryptoInfos", &obj)) {
+ buffer->meta()->setSize("ssize", size);
+ buffer->meta()->setObject("cryptoInfos", obj);
+ if (msg->findObject("accessUnitInfo", &obj)) {
+ // the reference will be same here and
+ // setBufferParams
+ buffer->meta()->setObject("accessUnitInfo", obj);
+ }
+ err = mBufferChannel->attachEncryptedBuffers(
+ memory,
+ offset,
+ buffer,
+ (mFlags & kFlagIsSecure),
+ &errorDetailMsg);
+ } else {
+ err = mBufferChannel->attachEncryptedBuffer(
+ memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
+ offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
+ }
if (err != OK && hasCryptoOrDescrambler()
&& (mFlags & kFlagUseCryptoAsync)) {
// create error detail
- AString errorDetailMsg;
sp<AMessage> cryptoErrorInfo = new AMessage();
buildCryptoInfoAMessage(cryptoErrorInfo, CryptoAsync::kActionDecrypt);
cryptoErrorInfo->setInt32("err", err);
@@ -6150,10 +6356,17 @@
}
}
if (mCryptoAsync) {
+ // TODO b/316565675 - enable async path for audio
// prepare a message and enqueue
sp<AMessage> cryptoInfo = new AMessage();
buildCryptoInfoAMessage(cryptoInfo, CryptoAsync::kActionDecrypt);
mCryptoAsync->decrypt(cryptoInfo);
+ } else if (msg->findObject("cryptoInfos", &obj)) {
+ buffer->meta()->setObject("cryptoInfos", obj);
+ err = mBufferChannel->queueSecureInputBuffers(
+ buffer,
+ (mFlags & kFlagIsSecure),
+ errorDetailMsg);
} else {
err = mBufferChannel->queueSecureInputBuffer(
buffer,
@@ -6505,10 +6718,11 @@
if (discardDecodeOnlyOutputBuffer(index)) {
continue;
}
+ sp<AMessage> msg = mCallback->dup();
const sp<MediaCodecBuffer> &buffer =
mPortBuffers[kPortIndexOutput][index].mData;
- sp<AMessage> msg = mCallback->dup();
- msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
+ int32_t outputCallbackID = CB_OUTPUT_AVAILABLE;
+ sp<RefBase> accessUnitInfoObj;
msg->setInt32("index", index);
msg->setSize("offset", buffer->offset());
msg->setSize("size", buffer->size());
@@ -6522,6 +6736,15 @@
CHECK(buffer->meta()->findInt32("flags", &flags));
msg->setInt32("flags", flags);
+ buffer->meta()->findObject("accessUnitInfo", &accessUnitInfoObj);
+ if (accessUnitInfoObj) {
+ outputCallbackID = CB_LARGE_FRAME_OUTPUT_AVAILABLE;
+ msg->setObject("accessUnitInfo", accessUnitInfoObj);
+ sp<BufferInfosWrapper> auInfo(
+ (decltype(auInfo.get()))accessUnitInfoObj.get());
+ auInfo->value.back().mFlags |= flags & BUFFER_FLAG_END_OF_STREAM;
+ }
+ msg->setInt32("callbackID", outputCallbackID);
statsBufferReceived(timeUs, buffer);
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index 22885c9..5dd8423 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -1,8 +1,5 @@
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
// writerTest fails about 5 out of 66
// { "name": "writerTest" },
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 24020d1..dc7d787 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -330,6 +330,7 @@
<!-- Video Quality control -->
<!-- supports QP bounding with standard keys -->
<Feature name="qp-bounds" />
+ <Feature name="bitrate-modes" value="VBR,CBR" />
<Attribute name="software-codec" />
</MediaCodec>
<MediaCodec name="c2.android.vp8.encoder" type="video/x-vnd.on2.vp8" variant="slow-cpu,!slow-cpu">
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index 0927653..bffb294 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -61,6 +61,36 @@
using hardware::cas::native::V1_0::IDescrambler;
+struct AccessUnitInfo {
+ uint32_t mFlags;
+ uint32_t mSize;
+ int64_t mTimestamp;
+ AccessUnitInfo(uint32_t flags, uint32_t size, int64_t ptsUs)
+ :mFlags(flags), mSize(size), mTimestamp(ptsUs) {
+ }
+ ~AccessUnitInfo() {}
+};
+
+struct CodecCryptoInfo {
+ size_t mNumSubSamples{0};
+ CryptoPlugin::SubSample *mSubSamples{nullptr};
+ uint8_t *mIv{nullptr};
+ uint8_t *mKey{nullptr};
+ enum CryptoPlugin::Mode mMode;
+ CryptoPlugin::Pattern mPattern;
+
+ virtual ~CodecCryptoInfo() {}
+protected:
+ CodecCryptoInfo():
+ mNumSubSamples(0),
+ mSubSamples(nullptr),
+ mIv(nullptr),
+ mKey(nullptr),
+ mMode{CryptoPlugin::kMode_Unencrypted},
+ mPattern{0, 0} {
+ }
+};
+
struct CodecParameterDescriptor {
std::string name;
AMessage::Type type;
@@ -362,6 +392,30 @@
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
AString *errorDetailMsg) = 0;
+
+ /**
+ * Queue a secure input buffer with multiple access units into the buffer channel.
+ *
+ * @param buffer The buffer to queue. The access unit delimiters and crypto
+ * subsample information is included in the buffer metadata.
+ * @param secure Whether the buffer is secure.
+ * @param errorDetailMsg The error message to be set in case of error.
+ * @return OK if successful;
+ * -ENOENT of the buffer is not known
+ * -ENOSYS if mCrypto is not set so that decryption is not
+ * possible;
+ * other errors if decryption failed.
+ */
+ virtual status_t queueSecureInputBuffers(
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString *errorDetailMsg) {
+ (void)buffer;
+ (void)secure;
+ (void)errorDetailMsg;
+ return -ENOSYS;
+ }
+
/**
* Attach a Codec 2.0 buffer to MediaCodecBuffer.
*
@@ -408,6 +462,34 @@
(void)errorDetailMsg;
return -ENOSYS;
}
+
+ /**
+ * Attach an encrypted HidlMemory buffer containing multiple access units to an index
+ *
+ * @param memory The memory to attach.
+ * @param offset index???
+ * @param buffer The MediaCodecBuffer to attach the memory to. The access
+ * unit delimiters and crypto subsample information is included
+ * in the buffer metadata.
+ * @param secure Whether the buffer is secure.
+ * @param errorDetailMsg The error message to be set if an error occurs.
+ * @return OK if successful;
+ * -ENOENT if index is not recognized
+ * -ENOSYS if attaching buffer is not possible or not supported
+ */
+ virtual status_t attachEncryptedBuffers(
+ const sp<hardware::HidlMemory> &memory,
+ size_t offset,
+ const sp<MediaCodecBuffer> &buffer,
+ bool secure,
+ AString* errorDetailMsg) {
+ (void)memory;
+ (void)offset;
+ (void)buffer;
+ (void)secure;
+ (void)errorDetailMsg;
+ return -ENOSYS;
+ }
/**
* Request buffer rendering at specified time.
*
diff --git a/media/libstagefright/include/media/stagefright/CryptoAsync.h b/media/libstagefright/include/media/stagefright/CryptoAsync.h
index b675518..acb3dae 100644
--- a/media/libstagefright/include/media/stagefright/CryptoAsync.h
+++ b/media/libstagefright/include/media/stagefright/CryptoAsync.h
@@ -85,6 +85,18 @@
kActionDecrypt = (1 << 0),
kActionAttachEncryptedBuffer = (1 << 1)
};
+
+ // This struct is meant to copy the mapped contents from the original info.
+ struct CryptoAsyncInfo : public CodecCryptoInfo {
+ public:
+ explicit CryptoAsyncInfo(const std::unique_ptr<CodecCryptoInfo> &info);
+ virtual ~CryptoAsyncInfo() = default;
+ protected:
+ // all backup buffers for the base object.
+ sp<ABuffer> mKeyBuffer;
+ sp<ABuffer> mIvBuffer;
+ sp<ABuffer> mSubSamplesBuffer;
+ };
protected:
// Message types for the looper
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 054a4b8..1ff8acf 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -77,6 +77,9 @@
virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
virtual status_t setNextFd(int fd);
+ // Returns true if the timestamp is valid which is compatible with the Mpeg4.
+ // Note that this overloads that method in the base class.
+ bool isSampleMetadataValid(size_t trackIndex, int64_t timeUs) override;
protected:
virtual ~MPEG4Writer();
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 2f94e5e..9ecb12e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -28,6 +28,7 @@
#include <media/MediaMetrics.h>
#include <media/MediaProfiles.h>
#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/CodecErrorLog.h>
#include <media/stagefright/FrameRenderTracker.h>
#include <media/stagefright/MediaHistogram.h>
@@ -56,7 +57,9 @@
struct AString;
struct BatteryChecker;
class BufferChannelBase;
+struct AccessUnitInfo;
struct CodecBase;
+struct CodecCryptoInfo;
struct CodecParameterDescriptor;
class IBatteryStats;
struct ICrypto;
@@ -78,6 +81,9 @@
using aidl::android::media::MediaResourceParcel;
using aidl::android::media::ClientConfigParcel;
+typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
+typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
+
struct MediaCodec : public AHandler {
enum Domain {
DOMAIN_UNKNOWN = 0,
@@ -115,6 +121,7 @@
CB_OUTPUT_FORMAT_CHANGED = 4,
CB_RESOURCE_RECLAIMED = 5,
CB_CRYPTO_ERROR = 6,
+ CB_LARGE_FRAME_OUTPUT_AVAILABLE = 7,
};
static const pid_t kNoPid = -1;
@@ -185,6 +192,13 @@
uint32_t flags,
AString *errorDetailMsg = NULL);
+ status_t queueInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &accessUnitInfo,
+ AString *errorDetailMsg = NULL);
+
status_t queueSecureInputBuffer(
size_t index,
size_t offset,
@@ -198,11 +212,18 @@
uint32_t flags,
AString *errorDetailMsg = NULL);
+ status_t queueSecureInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<BufferInfosWrapper> &accessUnitInfo,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
+ AString *errorDetailMsg = NULL);
+
status_t queueBuffer(
size_t index,
const std::shared_ptr<C2Buffer> &buffer,
- int64_t presentationTimeUs,
- uint32_t flags,
+ const sp<BufferInfosWrapper> &bufferInfos,
const sp<AMessage> &tunings,
AString *errorDetailMsg = NULL);
@@ -210,14 +231,9 @@
size_t index,
const sp<hardware::HidlMemory> &memory,
size_t offset,
- const CryptoPlugin::SubSample *subSamples,
- size_t numSubSamples,
- const uint8_t key[16],
- const uint8_t iv[16],
- CryptoPlugin::Mode mode,
- const CryptoPlugin::Pattern &pattern,
- int64_t presentationTimeUs,
- uint32_t flags,
+ size_t size,
+ const sp<BufferInfosWrapper> &bufferInfos,
+ const sp<CryptoInfosWrapper> &cryptoInfos,
const sp<AMessage> &tunings,
AString *errorDetailMsg = NULL);
@@ -321,7 +337,10 @@
friend struct ResourceManagerClient;
// to create the metrics associated with this codec.
- mediametrics_handle_t createMediaMetrics(const sp<AMessage>& format, uint32_t flags);
+ // Any error in this function will be captured by the output argument err.
+ mediametrics_handle_t createMediaMetrics(const sp<AMessage>& format,
+ uint32_t flags,
+ status_t* err);
private:
enum State {
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index f4c40e1..24ac2e8 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -697,6 +697,7 @@
inline constexpr char FEATURE_AdaptivePlayback[] = "adaptive-playback";
inline constexpr char FEATURE_EncodingStatistics[] = "encoding-statistics";
inline constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
+inline constexpr char FEATURE_MultipleFrames[] = "multiple-frames";
inline constexpr char FEATURE_PartialFrame[] = "partial-frame";
inline constexpr char FEATURE_QpBounds[] = "qp-bounds";
inline constexpr char FEATURE_SecurePlayback[] = "secure-playback";
diff --git a/media/libstagefright/include/media/stagefright/SkipCutBuffer.h b/media/libstagefright/include/media/stagefright/SkipCutBuffer.h
index 0fb5690..66f0bb1 100644
--- a/media/libstagefright/include/media/stagefright/SkipCutBuffer.h
+++ b/media/libstagefright/include/media/stagefright/SkipCutBuffer.h
@@ -59,6 +59,12 @@
int32_t mReadHead;
int32_t mCapacity;
char* mCutBuffer;
+
+ /*
+ * Added to use Access unit skip cut in Codec2 framework
+ */
+ friend class MultiAccessUnitSkipCutBuffer;
+
DISALLOW_EVIL_CONSTRUCTORS(SkipCutBuffer);
};
diff --git a/media/libstagefright/timedtext/TEST_MAPPING b/media/libstagefright/timedtext/TEST_MAPPING
index 35a5b11..f011d04 100644
--- a/media/libstagefright/timedtext/TEST_MAPPING
+++ b/media/libstagefright/timedtext/TEST_MAPPING
@@ -1,9 +1,5 @@
-// mappings for frameworks/av/media/libstagefright/timedtext
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
{ "name": "TimedTextUnitTest" }
]
}
diff --git a/media/mediaserver/manifest_media_c2_software.xml b/media/mediaserver/manifest_media_c2_software.xml
index d7fb1a0..31dfafb 100644
--- a/media/mediaserver/manifest_media_c2_software.xml
+++ b/media/mediaserver/manifest_media_c2_software.xml
@@ -1,5 +1,5 @@
<manifest version="1.0" type="framework">
- <hal>
+ <hal format="hidl" max-level="8">
<name>android.hardware.media.c2</name>
<transport>hwbinder</transport>
<version>1.2</version>
diff --git a/media/module/codecs/amrnb/TEST_MAPPING b/media/module/codecs/amrnb/TEST_MAPPING
index 343d08a..306921f 100644
--- a/media/module/codecs/amrnb/TEST_MAPPING
+++ b/media/module/codecs/amrnb/TEST_MAPPING
@@ -1,9 +1,5 @@
-// mappings for frameworks/av/media/libstagefright/codecs/amrnb
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
{ "name": "AmrnbDecoderTest"},
{ "name": "AmrnbEncoderTest"}
]
diff --git a/media/module/codecs/amrwb/TEST_MAPPING b/media/module/codecs/amrwb/TEST_MAPPING
new file mode 100644
index 0000000..3f05c90
--- /dev/null
+++ b/media/module/codecs/amrwb/TEST_MAPPING
@@ -0,0 +1,6 @@
+{
+ "postsubmit": [
+ { "name": "AmrwbDecoderTest"},
+ { "name": "AmrwbEncoderTest"}
+ ]
+}
diff --git a/media/module/codecs/amrwb/dec/TEST_MAPPING b/media/module/codecs/amrwb/dec/TEST_MAPPING
deleted file mode 100644
index 0278d26..0000000
--- a/media/module/codecs/amrwb/dec/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-// mappings for frameworks/av/media/libstagefright/codecs/amrwb
-{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
- { "name": "AmrwbDecoderTest"}
-
- ]
-}
diff --git a/media/module/codecs/amrwb/enc/TEST_MAPPING b/media/module/codecs/amrwb/enc/TEST_MAPPING
deleted file mode 100644
index 045e8b3..0000000
--- a/media/module/codecs/amrwb/enc/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-// mappings for frameworks/av/media/libstagefright/codecs/amrwbenc
-{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
- { "name": "AmrwbEncoderTest"}
-
- ]
-}
diff --git a/media/module/codecs/flac/TEST_MAPPING b/media/module/codecs/flac/TEST_MAPPING
new file mode 100644
index 0000000..725ea90
--- /dev/null
+++ b/media/module/codecs/flac/TEST_MAPPING
@@ -0,0 +1,5 @@
+{
+ "postsubmit": [
+ { "name": "FlacDecoderTest"}
+ ]
+}
diff --git a/media/module/codecs/flac/dec/test/Android.bp b/media/module/codecs/flac/dec/test/Android.bp
index a4c2735..8004c4a 100644
--- a/media/module/codecs/flac/dec/test/Android.bp
+++ b/media/module/codecs/flac/dec/test/Android.bp
@@ -28,6 +28,7 @@
cc_test {
name: "FlacDecoderTest",
gtest: true,
+ test_suites: ["device-tests"],
srcs: [
"FlacDecoderTest.cpp",
diff --git a/media/module/codecs/m4v_h263/TEST_MAPPING b/media/module/codecs/m4v_h263/TEST_MAPPING
index ba3ff1c..8599fa5 100644
--- a/media/module/codecs/m4v_h263/TEST_MAPPING
+++ b/media/module/codecs/m4v_h263/TEST_MAPPING
@@ -1,18 +1,6 @@
-// mappings for frameworks/av/media/libstagefright/codecs/m4v_h263
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
-
- // the decoder reports something bad about an unexpected newline in the *config file
- // and the config file looks like the AndroidTest.xml file that we put in there.
- // I don't get this from the Encoder -- and I don't see any substantive difference
- // between decode and encode AndroidTest.xml files -- except that encode does NOT
- // finish with a newline.
- // strange.
+ "postsubmit": [
{ "name": "Mpeg4H263DecoderTest"},
{ "name": "Mpeg4H263EncoderTest"}
-
]
}
diff --git a/media/module/codecs/mp3dec/TEST_MAPPING b/media/module/codecs/mp3dec/TEST_MAPPING
index 4ef4317..5faece6 100644
--- a/media/module/codecs/mp3dec/TEST_MAPPING
+++ b/media/module/codecs/mp3dec/TEST_MAPPING
@@ -1,9 +1,5 @@
-// mappings for frameworks/av/media/libstagefright/codecs/mp3dec
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
{ "name": "Mp3DecoderTest"}
]
}
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index f95fc4d..4fbfab1 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -25,6 +25,7 @@
#include <C2Component.h>
#include <C2PlatformSupport.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <codec2/hidl/1.0/ComponentStore.h>
#include <codec2/hidl/1.1/ComponentStore.h>
#include <codec2/hidl/1.2/ComponentStore.h>
@@ -818,31 +819,44 @@
}
bool registered = false;
- if (platformVersion >= __ANDROID_API_V__) {
- if (!aidlStore) {
- aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(
- std::make_shared<H2C2ComponentStore>(nullptr));
- }
- const std::string serviceName =
- std::string(c2_aidl::IComponentStore::descriptor) + "/software";
- binder_exception_t ex = AServiceManager_addService(
- aidlStore->asBinder().get(), serviceName.c_str());
- if (ex == EX_NONE) {
- registered = true;
- } else {
- LOG(ERROR) << "Cannot register software Codec2 AIDL service.";
+ const std::string aidlServiceName =
+ std::string(c2_aidl::IComponentStore::descriptor) + "/software";
+ if (__builtin_available(android __ANDROID_API_S__, *)) {
+ if (AServiceManager_isDeclared(aidlServiceName.c_str())) {
+ if (!aidlStore) {
+ aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(
+ std::make_shared<H2C2ComponentStore>(nullptr));
+ }
+ binder_exception_t ex = AServiceManager_addService(
+ aidlStore->asBinder().get(), aidlServiceName.c_str());
+ if (ex == EX_NONE) {
+ registered = true;
+ } else {
+ LOG(WARNING) << "Cannot register software Codec2 AIDL service. Exception: " << ex;
+ }
}
}
- if (!hidlStore) {
- hidlStore = ::android::sp<V1_2::utils::ComponentStore>::make(
- std::make_shared<H2C2ComponentStore>(nullptr));
- hidlVer = "1.2";
- }
- if (hidlStore->registerAsService("software") == android::OK) {
- registered = true;
+ // If the software component store isn't declared in the manifest, we don't
+ // need to create the service and register it.
+ using ::android::hidl::manager::V1_2::IServiceManager;
+ IServiceManager::Transport transport =
+ android::hardware::defaultServiceManager1_2()->getTransport(
+ V1_2::utils::ComponentStore::descriptor, "software");
+ if (transport == IServiceManager::Transport::HWBINDER) {
+ if (!hidlStore) {
+ hidlStore = ::android::sp<V1_2::utils::ComponentStore>::make(
+ std::make_shared<H2C2ComponentStore>(nullptr));
+ hidlVer = "1.2";
+ }
+ if (hidlStore->registerAsService("software") == android::OK) {
+ registered = true;
+ } else {
+ LOG(ERROR) << "Cannot register software Codec2 v" << hidlVer << " service.";
+ }
} else {
- LOG(ERROR) << "Cannot register software Codec2 v" << hidlVer << " service.";
+ LOG(INFO) << "The HIDL software Codec2 service is deprecated"
+ " so it is not being registered with hwservicemanager.";
}
if (registered) {
diff --git a/media/module/esds/TEST_MAPPING b/media/module/esds/TEST_MAPPING
index 9368b6d..0337743 100644
--- a/media/module/esds/TEST_MAPPING
+++ b/media/module/esds/TEST_MAPPING
@@ -1,9 +1,5 @@
-// mappings for frameworks/av/media/module/esds
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
{ "name": "ESDSTest" }
]
}
diff --git a/media/module/esds/tests/Android.bp b/media/module/esds/tests/Android.bp
index aea611e..427b275 100644
--- a/media/module/esds/tests/Android.bp
+++ b/media/module/esds/tests/Android.bp
@@ -25,6 +25,7 @@
cc_test {
name: "ESDSTest",
gtest: true,
+ test_suites: ["device-tests"],
srcs: [
"ESDSTest.cpp",
diff --git a/media/module/foundation/TEST_MAPPING b/media/module/foundation/TEST_MAPPING
index a70c352..ea4e4fd 100644
--- a/media/module/foundation/TEST_MAPPING
+++ b/media/module/foundation/TEST_MAPPING
@@ -1,9 +1,6 @@
-// mappings for frameworks/av/media/libstagefright/foundation
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
+ { "name": "AVCUtilsUnitTest" },
{ "name": "OpusHeaderTest" }
],
diff --git a/media/module/foundation/include/media/stagefright/foundation/AMessage.h b/media/module/foundation/include/media/stagefright/foundation/AMessage.h
index 7594565..b301c53 100644
--- a/media/module/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/module/foundation/include/media/stagefright/foundation/AMessage.h
@@ -356,6 +356,16 @@
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};
+/*
+ * Helper struct for wrapping any object with RefBase.
+ */
+template <typename T>
+struct WrapperObject : public RefBase {
+ WrapperObject(const T& v) : value(v) {}
+ WrapperObject(T&& v) : value(std::move(v)) {}
+ T value;
+};
+
} // namespace android
#endif // A_MESSAGE_H_
diff --git a/media/module/foundation/tests/AVCUtils/Android.bp b/media/module/foundation/tests/AVCUtils/Android.bp
index ee7db21..c306c73 100644
--- a/media/module/foundation/tests/AVCUtils/Android.bp
+++ b/media/module/foundation/tests/AVCUtils/Android.bp
@@ -28,6 +28,7 @@
cc_test {
name: "AVCUtilsUnitTest",
gtest: true,
+ test_suites: ["device-tests"],
srcs: [
"AVCUtilsUnitTest.cpp",
diff --git a/media/module/foundation/tests/AVCUtils/AndroidTest.xml b/media/module/foundation/tests/AVCUtils/AndroidTest.xml
index e30bfbf..315373f 100644
--- a/media/module/foundation/tests/AVCUtils/AndroidTest.xml
+++ b/media/module/foundation/tests/AVCUtils/AndroidTest.xml
@@ -16,7 +16,7 @@
<configuration description="Test module config for AVC Utils unit tests">
<option name="test-suite-tag" value="AVCUtilsUnitTest" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="false" />
+ <option name="cleanup" value="true" />
<option name="push" value="AVCUtilsUnitTest->/data/local/tmp/AVCUtilsUnitTest" />
</target_preparer>
diff --git a/media/module/id3/TEST_MAPPING b/media/module/id3/TEST_MAPPING
index 6106908..497d984 100644
--- a/media/module/id3/TEST_MAPPING
+++ b/media/module/id3/TEST_MAPPING
@@ -1,9 +1,5 @@
-// frameworks/av/media/libstagefright/id3
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
{ "name": "ID3Test" }
],
diff --git a/media/module/mpeg2ts/ATSParser.cpp b/media/module/mpeg2ts/ATSParser.cpp
index 86187bd..88c3cc2 100644
--- a/media/module/mpeg2ts/ATSParser.cpp
+++ b/media/module/mpeg2ts/ATSParser.cpp
@@ -440,6 +440,10 @@
ATSParser::CADescriptor *caDescriptor) {
bool found = false;
while (infoLength > 2) {
+ if (br->numBitsLeft() < 16) {
+ ALOGE("Not enough data left in bitreader");
+ return false;
+ }
unsigned descriptor_tag = br->getBits(8);
ALOGV(" tag = 0x%02x", descriptor_tag);
@@ -452,6 +456,10 @@
}
if (descriptor_tag == DESCRIPTOR_CA && descriptor_length >= 4) {
found = true;
+ if (br->numBitsLeft() < 32) {
+ ALOGE("Not enough data left in bitreader");
+ return false;
+ }
caDescriptor->mSystemID = br->getBits(16);
caDescriptor->mPID = br->getBits(16) & 0x1fff;
infoLength -= 4;
@@ -460,14 +468,24 @@
break;
} else {
infoLength -= descriptor_length;
- br->skipBits(descriptor_length * 8);
+ if (!br->skipBits(descriptor_length * 8)) {
+ ALOGE("Not enough data left in bitreader");
+ return false;
+ }
}
}
- br->skipBits(infoLength * 8);
+ if (!br->skipBits(infoLength * 8)) {
+ ALOGE("Not enough data left in bitreader");
+ return false;
+ }
return found;
}
status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
+ if (br->numBitsLeft() < 10) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned table_id = br->getBits(8);
ALOGV(" table_id = %u", table_id);
if (table_id != 0x02u) {
@@ -482,6 +500,10 @@
}
br->skipBits(1); // '0'
+ if (br->numBitsLeft() < 86) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
MY_LOGV(" reserved = %u", br->getBits(2));
unsigned section_length = br->getBits(12);
@@ -526,6 +548,10 @@
while (infoBytesRemaining >= 5) {
StreamInfo info;
+ if (br->numBitsLeft() < 40) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
info.mType = br->getBits(8);
ALOGV(" stream_type = 0x%02x", info.mType);
MY_LOGV(" reserved = %u", br->getBits(3));
@@ -545,6 +571,10 @@
info.mAudioPresentations.clear();
bool hasStreamCA = false;
while (ES_info_length > 2 && infoBytesRemaining >= 0) {
+ if (br->numBitsLeft() < 16) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned descriptor_tag = br->getBits(8);
ALOGV(" tag = 0x%02x", descriptor_tag);
@@ -562,21 +592,39 @@
if (descriptor_tag == DESCRIPTOR_DTS) {
info.mType = STREAMTYPE_DTS;
ES_info_length -= descriptor_length;
- br->skipBits(descriptor_length * 8);
+ if (!br->skipBits(descriptor_length * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
} else if (descriptor_tag == DESCRIPTOR_CA && descriptor_length >= 4) {
hasStreamCA = true;
+ if (br->numBitsLeft() < 32) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
streamCA.mSystemID = br->getBits(16);
streamCA.mPID = br->getBits(16) & 0x1fff;
ES_info_length -= descriptor_length;
descriptor_length -= 4;
streamCA.mPrivateData.assign(br->data(), br->data() + descriptor_length);
- br->skipBits(descriptor_length * 8);
+ if (!br->skipBits(descriptor_length * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
} else if (info.mType == STREAMTYPE_PES_PRIVATE_DATA &&
descriptor_tag == DESCRIPTOR_DVB_EXTENSION && descriptor_length >= 1) {
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned descTagExt = br->getBits(8);
ALOGV(" tag_ext = 0x%02x", descTagExt);
ES_info_length -= descriptor_length;
descriptor_length--;
+ if (br->numBitsLeft() < (descriptor_length * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
// The AC4 descriptor is used in the PSI PMT to identify streams which carry AC4
// audio.
if (descTagExt == EXT_DESCRIPTOR_DVB_AC4) {
@@ -594,6 +642,10 @@
br->skipBits(descriptor_length * 8);
} else if (descTagExt == EXT_DESCRIPTOR_DVB_AUDIO_PRESELECTION &&
descriptor_length >= 1) {
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
// DVB BlueBook A038 Table 110
unsigned num_preselections = br->getBits(5);
br->skipBits(3); // reserved
@@ -671,11 +723,17 @@
info.mAudioPresentations.push_back(std::move(ap));
}
} else {
- br->skipBits(descriptor_length * 8);
+ if (!br->skipBits(descriptor_length * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
}
} else {
ES_info_length -= descriptor_length;
- br->skipBits(descriptor_length * 8);
+ if (!br->skipBits(descriptor_length * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
}
}
if (hasStreamCA && !mParser->mCasManager->addStream(
@@ -694,6 +752,10 @@
if (infoBytesRemaining != 0) {
ALOGW("Section data remains unconsumed");
}
+ if (br->numBitsLeft() < 32) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned crc = br->getBits(32);
if (crc != mPMT_CRC) {
audioPresentationsChanged = true;
@@ -1261,6 +1323,10 @@
status_t ATSParser::Stream::parsePES(ABitReader *br, SyncEvent *event) {
const uint8_t *basePtr = br->data();
+ if (br->numBitsLeft() < 48) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned packet_startcode_prefix = br->getBits(24);
ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -1286,10 +1352,14 @@
&& stream_id != 0xff // program_stream_directory
&& stream_id != 0xf2 // DSMCC
&& stream_id != 0xf8) { // H.222.1 type E
- if (br->getBits(2) != 2u) {
+ if (br->numBitsLeft() < 2 || br->getBits(2) != 2u) {
return ERROR_MALFORMED;
}
+ if (br->numBitsLeft() < 22) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned PES_scrambling_control = br->getBits(2);
ALOGV("PES_scrambling_control = %u", PES_scrambling_control);
@@ -1328,19 +1398,19 @@
return ERROR_MALFORMED;
}
- if (br->getBits(4) != PTS_DTS_flags) {
+ if (br->numBitsLeft() < 7 || br->getBits(4) != PTS_DTS_flags) {
return ERROR_MALFORMED;
}
PTS = ((uint64_t)br->getBits(3)) << 30;
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 16 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
PTS |= ((uint64_t)br->getBits(15)) << 15;
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 16 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
PTS |= br->getBits(15);
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 1 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
@@ -1353,20 +1423,20 @@
return ERROR_MALFORMED;
}
- if (br->getBits(4) != 1u) {
+ if (br->numBitsLeft() < 7 || br->getBits(4) != 1u) {
return ERROR_MALFORMED;
}
DTS = ((uint64_t)br->getBits(3)) << 30;
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 16 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
DTS |= ((uint64_t)br->getBits(15)) << 15;
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 16 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
DTS |= br->getBits(15);
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 1 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
@@ -1381,22 +1451,30 @@
return ERROR_MALFORMED;
}
+ if (br->numBitsLeft() < 5) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
br->getBits(2);
uint64_t ESCR = ((uint64_t)br->getBits(3)) << 30;
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 16 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
ESCR |= ((uint64_t)br->getBits(15)) << 15;
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 16 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
ESCR |= br->getBits(15);
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 1 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
ALOGV("ESCR = %" PRIu64, ESCR);
+ if (br->numBitsLeft() < 10) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
MY_LOGV("ESCR_extension = %u", br->getBits(9));
if (br->getBits(1) != 1u) {
@@ -1411,18 +1489,25 @@
return ERROR_MALFORMED;
}
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 1 || br->getBits(1) != 1u) {
+ return ERROR_MALFORMED;
+ }
+ if (br->numBitsLeft() < 22) {
+ ALOGE("Not enough data left in bitreader!");
return ERROR_MALFORMED;
}
MY_LOGV("ES_rate = %u", br->getBits(22));
- if (br->getBits(1) != 1u) {
+ if (br->numBitsLeft() < 1 || br->getBits(1) != 1u) {
return ERROR_MALFORMED;
}
optional_bytes_remaining -= 3;
}
- br->skipBits(optional_bytes_remaining * 8);
+ if (!br->skipBits(optional_bytes_remaining * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
// ES data follows.
int32_t pesOffset = br->data() - basePtr;
@@ -1450,7 +1535,10 @@
PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
br->data(), dataLength, pesOffset, event);
- br->skipBits(dataLength * 8);
+ if (!br->skipBits(dataLength * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
} else {
onPayloadData(
PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
@@ -1465,15 +1553,13 @@
payloadSizeBits / 8, pesOffset);
}
} else if (stream_id == 0xbe) { // padding_stream
- if (PES_packet_length == 0u) {
+ if (PES_packet_length == 0u || !br->skipBits(PES_packet_length * 8)) {
return ERROR_MALFORMED;
}
- br->skipBits(PES_packet_length * 8);
} else {
- if (PES_packet_length == 0u) {
+ if (PES_packet_length == 0u || !br->skipBits(PES_packet_length * 8)) {
return ERROR_MALFORMED;
}
- br->skipBits(PES_packet_length * 8);
}
return OK;
@@ -1481,6 +1567,10 @@
uint32_t ATSParser::Stream::getPesScramblingControl(
ABitReader *br, int32_t *pesOffset) {
+ if (br->numBitsLeft() < 24) {
+ ALOGE("Not enough data left in bitreader!");
+ return 0;
+ }
unsigned packet_startcode_prefix = br->getBits(24);
ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -1491,6 +1581,7 @@
}
if (br->numBitsLeft() < 48) {
+ ALOGE("Not enough data left in bitreader!");
return 0;
}
@@ -1987,12 +2078,20 @@
}
void ATSParser::parseProgramAssociationTable(ABitReader *br) {
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return;
+ }
unsigned table_id = br->getBits(8);
ALOGV(" table_id = %u", table_id);
if (table_id != 0x00u) {
ALOGE("PAT data error!");
return ;
}
+ if (br->numBitsLeft() < 56) {
+ ALOGE("Not enough data left in bitreader!");
+ return;
+ }
unsigned section_syntax_indictor = br->getBits(1);
ALOGV(" section_syntax_indictor = %u", section_syntax_indictor);
@@ -2009,9 +2108,17 @@
MY_LOGV(" section_number = %u", br->getBits(8));
MY_LOGV(" last_section_number = %u", br->getBits(8));
+ // check for unsigned integer overflow before assigning it to numProgramBytes
+ if (section_length < 9) {
+ return;
+ }
size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */);
for (size_t i = 0; i < numProgramBytes / 4; ++i) {
+ if (br->numBitsLeft() < 32) {
+ ALOGE("Not enough data left in bitreader!");
+ return;
+ }
unsigned program_number = br->getBits(16);
ALOGV(" program_number = %u", program_number);
@@ -2049,6 +2156,10 @@
}
}
+ if (br->numBitsLeft() < 32) {
+ ALOGE("Not enough data left in bitreader!");
+ return;
+ }
MY_LOGV(" CRC = 0x%08x", br->getBits(32));
}
@@ -2070,9 +2181,16 @@
section->clear();
}
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned skip = br->getBits(8);
section->setSkipBytes(skip + 1); // skip filler bytes + pointer field itself
- br->skipBits(skip * 8);
+ if (!br->skipBits(skip * 8)) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
}
if (br->numBitsLeft() % 8 != 0) {
@@ -2157,6 +2275,10 @@
status_t ATSParser::parseAdaptationField(
ABitReader *br, unsigned PID, unsigned *random_access_indicator) {
*random_access_indicator = 0;
+ if (br->numBitsLeft() < 8) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned adaptation_field_length = br->getBits(8);
if (adaptation_field_length > 0) {
@@ -2227,6 +2349,10 @@
status_t ATSParser::parseTS(ABitReader *br, SyncEvent *event) {
ALOGV("---");
+ if (br->numBitsLeft() < 32) {
+ ALOGE("Not enough data left in bitreader!");
+ return ERROR_MALFORMED;
+ }
unsigned sync_byte = br->getBits(8);
if (sync_byte != 0x47u) {
ALOGE("[error] parseTS: return error as sync_byte=0x%x", sync_byte);
diff --git a/media/module/mpeg2ts/TEST_MAPPING b/media/module/mpeg2ts/TEST_MAPPING
index 9f4bbdf..536450f 100644
--- a/media/module/mpeg2ts/TEST_MAPPING
+++ b/media/module/mpeg2ts/TEST_MAPPING
@@ -1,9 +1,5 @@
-// frameworks/av/media/libstagefright/mpeg2ts
{
- // tests which require dynamic content
- // invoke with: atest -- --enable-module-dynamic-download=true
- // TODO(b/148094059): unit tests not allowed to download content
- "dynamic-presubmit": [
+ "postsubmit": [
{ "name": "Mpeg2tsUnitTest" }
]
}
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
index 111485c..aa632a4 100644
--- a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
+++ b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
@@ -45,18 +45,18 @@
pkt.size());
// packet is bigger than what the caller can handle,
- if (pkt.size() > len) {
+ if (pkt.size() - mPacketOffset > len) {
memcpy(data, pkt.data() + mPacketOffset, len);
mPacketOffset += len;
readAmt = len;
// packet is equal or smaller than the caller buffer
} else {
- memcpy(data, pkt.data() + mPacketOffset, pkt.size());
+ memcpy(data, pkt.data() + mPacketOffset, pkt.size() - mPacketOffset);
mPacketNumber++;
mPacketOffset = 0;
- readAmt = pkt.size();
+ readAmt = pkt.size() - mPacketOffset;
}
return readAmt;
diff --git a/services/Android.mk b/services/Android.mk
deleted file mode 100644
index c86a226..0000000
--- a/services/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-$(eval $(call declare-1p-copy-files,frameworks/av/services/audiopolicy,))
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 403fb9e..c78e98e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1933,7 +1933,7 @@
mHardwareStatus = AUDIO_HW_IDLE;
// Change parameters of the configuration each iteration until we find a
- // configuration that the device will support.
+ // configuration that the device will support, or HAL suggests what it supports.
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
for (auto testChannelMask : channelMasks) {
config.channel_mask = testChannelMask;
@@ -1943,11 +1943,16 @@
config.sample_rate = testSampleRate;
size_t bytes = 0;
+ audio_config_t loopConfig = config;
status_t result = dev->getInputBufferSize(&config, &bytes);
+ if (result == BAD_VALUE) {
+ // Retry with the config suggested by the HAL.
+ result = dev->getInputBufferSize(&config, &bytes);
+ }
if (result != OK || bytes == 0) {
+ config = loopConfig;
continue;
}
-
if (config.sample_rate != sampleRate || config.channel_mask != channelMask ||
config.format != format) {
uint32_t dstChannelCount = audio_channel_count_from_in_mask(channelMask);
@@ -4647,7 +4652,7 @@
case TransactionCode::GET_AUDIO_POLICY_CONFIG:
case TransactionCode::GET_AUDIO_MIX_PORT:
ALOGW("%s: transaction %d received from PID %d",
- __func__, code, IPCThreadState::self()->getCallingPid());
+ __func__, static_cast<int>(code), IPCThreadState::self()->getCallingPid());
// return status only for non void methods
switch (code) {
case TransactionCode::SET_RECORD_SILENCED:
@@ -4680,7 +4685,8 @@
case TransactionCode::SUPPORTS_BLUETOOTH_VARIABLE_LATENCY: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
- __func__, code, IPCThreadState::self()->getCallingPid(),
+ __func__, static_cast<int>(code),
+ IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
// return status only for non-void methods
switch (code) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 01e7b0d..c5931f6 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3046,7 +3046,7 @@
}
void PlaybackThread::onCodecFormatChanged(
- const std::basic_string<uint8_t>& metadataBs)
+ const std::vector<uint8_t>& metadataBs)
{
const auto weakPointerThis = wp<PlaybackThread>::fromExisting(this);
std::thread([this, metadataBs, weakPointerThis]() {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index b84079a..8a62ebe 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -925,7 +925,7 @@
protected:
// StreamHalInterfaceCodecFormatCallback implementation
void onCodecFormatChanged(
- const std::basic_string<uint8_t>& metadataBs) final;
+ const std::vector<uint8_t>& metadataBs) final;
// ThreadBase virtuals
void preExit() final EXCLUDES_ThreadBase_Mutex;
diff --git a/services/audioflinger/datapath/AudioStreamIn.cpp b/services/audioflinger/datapath/AudioStreamIn.cpp
index 24f3bb9..76618f4 100644
--- a/services/audioflinger/datapath/AudioStreamIn.cpp
+++ b/services/audioflinger/datapath/AudioStreamIn.cpp
@@ -56,15 +56,15 @@
return status;
}
- // Adjust for standby using HAL rate frames.
- // Only apply this correction if the HAL is getting PCM frames.
- if (mHalFormatHasProportionalFrames) {
+ if (mHalFormatHasProportionalFrames &&
+ (flags & AUDIO_INPUT_FLAG_DIRECT) == AUDIO_INPUT_FLAG_DIRECT) {
+ // For DirectRecord reset timestamp to 0 on standby.
const uint64_t adjustedPosition = (halPosition <= mFramesReadAtStandby) ?
0 : (halPosition - mFramesReadAtStandby);
// Scale from HAL sample rate to application rate.
*frames = adjustedPosition / mRateMultiplier;
} else {
- // For compressed formats.
+ // For compressed formats and linear PCM.
*frames = halPosition;
}
diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp
index 1830d15..9851f3a 100644
--- a/services/audioflinger/datapath/AudioStreamOut.cpp
+++ b/services/audioflinger/datapath/AudioStreamOut.cpp
@@ -99,15 +99,15 @@
return status;
}
- // Adjust for standby using HAL rate frames.
- // Only apply this correction if the HAL is getting PCM frames.
- if (mHalFormatHasProportionalFrames) {
+ if (mHalFormatHasProportionalFrames &&
+ (flags & AUDIO_OUTPUT_FLAG_DIRECT) == AUDIO_OUTPUT_FLAG_DIRECT) {
+ // For DirectTrack reset timestamp to 0 on standby.
const uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
0 : (halPosition - mFramesWrittenAtStandby);
// Scale from HAL sample rate to application rate.
*frames = adjustedPosition / mRateMultiplier;
} else {
- // For offloaded MP3 and other compressed formats.
+ // For offloaded MP3 and other compressed formats, and linear PCM.
*frames = halPosition;
}
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 39c80d8..44f75d8 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -236,7 +236,7 @@
auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
if (id == AUDIO_PORT_HANDLE_NONE) {
ALOGI("%s: no mapped id for audio device with type %d and address %s",
- __func__, in_audioDevice.type.type,
+ __func__, static_cast<int>(in_audioDevice.type.type),
in_audioDevice.address.toString().c_str());
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
@@ -265,7 +265,7 @@
auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
if (id == AUDIO_PORT_HANDLE_NONE) {
ALOGI("%s: no mapped id for audio device with type %d and address %s",
- __func__, in_audioDevice.type.type,
+ __func__, static_cast<int>(in_audioDevice.type.type),
in_audioDevice.address.toString().c_str());
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
diff --git a/services/audioparameterparser/Android.bp b/services/audioparameterparser/Android.bp
new file mode 100644
index 0000000..b3da333
--- /dev/null
+++ b/services/audioparameterparser/Android.bp
@@ -0,0 +1,69 @@
+// 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.
+
+package {
+ default_applicable_licenses: [
+ "frameworks_av_services_audioparameterparser_license",
+ ],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_av_services_audioparameterparser_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
+cc_defaults {
+ name: "android.hardware.audio.parameter_parser.example_defaults",
+ defaults: [
+ "latest_android_hardware_audio_core_ndk_shared",
+ ],
+
+ shared_libs: [
+ "av-audio-types-aidl-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.audio.parameter_parser.example_service",
+ system_ext_specific: true,
+ relative_install_path: "hw",
+
+ init_rc: ["android.hardware.audio.parameter_parser.example_service.rc"],
+
+ defaults: [
+ "android.hardware.audio.parameter_parser.example_defaults",
+ ],
+
+ srcs: [
+ "ParameterParser.cpp",
+ "main.cpp",
+ ],
+}
diff --git a/services/audioparameterparser/NOTICE b/services/audioparameterparser/NOTICE
new file mode 100644
index 0000000..44158cb
--- /dev/null
+++ b/services/audioparameterparser/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/services/audioparameterparser/ParameterParser.cpp b/services/audioparameterparser/ParameterParser.cpp
new file mode 100644
index 0000000..8d6a64f
--- /dev/null
+++ b/services/audioparameterparser/ParameterParser.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include "ParameterParser.h"
+
+#define LOG_TAG "Audio_ParameterParser"
+#include <android-base/logging.h>
+
+namespace vendor::audio::parserservice {
+
+using ::aidl::android::hardware::audio::core::VendorParameter;
+using ParameterScope = ::aidl::android::media::audio::IHalAdapterVendorExtension::ParameterScope;
+
+::ndk::ScopedAStatus ParameterParser::parseVendorParameterIds(ParameterScope in_scope,
+ const std::string& in_rawKeys,
+ std::vector<std::string>*) {
+ LOG(DEBUG) << __func__ << ": scope: " << toString(in_scope) << ", keys: " << in_rawKeys;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus ParameterParser::parseVendorParameters(ParameterScope in_scope,
+ const std::string& in_rawKeysAndValues,
+ std::vector<VendorParameter>*,
+ std::vector<VendorParameter>*) {
+ LOG(DEBUG) << __func__ << ": scope: " << toString(in_scope)
+ << ", keys/values: " << in_rawKeysAndValues;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus ParameterParser::parseBluetoothA2dpReconfigureOffload(
+ const std::string& in_rawValue, std::vector<VendorParameter>*) {
+ LOG(DEBUG) << __func__ << ": value: " << in_rawValue;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus ParameterParser::parseBluetoothLeReconfigureOffload(
+ const std::string& in_rawValue, std::vector<VendorParameter>*) {
+ LOG(DEBUG) << __func__ << ": value: " << in_rawValue;
+ return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus ParameterParser::processVendorParameters(
+ ParameterScope in_scope, const std::vector<VendorParameter>& in_parameters, std::string*) {
+ LOG(DEBUG) << __func__ << ": scope: " << toString(in_scope)
+ << ", parameters: " << ::android::internal::ToString(in_parameters);
+ return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace vendor::audio::parserservice
diff --git a/services/audioparameterparser/ParameterParser.h b/services/audioparameterparser/ParameterParser.h
new file mode 100644
index 0000000..1e0e333
--- /dev/null
+++ b/services/audioparameterparser/ParameterParser.h
@@ -0,0 +1,57 @@
+/*
+ * 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 <aidl/android/media/audio/BnHalAdapterVendorExtension.h>
+
+namespace vendor::audio::parserservice {
+
+class ParameterParser : public ::aidl::android::media::audio::BnHalAdapterVendorExtension {
+ public:
+ ParameterParser() = default;
+
+ private:
+ ::ndk::ScopedAStatus parseVendorParameterIds(
+ ::aidl::android::media::audio::IHalAdapterVendorExtension::ParameterScope in_scope,
+ const std::string& in_rawKeys, std::vector<std::string>* _aidl_return) override;
+
+ ::ndk::ScopedAStatus parseVendorParameters(
+ ::aidl::android::media::audio::IHalAdapterVendorExtension::ParameterScope in_scope,
+ const std::string& in_rawKeysAndValues,
+ std::vector<::aidl::android::hardware::audio::core::VendorParameter>*
+ out_syncParameters,
+ std::vector<::aidl::android::hardware::audio::core::VendorParameter>*
+ out_asyncParameters) override;
+
+ ::ndk::ScopedAStatus parseBluetoothA2dpReconfigureOffload(
+ const std::string& in_rawValue,
+ std::vector<::aidl::android::hardware::audio::core::VendorParameter>* _aidl_return)
+ override;
+
+ ::ndk::ScopedAStatus parseBluetoothLeReconfigureOffload(
+ const std::string& in_rawValue,
+ std::vector<::aidl::android::hardware::audio::core::VendorParameter>* _aidl_return)
+ override;
+
+ ::ndk::ScopedAStatus processVendorParameters(
+ ::aidl::android::media::audio::IHalAdapterVendorExtension::ParameterScope in_scope,
+ const std::vector<::aidl::android::hardware::audio::core::VendorParameter>&
+ in_parameters,
+ std::string* _aidl_return) override;
+};
+
+} // namespace vendor::audio::parserservice
diff --git a/services/audioparameterparser/android.hardware.audio.parameter_parser.example_service.rc b/services/audioparameterparser/android.hardware.audio.parameter_parser.example_service.rc
new file mode 100644
index 0000000..b6aca5c
--- /dev/null
+++ b/services/audioparameterparser/android.hardware.audio.parameter_parser.example_service.rc
@@ -0,0 +1,6 @@
+service audio_parameter_parser_service /system_ext/bin/hw/android.hardware.audio.parameter_parser.example_service
+ class core
+ user audioserver
+ group media
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh HighPerformance
diff --git a/services/audioparameterparser/main.cpp b/services/audioparameterparser/main.cpp
new file mode 100644
index 0000000..d22eb55
--- /dev/null
+++ b/services/audioparameterparser/main.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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_TAG "Audio_ParameterParser"
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "ParameterParser.h"
+
+using vendor::audio::parserservice::ParameterParser;
+
+int main() {
+ // This is a debug implementation, always enable debug logging.
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+
+ auto parser = ndk::SharedRefBase::make<ParameterParser>();
+ const std::string parserFqn =
+ std::string().append(ParameterParser::descriptor).append("/default");
+ binder_status_t status =
+ AServiceManager_addService(parser->asBinder().get(), parserFqn.c_str());
+ if (status != STATUS_OK) {
+ LOG(ERROR) << "failed to register service for \"" << parserFqn << "\"";
+ }
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index dd222de..c7d2e6b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -156,9 +156,9 @@
for (const auto sampleRate : profile->getSampleRates()) {
for (const auto channelMask : profile->getChannels()) {
const audio_config_base_t config = {
- .format = profile->getFormat(),
.sample_rate = sampleRate,
- .channel_mask = channelMask
+ .channel_mask = channelMask,
+ .format = profile->getFormat(),
};
for (const auto mixerBehavior : mMixerBehaviors) {
mixerAttributes->push_back({
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2fd908f..3dfd950 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -122,7 +122,8 @@
device->toAudioPort(&devicePort);
if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
status != OK) {
- ALOGE("Error %d while setting connected state for device %s", state,
+ ALOGE("Error %d while setting connected state for device %s",
+ static_cast<int>(state),
device->getDeviceTypeAddr().toString(false).c_str());
}
}
@@ -3265,6 +3266,7 @@
// requested device or one of the devices selected by the engine for this stream
// - For default requested device (AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME), apply volume only if
// no specific device volume value exists for currently selected device.
+ // - Only apply the volume if the requested device is the desired device for volume control.
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
DeviceTypeSet curDevices = desc->devices().types();
@@ -3284,7 +3286,8 @@
if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
curSrcDevices.insert(device);
applyVolume = (curSrcDevices.find(
- Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end());
+ Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end())
+ && Volume::getDeviceForVolume(curSrcDevices) == device;
} else {
applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
}
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 7859c2c..72582d3 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -821,7 +821,7 @@
spatializerMode = HeadTracking::Mode::RELATIVE_SCREEN;
break;
default:
- LOG_ALWAYS_FATAL("Unknown mode: %d", mode);
+ LOG_ALWAYS_FATAL("Unknown mode: %d", static_cast<int>(mode));
}
}
mActualHeadTrackingMode = spatializerMode;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index ae5e9a1..0bc2e8a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2256,39 +2256,65 @@
// Enable/disable camera service watchdog
client->setCameraServiceWatchdog(mCameraServiceWatchdogEnabled);
- // Set rotate-and-crop override behavior
- if (mOverrideRotateAndCropMode != ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
- client->setRotateAndCropOverride(mOverrideRotateAndCropMode);
- } else if (overrideToPortrait && portraitRotation != 0) {
- uint8_t rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_AUTO;
- switch (portraitRotation) {
- case 90:
- rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90;
- break;
- case 180:
- rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_180;
- break;
- case 270:
- rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_270;
- break;
- default:
- ALOGE("Unexpected portrait rotation: %d", portraitRotation);
- break;
+ CameraMetadata chars;
+ bool rotateAndCropSupported = true;
+ err = mCameraProviderManager->getCameraCharacteristics(cameraId, overrideForPerfClass,
+ &chars, overrideToPortrait);
+ if (err == OK) {
+ auto availableRotateCropEntry = chars.find(
+ ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES);
+ if (availableRotateCropEntry.count <= 1) {
+ rotateAndCropSupported = false;
}
- client->setRotateAndCropOverride(rotateAndCropMode);
} else {
- client->setRotateAndCropOverride(
- mCameraServiceProxyWrapper->getRotateAndCropOverride(
- clientPackageName, facing, multiuser_get_user_id(clientUid)));
+ ALOGE("%s: Unable to query static metadata for camera %s: %s (%d)", __FUNCTION__,
+ cameraId.c_str(), strerror(-err), err);
}
- // Set autoframing override behaviour
- if (mOverrideAutoframingMode != ANDROID_CONTROL_AUTOFRAMING_AUTO) {
- client->setAutoframingOverride(mOverrideAutoframingMode);
- } else {
- client->setAutoframingOverride(
- mCameraServiceProxyWrapper->getAutoframingOverride(
- clientPackageName));
+ if (rotateAndCropSupported) {
+ // Set rotate-and-crop override behavior
+ if (mOverrideRotateAndCropMode != ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ client->setRotateAndCropOverride(mOverrideRotateAndCropMode);
+ } else if (overrideToPortrait && portraitRotation != 0) {
+ uint8_t rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_AUTO;
+ switch (portraitRotation) {
+ case 90:
+ rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90;
+ break;
+ case 180:
+ rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_180;
+ break;
+ case 270:
+ rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_270;
+ break;
+ default:
+ ALOGE("Unexpected portrait rotation: %d", portraitRotation);
+ break;
+ }
+ client->setRotateAndCropOverride(rotateAndCropMode);
+ } else {
+ client->setRotateAndCropOverride(
+ mCameraServiceProxyWrapper->getRotateAndCropOverride(
+ clientPackageName, facing, multiuser_get_user_id(clientUid)));
+ }
+ }
+
+ bool autoframingSupported = true;
+ auto availableAutoframingEntry = chars.find(ANDROID_CONTROL_AUTOFRAMING_AVAILABLE);
+ if ((availableAutoframingEntry.count == 1) && (availableAutoframingEntry.data.u8[0] ==
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_FALSE)) {
+ autoframingSupported = false;
+ }
+
+ if (autoframingSupported) {
+ // Set autoframing override behaviour
+ if (mOverrideAutoframingMode != ANDROID_CONTROL_AUTOFRAMING_AUTO) {
+ client->setAutoframingOverride(mOverrideAutoframingMode);
+ } else {
+ client->setAutoframingOverride(
+ mCameraServiceProxyWrapper->getAutoframingOverride(
+ clientPackageName));
+ }
}
// Set camera muting behavior
@@ -5146,8 +5172,7 @@
for (auto& listener : mListenerList) {
bool isVendorListener = listener->isVendorListener();
if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
- listener->getListenerPid(), listener->getListenerUid()) ||
- isVendorListener) {
+ listener->getListenerPid(), listener->getListenerUid())) {
ALOGV("Skipping discovery callback for system-only camera device %s",
cameraId.c_str());
continue;
diff --git a/services/mediaresourcemanager/DefaultResourceModel.cpp b/services/mediaresourcemanager/DefaultResourceModel.cpp
index 7bad715..990df82 100644
--- a/services/mediaresourcemanager/DefaultResourceModel.cpp
+++ b/services/mediaresourcemanager/DefaultResourceModel.cpp
@@ -44,7 +44,9 @@
clients.clear();
MediaResourceParcel mediaResource{.type = reclimRequestInfo.mResources[0].type,
.subType = reclimRequestInfo.mResources[0].subType};
- ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};
+ ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid,
+ reclimRequestInfo.mClientId,
+ &mediaResource};
// Resolve the secure-unsecure codec conflicts if there is any.
switch (reclimRequestInfo.mResources[0].type) {
@@ -116,7 +118,9 @@
const ReclaimRequestInfo& reclimRequestInfo,
std::vector<ClientInfo>& clients) {
MediaResourceParcel mediaResource;
- ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};
+ ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid,
+ reclimRequestInfo.mClientId,
+ &mediaResource};
// 1. Look to find the client(s) with the other resources, for the given
// primary type.
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index af85772..cd00937 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -43,6 +43,28 @@
MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_NO_CLIENTS;
using stats::media_metrics::\
MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
+using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED;
+using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_AUDIO;
+using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_VIDEO;
+using stats::media_metrics::MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_IMAGE;
+
+// Map MediaResourceSubType to stats::media_metrics::CodecType
+inline int32_t getMetricsCodecType(MediaResourceSubType codecType) {
+ switch (codecType) {
+ case MediaResourceSubType::kHwAudioCodec:
+ case MediaResourceSubType::kSwAudioCodec:
+ return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_AUDIO;
+ case MediaResourceSubType::kHwVideoCodec:
+ case MediaResourceSubType::kSwVideoCodec:
+ return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_VIDEO;
+ case MediaResourceSubType::kHwImageCodec:
+ case MediaResourceSubType::kSwImageCodec:
+ return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_IMAGE;
+ case MediaResourceSubType::kUnspecifiedSubType:
+ return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED;
+ }
+ return MEDIA_CODEC_STARTED__CODEC_TYPE__CODEC_TYPE_UNSPECIFIED;
+}
inline const char* getCodecType(MediaResourceSubType codecType) {
switch (codecType) {
@@ -229,7 +251,7 @@
clientConfig.clientInfo.uid,
clientConfig.id,
clientConfig.clientInfo.name.c_str(),
- static_cast<int32_t>(clientConfig.codecType),
+ getMetricsCodecType(clientConfig.codecType),
clientConfig.isEncoder,
isHardwareCodec(clientConfig.codecType),
clientConfig.width, clientConfig.height,
@@ -311,7 +333,7 @@
clientConfig.clientInfo.uid,
clientConfig.id,
clientConfig.clientInfo.name.c_str(),
- static_cast<int32_t>(clientConfig.codecType),
+ getMetricsCodecType(clientConfig.codecType),
clientConfig.isEncoder,
isHardwareCodec(clientConfig.codecType),
clientConfig.width, clientConfig.height,
@@ -425,6 +447,42 @@
#endif
}
+inline void pushReclaimStats(int32_t callingPid,
+ int32_t requesterUid,
+ int requesterPriority,
+ const std::string& clientName,
+ int32_t noOfConcurrentCodecs,
+ int32_t reclaimStatus,
+ int32_t noOfCodecsReclaimed = 0,
+ int32_t targetIndex = -1,
+ int32_t targetClientPid = -1,
+ int32_t targetClientUid = -1,
+ int32_t targetPriority = -1) {
+ // Post the pushed atom
+ int result = stats_write(
+ MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
+ requesterUid,
+ requesterPriority,
+ clientName.c_str(),
+ noOfConcurrentCodecs,
+ reclaimStatus,
+ noOfCodecsReclaimed,
+ targetIndex,
+ targetClientUid,
+ targetPriority);
+ ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
+ "Requester[pid(%d): uid(%d): priority(%d)] "
+ "Codec: [%s] "
+ "No of concurrent codecs: %d "
+ "Reclaim Status: %d "
+ "No of codecs reclaimed: %d "
+ "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d",
+ __func__, callingPid, requesterUid, requesterPriority,
+ clientName.c_str(), noOfConcurrentCodecs,
+ reclaimStatus, noOfCodecsReclaimed,
+ targetIndex, targetClientPid, targetClientUid, targetPriority, result);
+}
+
void ResourceManagerMetrics::pushReclaimAtom(const ClientInfoParcel& clientInfo,
const std::vector<int>& priorities,
const std::vector<ClientInfo>& targetClients,
@@ -463,33 +521,34 @@
MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED__RECLAIM_STATUS__RECLAIM_FAILED_RECLAIM_RESOURCES;
}
}
+
+ if (targetClients.empty()) {
+ // Push the reclaim atom to stats.
+ pushReclaimStats(callingPid,
+ requesterUid,
+ requesterPriority,
+ clientName,
+ noOfConcurrentCodecs,
+ reclaimStatus);
+ return;
+ }
+
int32_t noOfCodecsReclaimed = targetClients.size();
int32_t targetIndex = 1;
for (const ClientInfo& targetClient : targetClients) {
int targetPriority = priorities[targetIndex];
- // Post the pushed atom
- int result = stats_write(
- MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED,
- requesterUid,
- requesterPriority,
- clientName.c_str(),
- noOfConcurrentCodecs,
- reclaimStatus,
- noOfCodecsReclaimed,
- targetIndex,
- targetClient.mUid,
- targetPriority);
- ALOGI("%s: Pushed MEDIA_CODEC_RECLAIM_REQUEST_COMPLETED atom: "
- "Requester[pid(%d): uid(%d): priority(%d)] "
- "Codec: [%s] "
- "No of concurrent codecs: %d "
- "Reclaim Status: %d "
- "No of codecs reclaimed: %d "
- "Target[%d][pid(%d): uid(%d): priority(%d)] result: %d",
- __func__, callingPid, requesterUid, requesterPriority,
- clientName.c_str(), noOfConcurrentCodecs,
- reclaimStatus, noOfCodecsReclaimed,
- targetIndex, targetClient.mPid, targetClient.mUid, targetPriority, result);
+ // Push the reclaim atom to stats.
+ pushReclaimStats(callingPid,
+ requesterUid,
+ requesterPriority,
+ clientName,
+ noOfConcurrentCodecs,
+ reclaimStatus,
+ noOfCodecsReclaimed,
+ targetIndex,
+ targetClient.mPid,
+ targetClient.mUid,
+ targetPriority);
targetIndex++;
}
}
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.h b/services/mediaresourcemanager/ResourceManagerMetrics.h
index a9bc34b..7a5a89f 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.h
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.h
@@ -96,7 +96,32 @@
};
//
-// ResourceManagerMetrics class that maintaines concurrent codec count based:
+// Resource Manager Metrics is designed to answer some of the questions like:
+// - What apps are causing reclaim and what apps are targeted (reclaimed from) in the process?
+// - which apps use the most codecs and the most codec memory?
+// - What is the % of total successful reclaims?
+//
+// Though, it's not in the context of this class, metrics should also answer:
+// - what % of codec errors are due to codec being reclaimed?
+// - What % of successful codec creation(start) requires codec reclaims?
+// - How often codec start fails even after successful reclaim?
+//
+// The metrics are collected to analyze and understand the codec resource usage
+// and use that information to help with:
+// - minimize the no of reclaims
+// - reduce the codec start delays by minimizing no of times we try to reclaim
+// - minimize the reclaim errors in codec records
+//
+// Success metrics for Resource Manager Service could be defined as:
+// - increase in sucecssful codec creation for the foreground apps
+// - reduce the number of reclaims for codecs
+// - reduce the time to create codec
+//
+// We would like to use this data to come up with a better resource management that would:
+// - increase the successful codec creation (for all kind of apps)
+// - decrease the codec errors due to resources
+//
+// This class that maintains concurrent codec counts based on:
//
// 1. # of concurrent active codecs (initialized, but aren't released yet) of given
// implementation (by codec name) across the system.
@@ -111,7 +136,7 @@
// This should help with understanding the (video) memory usage per
// application.
//
-//
+
class ResourceManagerMetrics {
public:
ResourceManagerMetrics(const sp<ProcessInfoInterface>& processInfo);
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 3a02443..d37d893 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -474,6 +474,7 @@
const std::vector<MediaResourceParcel>& resources,
std::vector<ClientInfo>& targetClients) {
int32_t callingPid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
std::scoped_lock lock{mLock};
if (!mProcessInfo->isPidTrusted(callingPid)) {
pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
@@ -508,7 +509,7 @@
if (secureCodec != NULL) {
MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
.subType = secureCodec->subType};
- ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, &mediaResource};
if (!mSupportsMultipleSecureCodecs) {
if (!getAllClients_l(resourceRequestInfo, targetClients)) {
return false;
@@ -525,7 +526,7 @@
if (!mSupportsSecureWithNonSecureCodec) {
MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
.subType = nonSecureCodec->subType};
- ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, &mediaResource};
if (!getAllClients_l(resourceRequestInfo, targetClients)) {
return false;
}
@@ -533,7 +534,7 @@
}
if (drmSession != NULL) {
- ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, drmSession};
getClientForResource_l(resourceRequestInfo, targetClients);
if (targetClients.size() == 0) {
return false;
@@ -542,18 +543,18 @@
if (targetClients.size() == 0 && graphicMemory != nullptr) {
// if no secure/non-secure codec conflict, run second pass to handle other resources.
- ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, graphicMemory};
getClientForResource_l(resourceRequestInfo, targetClients);
}
if (targetClients.size() == 0) {
// if we are here, run the third pass to free one codec with the same type.
if (secureCodec != nullptr) {
- ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, secureCodec};
getClientForResource_l(resourceRequestInfo, targetClients);
}
if (nonSecureCodec != nullptr) {
- ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, nonSecureCodec};
getClientForResource_l(resourceRequestInfo, targetClients);
}
}
@@ -562,12 +563,12 @@
// if we are here, run the fourth pass to free one codec with the different type.
if (secureCodec != nullptr) {
MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
- ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, &temp};
getClientForResource_l(resourceRequestInfo, targetClients);
}
if (nonSecureCodec != nullptr) {
MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
- ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ ResourceRequestInfo resourceRequestInfo{callingPid, clientId, &temp};
getClientForResource_l(resourceRequestInfo, targetClients);
}
}
@@ -585,18 +586,21 @@
// Check if there are any resources to be reclaimed before processing.
if (resources.empty()) {
+ // Invalid reclaim request. So no need to log.
return Status::ok();
}
std::vector<ClientInfo> targetClients;
- if (!getTargetClients(clientInfo, resources, targetClients)) {
- // Nothing to reclaim from.
+ if (getTargetClients(clientInfo, resources, targetClients)) {
+ // Reclaim all the target clients.
+ *_aidl_return = reclaimUnconditionallyFrom(targetClients);
+ } else {
+ // No clients to reclaim from.
ALOGI("%s: There aren't any clients to reclaim from", __func__);
- return Status::ok();
+ // We need to log this failed reclaim as "no clients to reclaim from".
+ targetClients.clear();
}
- *_aidl_return = reclaimUnconditionallyFrom(targetClients);
-
// Log Reclaim Pushed Atom to statsd
pushReclaimAtom(clientInfo, targetClients, *_aidl_return);
@@ -914,6 +918,11 @@
for (auto& [pid, infos] : mMap) {
for (const auto& [id, info] : infos) {
+ if (pid == resourceRequestInfo.mCallingPid && id == resourceRequestInfo.mClientId) {
+ ALOGI("%s: Skip the client[%jd] for which the resource request is made",
+ __func__, id);
+ continue;
+ }
if (hasResourceType(type, subType, info.resources)) {
if (!isCallingPriorityHigher_l(resourceRequestInfo.mCallingPid, pid)) {
// some higher/equal priority process owns the resource,
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
index af093ca..0a0a8f4 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -248,7 +248,7 @@
// Use the Resource Model to get a list of all the clients that hold the
// needed/requested resources.
uint32_t callingImportance = std::max(0, clientInfo.importance);
- ReclaimRequestInfo reclaimRequestInfo{callingPid, callingImportance, resources};
+ ReclaimRequestInfo reclaimRequestInfo{callingPid, clientInfo.id, callingImportance, resources};
std::vector<ClientInfo> clients;
if (!mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients)) {
if (clients.empty()) {
@@ -300,7 +300,10 @@
// Use the DefaultResourceModel to get all the clients with the resources requested.
std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
- ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, 0, resources};
+ ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid,
+ resourceRequestInfo.mClientId,
+ 0, // default importance
+ resources};
std::vector<ClientInfo> clients;
mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
index 32cb219..e8f1515 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -166,11 +166,13 @@
/*
* Resource Reclaim request info that encapsulates
* - the calling/requesting process pid.
+ * - id of the client that made reclaim request.
* - the calling/requesting client's importance.
* - the list of resources requesting (to be reclaimed from others)
*/
struct ReclaimRequestInfo {
int mCallingPid = -1;
+ int64_t mClientId = 0;
uint32_t mCallingClientImportance = 0;
const std::vector<::aidl::android::media::MediaResourceParcel>& mResources;
};
@@ -178,11 +180,14 @@
/*
* Resource request info that encapsulates
* - the calling/requesting process pid.
+ * - the calling/requesting client's id.
* - the resource requesting (to be reclaimed from others)
*/
struct ResourceRequestInfo {
// pid of the calling/requesting process.
int mCallingPid = -1;
+ // id of the calling/requesting client.
+ int64_t mClientId = 0;
// resources requested.
const ::aidl::android::media::MediaResourceParcel* mResource;
};
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
index 22381c3..3ee20cd 100644
--- a/services/mediaresourcemanager/ResourceTracker.cpp
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -715,6 +715,11 @@
MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
for (const auto& [id, /* ResourceInfo */ info] : infos) {
+ if (pid == resourceRequestInfo.mCallingPid && id == resourceRequestInfo.mClientId) {
+ ALOGI("%s: Skip the client[%jd] for which the resource request is made",
+ __func__, id);
+ continue;
+ }
if (hasResourceType(type, subType, info.resources)) {
if (!isCallingPriorityHigher(resourceRequestInfo.mCallingPid, pid)) {
// some higher/equal priority process owns the resource,
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 7e8a4a0..2c8659d 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -165,6 +165,7 @@
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
};
+// [pid, uid] used by the test.
static const int kTestPid1 = 30;
static const int kTestUid1 = 1010;
@@ -175,6 +176,12 @@
static const int kMidPriorityPid = 25;
static const int kHighPriorityPid = 10;
+// Client Ids used by the test.
+static const int kLowPriorityClientId = 1111;
+static const int kMidPriorityClientId = 2222;
+static const int kHighPriorityClientId = 3333;
+
+// Client importance used by the test.
static const int32_t kHighestCodecImportance = 0;
static const int32_t kLowestCodecImportance = 100;
static const int32_t kMidCodecImportance = 50;
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index b3a0932..027987e 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -337,7 +337,7 @@
// priority too low to reclaim resource
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(kLowPriorityPid),
.uid = static_cast<int32_t>(kTestUid1),
- .id = 0,
+ .id = kLowPriorityClientId,
.name = "none"};
CHECK_STATUS_FALSE(mService->reclaimResource(clientInfo, resources, &result));
@@ -475,9 +475,9 @@
MediaResource resource(MediaResource::Type::kSecureCodec,
MediaResource::SubType::kUnspecifiedSubType,
1);
- ResourceRequestInfo requestInfoHigh { kHighPriorityPid, &resource};
- ResourceRequestInfo requestInfoMid { kMidPriorityPid, &resource};
- ResourceRequestInfo requestInfoLow { kLowPriorityPid, &resource};
+ ResourceRequestInfo requestInfoHigh { kHighPriorityPid, kHighPriorityClientId, &resource};
+ ResourceRequestInfo requestInfoMid { kMidPriorityPid, kMidPriorityClientId, &resource};
+ ResourceRequestInfo requestInfoLow { kLowPriorityPid, kLowPriorityClientId, &resource};
EXPECT_FALSE(mService->getAllClients_l(requestInfoLow, targetClients));
// some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
@@ -491,6 +491,81 @@
EXPECT_EQ(getId(mTestClient1), targetClients[1].mClientId);
}
+ // test set up
+ // ---------------------------------------------------------------------------
+ // pid/priority client/clientId type number
+ // ---------------------------------------------------------------------------
+ // kTestPid1(30) mTestClient1 secure codec 1
+ // graphic memory 200
+ // graphic memory 200
+ // ---------------------------------------------------------------------------
+ // kTestPid2(20) mTestClient2 non-secure codec 1
+ // graphic memory 300
+ // ---------------------------------------------------
+ // mTestClient3 secure codec 1
+ // graphic memory 100
+ // ---------------------------------------------------------------------------
+ // kHighPriorityPid(10) kHighPriorityClient secure codec 1
+ // ---------------------------------------------------------------------------
+ // The kHighPriorityClient tries to reclaim request (after adding self)
+ // This should pass (and shouldn't be considered as a new client trying to
+ // reclaim from an existing client from same/higher priority process).
+ void testSelfReclaimResourceSecure() {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
+
+ ClientInfoParcel lowPriorityClient{.pid = static_cast<int32_t>(kLowPriorityPid),
+ .uid = static_cast<int32_t>(kTestUid2),
+ .id = kLowPriorityClientId,
+ .name = "none"};
+ ClientInfoParcel midPriorityClient{.pid = static_cast<int32_t>(kMidPriorityPid),
+ .uid = static_cast<int32_t>(kTestUid2),
+ .id = kMidPriorityClientId,
+ .name = "none"};
+ // HighPriority process with client id kHighPriorityClientId.
+ ClientInfoParcel highPriorityClient1{.pid = static_cast<int32_t>(kHighPriorityPid),
+ .uid = static_cast<int32_t>(kTestUid2),
+ .id = kHighPriorityClientId,
+ .name = "none"};
+ // HighPriority process with client id 0xABCD.
+ ClientInfoParcel highPriorityClient2{.pid = static_cast<int32_t>(kHighPriorityPid),
+ .uid = static_cast<int32_t>(kTestUid2),
+ .id = 0xABCD,
+ .name = "none"};
+
+ addResource();
+
+ // Add a secure codec resource for the highPriorityClient1.
+ std::shared_ptr<IResourceManagerClient> testClient4 =
+ createTestClient(kHighPriorityPid, kTestUid2);
+ std::vector<MediaResourceParcel> resources1;
+ resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+ mService->addResource(highPriorityClient1, testClient4, resources1);
+
+ // secure codecs can't coexist and secure codec can't coexist with non-secure codec.
+ updateConfig(false, false);
+
+ // priority too low
+ CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
+ CHECK_STATUS_FALSE(mService->reclaimResource(midPriorityClient, resources, &result));
+
+ // highPriorityClient2 tries to reclaim SecureCodec with Graphic memory.
+ // This should fail as this process already has an instance of secure
+ // codec through testClient4.
+ CHECK_STATUS_FALSE(mService->reclaimResource(highPriorityClient2, resources, &result));
+
+ // highPriorityClient1 tries to reclaim SecureCodec with Graphic memory.
+ // This should reclaim all secure and non-secure codecs.
+ CHECK_STATUS_TRUE(mService->reclaimResource(highPriorityClient1, resources, &result));
+ EXPECT_TRUE(toTestClient(mTestClient1)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient2)->checkIfReclaimedAndReset());
+ EXPECT_TRUE(toTestClient(mTestClient3)->checkIfReclaimedAndReset());
+
+ // Make sure there is nothing left.
+ CHECK_STATUS_FALSE(mService->reclaimResource(highPriorityClient1, resources, &result));
+ }
+
void testReclaimResourceSecure() {
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
@@ -498,15 +573,15 @@
ClientInfoParcel lowPriorityClient{.pid = static_cast<int32_t>(kLowPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kLowPriorityClientId,
.name = "none"};
ClientInfoParcel midPriorityClient{.pid = static_cast<int32_t>(kMidPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kMidPriorityClientId,
.name = "none"};
ClientInfoParcel highPriorityClient{.pid = static_cast<int32_t>(kHighPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kHighPriorityClientId,
.name = "none"};
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
@@ -553,7 +628,6 @@
CHECK_STATUS_FALSE(mService->reclaimResource(highPriorityClient, resources, &result));
}
-
// ### secure codecs can coexist but secure codec can't coexist with non-secure codec ###
{
addResource();
@@ -650,15 +724,15 @@
ClientInfoParcel lowPriorityClient{.pid = static_cast<int32_t>(kLowPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kLowPriorityClientId,
.name = "none"};
ClientInfoParcel midPriorityClient{.pid = static_cast<int32_t>(kMidPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kMidPriorityClientId,
.name = "none"};
ClientInfoParcel highPriorityClient{.pid = static_cast<int32_t>(kHighPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kHighPriorityClientId,
.name = "none"};
// ### secure codec can't coexist with non-secure codec ###
@@ -751,8 +825,8 @@
MediaResource resource(MediaResource::Type::kGraphicMemory,
MediaResource::SubType::kUnspecifiedSubType,
1);
- ResourceRequestInfo requestInfoHigh { kHighPriorityPid, &resource};
- ResourceRequestInfo requestInfoLow { kLowPriorityPid, &resource};
+ ResourceRequestInfo requestInfoHigh { kHighPriorityPid, kHighPriorityClientId, &resource};
+ ResourceRequestInfo requestInfoLow { kLowPriorityPid, kLowPriorityClientId, &resource};
EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(requestInfoHigh, clientInfo));
addResource();
@@ -910,7 +984,7 @@
reclaimResources.push_back(createNonSecureVideoCodecResource());
ClientInfoParcel highPriorityClient{.pid = static_cast<int32_t>(kHighPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kHighPriorityClientId,
.name = "none"};
CHECK_STATUS_FALSE(mService->reclaimResource(highPriorityClient, reclaimResources, &result));
@@ -951,7 +1025,7 @@
reclaimResources.push_back(createNonSecureAudioCodecResource());
ClientInfoParcel highPriorityClient{.pid = static_cast<int32_t>(kHighPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kHighPriorityClientId,
.name = "none"};
CHECK_STATUS_FALSE(mService->reclaimResource(highPriorityClient, reclaimResources, &result));
@@ -992,7 +1066,7 @@
reclaimResources.push_back(createNonSecureImageCodecResource());
ClientInfoParcel highPriorityClient{.pid = static_cast<int32_t>(kHighPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kHighPriorityClientId,
.name = "none"};
CHECK_STATUS_FALSE(mService->reclaimResource(highPriorityClient, reclaimResources, &result));
@@ -1034,7 +1108,7 @@
reclaimResources.push_back(createGraphicMemoryResource(100));
ClientInfoParcel highPriorityClient{.pid = static_cast<int32_t>(kHighPriorityPid),
.uid = static_cast<int32_t>(kTestUid2),
- .id = 0,
+ .id = kHighPriorityClientId,
.name = "none"};
CHECK_STATUS_TRUE(mService->reclaimResource(highPriorityClient, reclaimResources, &result));
@@ -1786,6 +1860,10 @@
testRemoveClient();
}
+TEST_F(ResourceManagerServiceTest, selfReclaimResource) {
+ testSelfReclaimResourceSecure();
+}
+
TEST_F(ResourceManagerServiceTest, reclaimResource) {
testReclaimResourceSecure();
testReclaimResourceNonSecure();
@@ -1873,6 +1951,10 @@
testRemoveClient();
}
+TEST_F(ResourceManagerServiceNewTest, selfReclaimResource) {
+ testSelfReclaimResourceSecure();
+}
+
TEST_F(ResourceManagerServiceNewTest, reclaimResource) {
testReclaimResourceSecure();
testReclaimResourceNonSecure();
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 65854c8..63cf432 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -643,7 +643,7 @@
int32_t count = mUpMessageQueue->getFifoBuffer()->write(command, 1);
if (count != 1) {
ALOGW("%s(): Queue full. Did client stop? Suspending stream. what = %u, %s",
- __func__, command->what, getTypeText());
+ __func__, static_cast<unsigned>(command->what), getTypeText());
setSuspended(true);
return AAUDIO_ERROR_WOULD_BLOCK;
} else {